--- /dev/null
+From b35108a51cf7bab58d7eace1267d7965978bcdb8 Mon Sep 17 00:00:00 2001
+Date: Wed, 30 Oct 2024 17:47:35 +0000
+Subject: [PATCH] jiffies: Define secs_to_jiffies()
+
+secs_to_jiffies() is defined in hci_event.c and cannot be reused by
+other call sites. Hoist it into the core code to allow conversion of the
+~1150 usages of msecs_to_jiffies() that either:
+
+ - use a multiplier value of 1000 or equivalently MSEC_PER_SEC, or
+ - have timeouts that are denominated in seconds (i.e. end in 000)
+
+It's implemented as a macro to allow usage in static initializers.
+
+This will also allow conversion of yet more sites that use (sec * HZ)
+directly, and improve their readability.
+
+Link: https://lore.kernel.org/all/20241030-open-coded-timeouts-v3-1-9ba123facf88@linux.microsoft.com
+---
+ include/linux/jiffies.h | 13 +++++++++++++
+ net/bluetooth/hci_event.c | 2 --
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/include/linux/jiffies.h
++++ b/include/linux/jiffies.h
+@@ -526,6 +526,19 @@ static __always_inline unsigned long mse
+ }
+ }
+
++/**
++ * secs_to_jiffies: - convert seconds to jiffies
++ * @_secs: time in seconds
++ *
++ * Conversion is done by simple multiplication with HZ
++ *
++ * secs_to_jiffies() is defined as a macro rather than a static inline
++ * function so it can be used in static initializers.
++ *
++ * Return: jiffies value
++ */
++#define secs_to_jiffies(_secs) ((_secs) * HZ)
++
+ extern unsigned long __usecs_to_jiffies(const unsigned int u);
+ #if !(USEC_PER_SEC % HZ)
+ static inline unsigned long _usecs_to_jiffies(const unsigned int u)
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -42,8 +42,6 @@
+ #define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+
+-#define secs_to_jiffies(_secs) msecs_to_jiffies((_secs) * 1000)
+-
+ /* Handle HCI Event packets */
+
+ static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
--- /dev/null
+From bb2784d9ab49587ba4fbff37a319fff2924db289 Mon Sep 17 00:00:00 2001
+Date: Thu, 30 Jan 2025 19:26:58 +0000
+Subject: [PATCH] jiffies: Cast to unsigned long in secs_to_jiffies()
+ conversion
+
+While converting users of msecs_to_jiffies(), lkp reported that some range
+checks would always be true because of the mismatch between the implied int
+value of secs_to_jiffies() vs the unsigned long return value of the
+msecs_to_jiffies() calls it was replacing.
+
+Fix this by casting the secs_to_jiffies() input value to unsigned long.
+
+Fixes: b35108a51cf7ba ("jiffies: Define secs_to_jiffies()")
+---
+ include/linux/jiffies.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/linux/jiffies.h
++++ b/include/linux/jiffies.h
+@@ -537,7 +537,7 @@ static __always_inline unsigned long mse
+ *
+ * Return: jiffies value
+ */
+-#define secs_to_jiffies(_secs) ((_secs) * HZ)
++#define secs_to_jiffies(_secs) (unsigned long)((_secs) * HZ)
+
+ extern unsigned long __usecs_to_jiffies(const unsigned int u);
+ #if !(USEC_PER_SEC % HZ)
+++ /dev/null
-From 0f4ae7c6ecb89bfda026d210dcf8216fb67d2333 Mon Sep 17 00:00:00 2001
-Date: Sat, 29 Mar 2025 08:39:03 -0700
-Subject: mips: Add -std= flag specified in KBUILD_CFLAGS to vdso CFLAGS
-
-GCC 15 changed the default C standard dialect from gnu17 to gnu23,
-which should not have impacted the kernel because it explicitly requests
-the gnu11 standard in the main Makefile. However, mips/vdso code uses
-its own CFLAGS without a '-std=' value, which break with this dialect
-change because of the kernel's own definitions of bool, false, and true
-conflicting with the C23 reserved keywords.
-
- include/linux/stddef.h:11:9: error: cannot use keyword 'false' as enumeration constant
- 11 | false = 0,
- | ^~~~~
- include/linux/stddef.h:11:9: note: 'false' is a keyword with '-std=c23' onwards
- include/linux/types.h:35:33: error: 'bool' cannot be defined via 'typedef'
- 35 | typedef _Bool bool;
- | ^~~~
- include/linux/types.h:35:33: note: 'bool' is a keyword with '-std=c23' onwards
-
-Add -std as specified in KBUILD_CFLAGS to the decompressor and purgatory
-CFLAGS to eliminate these errors and make the C standard version of these
-areas match the rest of the kernel.
-
----
- arch/mips/vdso/Makefile | 1 +
- 1 file changed, 1 insertion(+)
-
-(limited to 'arch/mips/vdso')
-
---- a/arch/mips/vdso/Makefile
-+++ b/arch/mips/vdso/Makefile
-@@ -27,6 +27,7 @@ endif
- # offsets.
- cflags-vdso := $(ccflags-vdso) \
- $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
-+ $(filter -std=%,$(KBUILD_CFLAGS)) \
- -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \
- -mrelax-pic-calls $(call cc-option, -mexplicit-relocs) \
- -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
--- /dev/null
+From 239d87327dcd361b0098038995f8908f3296864f Mon Sep 17 00:00:00 2001
+Date: Thu, 12 Dec 2024 17:28:06 -0800
+Subject: fortify: Hide run-time copy size from value range tracking
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+GCC performs value range tracking for variables as a way to provide better
+diagnostics. One place this is regularly seen is with warnings associated
+with bounds-checking, e.g. -Wstringop-overflow, -Wstringop-overread,
+-Warray-bounds, etc. In order to keep the signal-to-noise ratio high,
+warnings aren't emitted when a value range spans the entire value range
+representable by a given variable. For example:
+
+ unsigned int len;
+ char dst[8];
+ ...
+ memcpy(dst, src, len);
+
+If len's value is unknown, it has the full "unsigned int" range of [0,
+UINT_MAX], and GCC's compile-time bounds checks against memcpy() will
+be ignored. However, when a code path has been able to narrow the range:
+
+ if (len > 16)
+ return;
+ memcpy(dst, src, len);
+
+Then the range will be updated for the execution path. Above, len is
+now [0, 16] when reading memcpy(), so depending on other optimizations,
+we might see a -Wstringop-overflow warning like:
+
+ error: '__builtin_memcpy' writing between 9 and 16 bytes into region of size 8 [-Werror=stringop-overflow]
+
+When building with CONFIG_FORTIFY_SOURCE, the fortified run-time bounds
+checking can appear to narrow value ranges of lengths for memcpy(),
+depending on how the compiler constructs the execution paths during
+optimization passes, due to the checks against the field sizes. For
+example:
+
+ if (p_size_field != SIZE_MAX &&
+ p_size != p_size_field && p_size_field < size)
+
+As intentionally designed, these checks only affect the kernel warnings
+emitted at run-time and do not block the potentially overflowing memcpy(),
+so GCC thinks it needs to produce a warning about the resulting value
+range that might be reaching the memcpy().
+
+We have seen this manifest a few times now, with the most recent being
+with cpumasks:
+
+In function ‘bitmap_copy’,
+ inlined from ‘cpumask_copy’ at ./include/linux/cpumask.h:839:2,
+ inlined from ‘__padata_set_cpumasks’ at kernel/padata.c:730:2:
+./include/linux/fortify-string.h:114:33: error: ‘__builtin_memcpy’ reading between 257 and 536870904 bytes from a region of size 256 [-Werror=stringop-overread]
+ 114 | #define __underlying_memcpy __builtin_memcpy
+ | ^
+./include/linux/fortify-string.h:633:9: note: in expansion of macro ‘__underlying_memcpy’
+ 633 | __underlying_##op(p, q, __fortify_size); \
+ | ^~~~~~~~~~~~~
+./include/linux/fortify-string.h:678:26: note: in expansion of macro ‘__fortify_memcpy_chk’
+ 678 | #define memcpy(p, q, s) __fortify_memcpy_chk(p, q, s, \
+ | ^~~~~~~~~~~~~~~~~~~~
+./include/linux/bitmap.h:259:17: note: in expansion of macro ‘memcpy’
+ 259 | memcpy(dst, src, len);
+ | ^~~~~~
+kernel/padata.c: In function ‘__padata_set_cpumasks’:
+kernel/padata.c:713:48: note: source object ‘pcpumask’ of size [0, 256]
+ 713 | cpumask_var_t pcpumask,
+ | ~~~~~~~~~~~~~~^~~~~~~~
+
+This warning is _not_ emitted when CONFIG_FORTIFY_SOURCE is disabled,
+and with the recent -fdiagnostics-details we can confirm the origin of
+the warning is due to FORTIFY's bounds checking:
+
+../include/linux/bitmap.h:259:17: note: in expansion of macro 'memcpy'
+ 259 | memcpy(dst, src, len);
+ | ^~~~~~
+ '__padata_set_cpumasks': events 1-2
+../include/linux/fortify-string.h:613:36:
+ 612 | if (p_size_field != SIZE_MAX &&
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 613 | p_size != p_size_field && p_size_field < size)
+ | ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) when the condition is evaluated to false
+ | (2) when the condition is evaluated to true
+ '__padata_set_cpumasks': event 3
+ 114 | #define __underlying_memcpy __builtin_memcpy
+ | ^
+ | |
+ | (3) out of array bounds here
+
+Note that the cpumask warning started appearing since bitmap functions
+were recently marked __always_inline in commit ed8cd2b3bd9f ("bitmap:
+Switch from inline to __always_inline"), which allowed GCC to gain
+visibility into the variables as they passed through the FORTIFY
+implementation.
+
+In order to silence these false positives but keep otherwise deterministic
+compile-time warnings intact, hide the length variable from GCC with
+OPTIMIZE_HIDE_VAR() before calling the builtin memcpy.
+
+Additionally add a comment about why all the macro args have copies with
+const storage.
+
+---
+ include/linux/fortify-string.h | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+--- a/include/linux/fortify-string.h
++++ b/include/linux/fortify-string.h
+@@ -616,6 +616,12 @@ __FORTIFY_INLINE bool fortify_memcpy_chk
+ return false;
+ }
+
++/*
++ * To work around what seems to be an optimizer bug, the macro arguments
++ * need to have const copies or the values end up changed by the time they
++ * reach fortify_warn_once(). See commit 6f7630b1b5bc ("fortify: Capture
++ * __bos() results in const temp vars") for more details.
++ */
+ #define __fortify_memcpy_chk(p, q, size, p_size, q_size, \
+ p_size_field, q_size_field, op) ({ \
+ const size_t __fortify_size = (size_t)(size); \
+@@ -623,6 +629,8 @@ __FORTIFY_INLINE bool fortify_memcpy_chk
+ const size_t __q_size = (q_size); \
+ const size_t __p_size_field = (p_size_field); \
+ const size_t __q_size_field = (q_size_field); \
++ /* Keep a mutable version of the size for the final copy. */ \
++ size_t __copy_size = __fortify_size; \
+ fortify_warn_once(fortify_memcpy_chk(__fortify_size, __p_size, \
+ __q_size, __p_size_field, \
+ __q_size_field, FORTIFY_FUNC_ ##op), \
+@@ -630,7 +638,11 @@ __FORTIFY_INLINE bool fortify_memcpy_chk
+ __fortify_size, \
+ "field \"" #p "\" at " FILE_LINE, \
+ __p_size_field); \
+- __underlying_##op(p, q, __fortify_size); \
++ /* Hide only the run-time size from value range tracking to */ \
++ /* silence compile-time false positive bounds warnings. */ \
++ if (!__builtin_constant_p(__copy_size)) \
++ OPTIMIZER_HIDE_VAR(__copy_size); \
++ __underlying_##op(p, q, __copy_size); \
+ })
+
+ /*
--- /dev/null
+From 0f4ae7c6ecb89bfda026d210dcf8216fb67d2333 Mon Sep 17 00:00:00 2001
+Date: Sat, 29 Mar 2025 08:39:03 -0700
+Subject: mips: Add -std= flag specified in KBUILD_CFLAGS to vdso CFLAGS
+
+GCC 15 changed the default C standard dialect from gnu17 to gnu23,
+which should not have impacted the kernel because it explicitly requests
+the gnu11 standard in the main Makefile. However, mips/vdso code uses
+its own CFLAGS without a '-std=' value, which break with this dialect
+change because of the kernel's own definitions of bool, false, and true
+conflicting with the C23 reserved keywords.
+
+ include/linux/stddef.h:11:9: error: cannot use keyword 'false' as enumeration constant
+ 11 | false = 0,
+ | ^~~~~
+ include/linux/stddef.h:11:9: note: 'false' is a keyword with '-std=c23' onwards
+ include/linux/types.h:35:33: error: 'bool' cannot be defined via 'typedef'
+ 35 | typedef _Bool bool;
+ | ^~~~
+ include/linux/types.h:35:33: note: 'bool' is a keyword with '-std=c23' onwards
+
+Add -std as specified in KBUILD_CFLAGS to the decompressor and purgatory
+CFLAGS to eliminate these errors and make the C standard version of these
+areas match the rest of the kernel.
+
+---
+ arch/mips/vdso/Makefile | 1 +
+ 1 file changed, 1 insertion(+)
+
+(limited to 'arch/mips/vdso')
+
+--- a/arch/mips/vdso/Makefile
++++ b/arch/mips/vdso/Makefile
+@@ -27,6 +27,7 @@ endif
+ # offsets.
+ cflags-vdso := $(ccflags-vdso) \
+ $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
++ $(filter -std=%,$(KBUILD_CFLAGS)) \
+ -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \
+ -mrelax-pic-calls $(call cc-option, -mexplicit-relocs) \
+ -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
+++ /dev/null
-From b35108a51cf7bab58d7eace1267d7965978bcdb8 Mon Sep 17 00:00:00 2001
-Date: Wed, 30 Oct 2024 17:47:35 +0000
-Subject: [PATCH] jiffies: Define secs_to_jiffies()
-
-secs_to_jiffies() is defined in hci_event.c and cannot be reused by
-other call sites. Hoist it into the core code to allow conversion of the
-~1150 usages of msecs_to_jiffies() that either:
-
- - use a multiplier value of 1000 or equivalently MSEC_PER_SEC, or
- - have timeouts that are denominated in seconds (i.e. end in 000)
-
-It's implemented as a macro to allow usage in static initializers.
-
-This will also allow conversion of yet more sites that use (sec * HZ)
-directly, and improve their readability.
-
-Link: https://lore.kernel.org/all/20241030-open-coded-timeouts-v3-1-9ba123facf88@linux.microsoft.com
----
- include/linux/jiffies.h | 13 +++++++++++++
- net/bluetooth/hci_event.c | 2 --
- 2 files changed, 13 insertions(+), 2 deletions(-)
-
---- a/include/linux/jiffies.h
-+++ b/include/linux/jiffies.h
-@@ -526,6 +526,19 @@ static __always_inline unsigned long mse
- }
- }
-
-+/**
-+ * secs_to_jiffies: - convert seconds to jiffies
-+ * @_secs: time in seconds
-+ *
-+ * Conversion is done by simple multiplication with HZ
-+ *
-+ * secs_to_jiffies() is defined as a macro rather than a static inline
-+ * function so it can be used in static initializers.
-+ *
-+ * Return: jiffies value
-+ */
-+#define secs_to_jiffies(_secs) ((_secs) * HZ)
-+
- extern unsigned long __usecs_to_jiffies(const unsigned int u);
- #if !(USEC_PER_SEC % HZ)
- static inline unsigned long _usecs_to_jiffies(const unsigned int u)
---- a/net/bluetooth/hci_event.c
-+++ b/net/bluetooth/hci_event.c
-@@ -42,8 +42,6 @@
- #define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
- "\x00\x00\x00\x00\x00\x00\x00\x00"
-
--#define secs_to_jiffies(_secs) msecs_to_jiffies((_secs) * 1000)
--
- /* Handle HCI Event packets */
-
- static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
+++ /dev/null
-From bb2784d9ab49587ba4fbff37a319fff2924db289 Mon Sep 17 00:00:00 2001
-Date: Thu, 30 Jan 2025 19:26:58 +0000
-Subject: [PATCH] jiffies: Cast to unsigned long in secs_to_jiffies()
- conversion
-
-While converting users of msecs_to_jiffies(), lkp reported that some range
-checks would always be true because of the mismatch between the implied int
-value of secs_to_jiffies() vs the unsigned long return value of the
-msecs_to_jiffies() calls it was replacing.
-
-Fix this by casting the secs_to_jiffies() input value to unsigned long.
-
-Fixes: b35108a51cf7ba ("jiffies: Define secs_to_jiffies()")
----
- include/linux/jiffies.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/include/linux/jiffies.h
-+++ b/include/linux/jiffies.h
-@@ -537,7 +537,7 @@ static __always_inline unsigned long mse
- *
- * Return: jiffies value
- */
--#define secs_to_jiffies(_secs) ((_secs) * HZ)
-+#define secs_to_jiffies(_secs) (unsigned long)((_secs) * HZ)
-
- extern unsigned long __usecs_to_jiffies(const unsigned int u);
- #if !(USEC_PER_SEC % HZ)
--- /dev/null
+From ae461cde5c559675fc4c0ba351c7c31ace705f56 Mon Sep 17 00:00:00 2001
+Date: Sun, 10 Nov 2024 22:50:47 +0200
+Subject: [PATCH] mtd: spinand: add support for FORESEE F35SQA001G
+
+Add support for FORESEE F35SQA001G SPI NAND.
+
+Similar to F35SQA002G, but differs in capacity.
+Datasheet:
+ - https://cdn.ozdisan.com/ETicaret_Dosya/704795_871495.pdf
+
+Tested on Xiaomi AX3000T flashed with OpenWRT.
+
+---
+ drivers/mtd/nand/spi/foresee.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/nand/spi/foresee.c
++++ b/drivers/mtd/nand/spi/foresee.c
+@@ -81,6 +81,16 @@ static const struct spinand_info foresee
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&f35sqa002g_ooblayout,
+ f35sqa002g_ecc_get_status)),
++ SPINAND_INFO("F35SQA001G",
++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71, 0x71),
++ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
++ NAND_ECCREQ(1, 512),
++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++ &write_cache_variants,
++ &update_cache_variants),
++ SPINAND_HAS_QE_BIT,
++ SPINAND_ECCINFO(&f35sqa002g_ooblayout,
++ f35sqa002g_ecc_get_status)),
+ };
+
+ static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = {
--- /dev/null
+From 8c52932da5e6756fa66f52f0720da283fba13aa6 Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Nov 2024 14:45:00 +0530
+Subject: [PATCH 1/4] mtd: rawnand: qcom: cleanup qcom_nandc driver
+
+Perform a global cleanup of the Qualcomm NAND
+controller driver with the following improvements:
+
+- Remove register value indirection API
+
+- Remove set_reg() API
+
+- Convert read_loc_first & read_loc_last macro to functions
+
+- Rename multiple variables
+
+---
+ drivers/mtd/nand/raw/qcom_nandc.c | 516 ++++++++++++++----------------
+ 1 file changed, 234 insertions(+), 282 deletions(-)
+
+--- a/drivers/mtd/nand/raw/qcom_nandc.c
++++ b/drivers/mtd/nand/raw/qcom_nandc.c
+@@ -189,17 +189,6 @@
+ #define ECC_BCH_4BIT BIT(2)
+ #define ECC_BCH_8BIT BIT(3)
+
+-#define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc) \
+-nandc_set_reg(chip, reg, \
+- ((cw_offset) << READ_LOCATION_OFFSET) | \
+- ((read_size) << READ_LOCATION_SIZE) | \
+- ((is_last_read_loc) << READ_LOCATION_LAST))
+-
+-#define nandc_set_read_loc_last(chip, reg, cw_offset, read_size, is_last_read_loc) \
+-nandc_set_reg(chip, reg, \
+- ((cw_offset) << READ_LOCATION_OFFSET) | \
+- ((read_size) << READ_LOCATION_SIZE) | \
+- ((is_last_read_loc) << READ_LOCATION_LAST))
+ /*
+ * Returns the actual register address for all NAND_DEV_ registers
+ * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
+@@ -257,8 +246,6 @@ nandc_set_reg(chip, reg, \
+ * @tx_sgl_start - start index in data sgl for tx.
+ * @rx_sgl_pos - current index in data sgl for rx.
+ * @rx_sgl_start - start index in data sgl for rx.
+- * @wait_second_completion - wait for second DMA desc completion before making
+- * the NAND transfer completion.
+ */
+ struct bam_transaction {
+ struct bam_cmd_element *bam_ce;
+@@ -275,7 +262,6 @@ struct bam_transaction {
+ u32 tx_sgl_start;
+ u32 rx_sgl_pos;
+ u32 rx_sgl_start;
+- bool wait_second_completion;
+ };
+
+ /*
+@@ -471,9 +457,9 @@ struct qcom_op {
+ unsigned int data_instr_idx;
+ unsigned int rdy_timeout_ms;
+ unsigned int rdy_delay_ns;
+- u32 addr1_reg;
+- u32 addr2_reg;
+- u32 cmd_reg;
++ __le32 addr1_reg;
++ __le32 addr2_reg;
++ __le32 cmd_reg;
+ u8 flag;
+ };
+
+@@ -549,17 +535,17 @@ struct qcom_nand_host {
+ * among different NAND controllers.
+ * @ecc_modes - ecc mode for NAND
+ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
+- * @is_bam - whether NAND controller is using BAM
+- * @is_qpic - whether NAND CTRL is part of qpic IP
+- * @qpic_v2 - flag to indicate QPIC IP version 2
++ * @supports_bam - whether NAND controller is using Bus Access Manager (BAM)
++ * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
++ * @qpic_version2 - flag to indicate QPIC IP version 2
+ * @use_codeword_fixup - whether NAND has different layout for boot partitions
+ */
+ struct qcom_nandc_props {
+ u32 ecc_modes;
+ u32 dev_cmd_reg_start;
+- bool is_bam;
+- bool is_qpic;
+- bool qpic_v2;
++ bool supports_bam;
++ bool nandc_part_of_qpic;
++ bool qpic_version2;
+ bool use_codeword_fixup;
+ };
+
+@@ -613,19 +599,11 @@ static void clear_bam_transaction(struct
+ {
+ struct bam_transaction *bam_txn = nandc->bam_txn;
+
+- if (!nandc->props->is_bam)
++ if (!nandc->props->supports_bam)
+ return;
+
+- bam_txn->bam_ce_pos = 0;
+- bam_txn->bam_ce_start = 0;
+- bam_txn->cmd_sgl_pos = 0;
+- bam_txn->cmd_sgl_start = 0;
+- bam_txn->tx_sgl_pos = 0;
+- bam_txn->tx_sgl_start = 0;
+- bam_txn->rx_sgl_pos = 0;
+- bam_txn->rx_sgl_start = 0;
++ memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
+ bam_txn->last_data_desc = NULL;
+- bam_txn->wait_second_completion = false;
+
+ sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
+ QPIC_PER_CW_CMD_SGL);
+@@ -640,46 +618,35 @@ static void qpic_bam_dma_done(void *data
+ {
+ struct bam_transaction *bam_txn = data;
+
+- /*
+- * In case of data transfer with NAND, 2 callbacks will be generated.
+- * One for command channel and another one for data channel.
+- * If current transaction has data descriptors
+- * (i.e. wait_second_completion is true), then set this to false
+- * and wait for second DMA descriptor completion.
+- */
+- if (bam_txn->wait_second_completion)
+- bam_txn->wait_second_completion = false;
+- else
+- complete(&bam_txn->txn_done);
++ complete(&bam_txn->txn_done);
+ }
+
+-static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
++static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
+ {
+ return container_of(chip, struct qcom_nand_host, chip);
+ }
+
+-static inline struct qcom_nand_controller *
++static struct qcom_nand_controller *
+ get_qcom_nand_controller(struct nand_chip *chip)
+ {
+ return container_of(chip->controller, struct qcom_nand_controller,
+ controller);
+ }
+
+-static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
++static u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
+ {
+ return ioread32(nandc->base + offset);
+ }
+
+-static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
+- u32 val)
++static void nandc_write(struct qcom_nand_controller *nandc, int offset,
++ u32 val)
+ {
+ iowrite32(val, nandc->base + offset);
+ }
+
+-static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
+- bool is_cpu)
++static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
+ {
+- if (!nandc->props->is_bam)
++ if (!nandc->props->supports_bam)
+ return;
+
+ if (is_cpu)
+@@ -694,93 +661,90 @@ static inline void nandc_read_buffer_syn
+ DMA_FROM_DEVICE);
+ }
+
+-static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
+-{
+- switch (offset) {
+- case NAND_FLASH_CMD:
+- return ®s->cmd;
+- case NAND_ADDR0:
+- return ®s->addr0;
+- case NAND_ADDR1:
+- return ®s->addr1;
+- case NAND_FLASH_CHIP_SELECT:
+- return ®s->chip_sel;
+- case NAND_EXEC_CMD:
+- return ®s->exec;
+- case NAND_FLASH_STATUS:
+- return ®s->clrflashstatus;
+- case NAND_DEV0_CFG0:
+- return ®s->cfg0;
+- case NAND_DEV0_CFG1:
+- return ®s->cfg1;
+- case NAND_DEV0_ECC_CFG:
+- return ®s->ecc_bch_cfg;
+- case NAND_READ_STATUS:
+- return ®s->clrreadstatus;
+- case NAND_DEV_CMD1:
+- return ®s->cmd1;
+- case NAND_DEV_CMD1_RESTORE:
+- return ®s->orig_cmd1;
+- case NAND_DEV_CMD_VLD:
+- return ®s->vld;
+- case NAND_DEV_CMD_VLD_RESTORE:
+- return ®s->orig_vld;
+- case NAND_EBI2_ECC_BUF_CFG:
+- return ®s->ecc_buf_cfg;
+- case NAND_READ_LOCATION_0:
+- return ®s->read_location0;
+- case NAND_READ_LOCATION_1:
+- return ®s->read_location1;
+- case NAND_READ_LOCATION_2:
+- return ®s->read_location2;
+- case NAND_READ_LOCATION_3:
+- return ®s->read_location3;
+- case NAND_READ_LOCATION_LAST_CW_0:
+- return ®s->read_location_last0;
+- case NAND_READ_LOCATION_LAST_CW_1:
+- return ®s->read_location_last1;
+- case NAND_READ_LOCATION_LAST_CW_2:
+- return ®s->read_location_last2;
+- case NAND_READ_LOCATION_LAST_CW_3:
+- return ®s->read_location_last3;
+- default:
+- return NULL;
+- }
+-}
+-
+-static void nandc_set_reg(struct nand_chip *chip, int offset,
+- u32 val)
+-{
+- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+- struct nandc_regs *regs = nandc->regs;
+- __le32 *reg;
+-
+- reg = offset_to_nandc_reg(regs, offset);
+-
+- if (reg)
+- *reg = cpu_to_le32(val);
+-}
+-
+-/* Helper to check the code word, whether it is last cw or not */
++/* Helper to check whether this is the last CW or not */
+ static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
+ {
+ return cw == (ecc->steps - 1);
+ }
+
++/**
++ * nandc_set_read_loc_first() - to set read location first register
++ * @chip: NAND Private Flash Chip Data
++ * @reg_base: location register base
++ * @cw_offset: code word offset
++ * @read_size: code word read length
++ * @is_last_read_loc: is this the last read location
++ *
++ * This function will set location register value
++ */
++static void nandc_set_read_loc_first(struct nand_chip *chip,
++ int reg_base, u32 cw_offset,
++ u32 read_size, u32 is_last_read_loc)
++{
++ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++ __le32 locreg_val;
++ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
++ ((read_size) << READ_LOCATION_SIZE) |
++ ((is_last_read_loc) << READ_LOCATION_LAST));
++
++ locreg_val = cpu_to_le32(val);
++
++ if (reg_base == NAND_READ_LOCATION_0)
++ nandc->regs->read_location0 = locreg_val;
++ else if (reg_base == NAND_READ_LOCATION_1)
++ nandc->regs->read_location1 = locreg_val;
++ else if (reg_base == NAND_READ_LOCATION_2)
++ nandc->regs->read_location2 = locreg_val;
++ else if (reg_base == NAND_READ_LOCATION_3)
++ nandc->regs->read_location3 = locreg_val;
++}
++
++/**
++ * nandc_set_read_loc_last - to set read location last register
++ * @chip: NAND Private Flash Chip Data
++ * @reg_base: location register base
++ * @cw_offset: code word offset
++ * @read_size: code word read length
++ * @is_last_read_loc: is this the last read location
++ *
++ * This function will set location last register value
++ */
++static void nandc_set_read_loc_last(struct nand_chip *chip,
++ int reg_base, u32 cw_offset,
++ u32 read_size, u32 is_last_read_loc)
++{
++ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++ __le32 locreg_val;
++ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
++ ((read_size) << READ_LOCATION_SIZE) |
++ ((is_last_read_loc) << READ_LOCATION_LAST));
++
++ locreg_val = cpu_to_le32(val);
++
++ if (reg_base == NAND_READ_LOCATION_LAST_CW_0)
++ nandc->regs->read_location_last0 = locreg_val;
++ else if (reg_base == NAND_READ_LOCATION_LAST_CW_1)
++ nandc->regs->read_location_last1 = locreg_val;
++ else if (reg_base == NAND_READ_LOCATION_LAST_CW_2)
++ nandc->regs->read_location_last2 = locreg_val;
++ else if (reg_base == NAND_READ_LOCATION_LAST_CW_3)
++ nandc->regs->read_location_last3 = locreg_val;
++}
++
+ /* helper to configure location register values */
+ static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg,
+- int cw_offset, int read_size, int is_last_read_loc)
++ u32 cw_offset, u32 read_size, u32 is_last_read_loc)
+ {
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int reg_base = NAND_READ_LOCATION_0;
+
+- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
++ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw))
+ reg_base = NAND_READ_LOCATION_LAST_CW_0;
+
+ reg_base += reg * 4;
+
+- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
++ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw))
+ return nandc_set_read_loc_last(chip, reg_base, cw_offset,
+ read_size, is_last_read_loc);
+ else
+@@ -792,12 +756,13 @@ static void nandc_set_read_loc(struct na
+ static void set_address(struct qcom_nand_host *host, u16 column, int page)
+ {
+ struct nand_chip *chip = &host->chip;
++ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+ if (chip->options & NAND_BUSWIDTH_16)
+ column >>= 1;
+
+- nandc_set_reg(chip, NAND_ADDR0, page << 16 | column);
+- nandc_set_reg(chip, NAND_ADDR1, page >> 16 & 0xff);
++ nandc->regs->addr0 = cpu_to_le32(page << 16 | column);
++ nandc->regs->addr1 = cpu_to_le32(page >> 16 & 0xff);
+ }
+
+ /*
+@@ -811,41 +776,43 @@ static void set_address(struct qcom_nand
+ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, int cw)
+ {
+ struct nand_chip *chip = &host->chip;
+- u32 cmd, cfg0, cfg1, ecc_bch_cfg;
++ __le32 cmd, cfg0, cfg1, ecc_bch_cfg;
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+ if (read) {
+ if (host->use_ecc)
+- cmd = OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
++ cmd = cpu_to_le32(OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE);
+ else
+- cmd = OP_PAGE_READ | PAGE_ACC | LAST_PAGE;
++ cmd = cpu_to_le32(OP_PAGE_READ | PAGE_ACC | LAST_PAGE);
+ } else {
+- cmd = OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
++ cmd = cpu_to_le32(OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE);
+ }
+
+ if (host->use_ecc) {
+- cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) |
+- (num_cw - 1) << CW_PER_PAGE;
++ cfg0 = cpu_to_le32((host->cfg0 & ~(7U << CW_PER_PAGE)) |
++ (num_cw - 1) << CW_PER_PAGE);
+
+- cfg1 = host->cfg1;
+- ecc_bch_cfg = host->ecc_bch_cfg;
++ cfg1 = cpu_to_le32(host->cfg1);
++ ecc_bch_cfg = cpu_to_le32(host->ecc_bch_cfg);
+ } else {
+- cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
+- (num_cw - 1) << CW_PER_PAGE;
++ cfg0 = cpu_to_le32((host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
++ (num_cw - 1) << CW_PER_PAGE);
+
+- cfg1 = host->cfg1_raw;
+- ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
++ cfg1 = cpu_to_le32(host->cfg1_raw);
++ ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
+ }
+
+- nandc_set_reg(chip, NAND_FLASH_CMD, cmd);
+- nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0);
+- nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1);
+- nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
+- if (!nandc->props->qpic_v2)
+- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
+- nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
+- nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
+- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
++ nandc->regs->cmd = cmd;
++ nandc->regs->cfg0 = cfg0;
++ nandc->regs->cfg1 = cfg1;
++ nandc->regs->ecc_bch_cfg = ecc_bch_cfg;
++
++ if (!nandc->props->qpic_version2)
++ nandc->regs->ecc_buf_cfg = cpu_to_le32(host->ecc_buf_cfg);
++
++ nandc->regs->clrflashstatus = cpu_to_le32(host->clrflashstatus);
++ nandc->regs->clrreadstatus = cpu_to_le32(host->clrreadstatus);
++ nandc->regs->exec = cpu_to_le32(1);
+
+ if (read)
+ nandc_set_read_loc(chip, cw, 0, 0, host->use_ecc ?
+@@ -1121,7 +1088,7 @@ static int read_reg_dma(struct qcom_nand
+ if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
+ first = dev_cmd_reg_addr(nandc, first);
+
+- if (nandc->props->is_bam)
++ if (nandc->props->supports_bam)
+ return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
+ num_regs, flags);
+
+@@ -1136,25 +1103,16 @@ static int read_reg_dma(struct qcom_nand
+ * write_reg_dma: prepares a descriptor to write a given number of
+ * contiguous registers
+ *
++ * @vaddr: contiguous memory from where register value will
++ * be written
+ * @first: offset of the first register in the contiguous block
+ * @num_regs: number of registers to write
+ * @flags: flags to control DMA descriptor preparation
+ */
+-static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
+- int num_regs, unsigned int flags)
++static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
++ int first, int num_regs, unsigned int flags)
+ {
+ bool flow_control = false;
+- struct nandc_regs *regs = nandc->regs;
+- void *vaddr;
+-
+- vaddr = offset_to_nandc_reg(regs, first);
+-
+- if (first == NAND_ERASED_CW_DETECT_CFG) {
+- if (flags & NAND_ERASED_CW_SET)
+- vaddr = ®s->erased_cw_detect_cfg_set;
+- else
+- vaddr = ®s->erased_cw_detect_cfg_clr;
+- }
+
+ if (first == NAND_EXEC_CMD)
+ flags |= NAND_BAM_NWD;
+@@ -1165,7 +1123,7 @@ static int write_reg_dma(struct qcom_nan
+ if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
+ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
+
+- if (nandc->props->is_bam)
++ if (nandc->props->supports_bam)
+ return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
+ num_regs, flags);
+
+@@ -1188,7 +1146,7 @@ static int write_reg_dma(struct qcom_nan
+ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+ const u8 *vaddr, int size, unsigned int flags)
+ {
+- if (nandc->props->is_bam)
++ if (nandc->props->supports_bam)
+ return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
+
+ return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
+@@ -1206,7 +1164,7 @@ static int read_data_dma(struct qcom_nan
+ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+ const u8 *vaddr, int size, unsigned int flags)
+ {
+- if (nandc->props->is_bam)
++ if (nandc->props->supports_bam)
+ return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
+
+ return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
+@@ -1220,13 +1178,14 @@ static void config_nand_page_read(struct
+ {
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+- write_reg_dma(nandc, NAND_ADDR0, 2, 0);
+- write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
+- if (!nandc->props->qpic_v2)
+- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
+- write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
+- write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
+- NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
++ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++ if (!nandc->props->qpic_version2)
++ write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
++ write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr,
++ NAND_ERASED_CW_DETECT_CFG, 1, 0);
++ write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set,
++ NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
+ }
+
+ /*
+@@ -1239,16 +1198,16 @@ config_nand_cw_read(struct nand_chip *ch
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+- int reg = NAND_READ_LOCATION_0;
++ __le32 *reg = &nandc->regs->read_location0;
+
+- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
+- reg = NAND_READ_LOCATION_LAST_CW_0;
++ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw))
++ reg = &nandc->regs->read_location_last0;
+
+- if (nandc->props->is_bam)
+- write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL);
++ if (nandc->props->supports_bam)
++ write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
+
+- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+ if (use_ecc) {
+ read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
+@@ -1279,10 +1238,10 @@ static void config_nand_page_write(struc
+ {
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+- write_reg_dma(nandc, NAND_ADDR0, 2, 0);
+- write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
+- if (!nandc->props->qpic_v2)
+- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
++ write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
++ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++ if (!nandc->props->qpic_version2)
++ write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1,
+ NAND_BAM_NEXT_SGL);
+ }
+
+@@ -1294,13 +1253,13 @@ static void config_nand_cw_write(struct
+ {
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+ read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+- write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
+- write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
++ write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
+ }
+
+ /* helpers to submit/free our list of dma descriptors */
+@@ -1311,7 +1270,7 @@ static int submit_descs(struct qcom_nand
+ struct bam_transaction *bam_txn = nandc->bam_txn;
+ int ret = 0;
+
+- if (nandc->props->is_bam) {
++ if (nandc->props->supports_bam) {
+ if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
+ ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
+ if (ret)
+@@ -1336,14 +1295,9 @@ static int submit_descs(struct qcom_nand
+ list_for_each_entry(desc, &nandc->desc_list, node)
+ cookie = dmaengine_submit(desc->dma_desc);
+
+- if (nandc->props->is_bam) {
++ if (nandc->props->supports_bam) {
+ bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
+ bam_txn->last_cmd_desc->callback_param = bam_txn;
+- if (bam_txn->last_data_desc) {
+- bam_txn->last_data_desc->callback = qpic_bam_dma_done;
+- bam_txn->last_data_desc->callback_param = bam_txn;
+- bam_txn->wait_second_completion = true;
+- }
+
+ dma_async_issue_pending(nandc->tx_chan);
+ dma_async_issue_pending(nandc->rx_chan);
+@@ -1365,7 +1319,7 @@ err_unmap_free_desc:
+ list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
+ list_del(&desc->node);
+
+- if (nandc->props->is_bam)
++ if (nandc->props->supports_bam)
+ dma_unmap_sg(nandc->dev, desc->bam_sgl,
+ desc->sgl_cnt, desc->dir);
+ else
+@@ -1382,7 +1336,7 @@ err_unmap_free_desc:
+ static void clear_read_regs(struct qcom_nand_controller *nandc)
+ {
+ nandc->reg_read_pos = 0;
+- nandc_read_buffer_sync(nandc, false);
++ nandc_dev_to_mem(nandc, false);
+ }
+
+ /*
+@@ -1446,7 +1400,7 @@ static int check_flash_errors(struct qco
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+ int i;
+
+- nandc_read_buffer_sync(nandc, true);
++ nandc_dev_to_mem(nandc, true);
+
+ for (i = 0; i < cw_cnt; i++) {
+ u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
+@@ -1476,7 +1430,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *
+ clear_read_regs(nandc);
+ host->use_ecc = false;
+
+- if (nandc->props->qpic_v2)
++ if (nandc->props->qpic_version2)
+ raw_cw = ecc->steps - 1;
+
+ clear_bam_transaction(nandc);
+@@ -1497,7 +1451,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *
+ oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+ }
+
+- if (nandc->props->is_bam) {
++ if (nandc->props->supports_bam) {
+ nandc_set_read_loc(chip, cw, 0, read_loc, data_size1, 0);
+ read_loc += data_size1;
+
+@@ -1621,7 +1575,7 @@ static int parse_read_errors(struct qcom
+ u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
+
+ buf = (struct read_stats *)nandc->reg_read_buf;
+- nandc_read_buffer_sync(nandc, true);
++ nandc_dev_to_mem(nandc, true);
+
+ for (i = 0; i < ecc->steps; i++, buf++) {
+ u32 flash, buffer, erased_cw;
+@@ -1734,7 +1688,7 @@ static int read_page_ecc(struct qcom_nan
+ oob_size = host->ecc_bytes_hw + host->spare_bytes;
+ }
+
+- if (nandc->props->is_bam) {
++ if (nandc->props->supports_bam) {
+ if (data_buf && oob_buf) {
+ nandc_set_read_loc(chip, i, 0, 0, data_size, 0);
+ nandc_set_read_loc(chip, i, 1, data_size,
+@@ -2455,14 +2409,14 @@ static int qcom_nand_attach_chip(struct
+
+ mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
+ /* Free the initially allocated BAM transaction for reading the ONFI params */
+- if (nandc->props->is_bam)
++ if (nandc->props->supports_bam)
+ free_bam_transaction(nandc);
+
+ nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
+ cwperpage);
+
+ /* Now allocate the BAM transaction based on updated max_cwperpage */
+- if (nandc->props->is_bam) {
++ if (nandc->props->supports_bam) {
+ nandc->bam_txn = alloc_bam_transaction(nandc);
+ if (!nandc->bam_txn) {
+ dev_err(nandc->dev,
+@@ -2522,7 +2476,7 @@ static int qcom_nand_attach_chip(struct
+ | ecc_mode << ECC_MODE
+ | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
+
+- if (!nandc->props->qpic_v2)
++ if (!nandc->props->qpic_version2)
+ host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+
+ host->clrflashstatus = FS_READY_BSY_N;
+@@ -2556,7 +2510,7 @@ static int qcom_op_cmd_mapping(struct na
+ cmd = OP_FETCH_ID;
+ break;
+ case NAND_CMD_PARAM:
+- if (nandc->props->qpic_v2)
++ if (nandc->props->qpic_version2)
+ cmd = OP_PAGE_READ_ONFI_READ;
+ else
+ cmd = OP_PAGE_READ;
+@@ -2609,7 +2563,7 @@ static int qcom_parse_instructions(struc
+ if (ret < 0)
+ return ret;
+
+- q_op->cmd_reg = ret;
++ q_op->cmd_reg = cpu_to_le32(ret);
+ q_op->rdy_delay_ns = instr->delay_ns;
+ break;
+
+@@ -2619,10 +2573,10 @@ static int qcom_parse_instructions(struc
+ addrs = &instr->ctx.addr.addrs[offset];
+
+ for (i = 0; i < min_t(unsigned int, 4, naddrs); i++)
+- q_op->addr1_reg |= addrs[i] << (i * 8);
++ q_op->addr1_reg |= cpu_to_le32(addrs[i] << (i * 8));
+
+ if (naddrs > 4)
+- q_op->addr2_reg |= addrs[4];
++ q_op->addr2_reg |= cpu_to_le32(addrs[4]);
+
+ q_op->rdy_delay_ns = instr->delay_ns;
+ break;
+@@ -2663,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nan
+ unsigned long start = jiffies + msecs_to_jiffies(time_ms);
+ u32 flash;
+
+- nandc_read_buffer_sync(nandc, true);
++ nandc_dev_to_mem(nandc, true);
+
+ do {
+ flash = le32_to_cpu(nandc->reg_read_buf[0]);
+@@ -2706,11 +2660,11 @@ static int qcom_read_status_exec(struct
+ clear_read_regs(nandc);
+ clear_bam_transaction(nandc);
+
+- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
+- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
++ nandc->regs->cmd = q_op.cmd_reg;
++ nandc->regs->exec = cpu_to_le32(1);
+
+- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+ read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+ ret = submit_descs(nandc);
+@@ -2719,7 +2673,7 @@ static int qcom_read_status_exec(struct
+ goto err_out;
+ }
+
+- nandc_read_buffer_sync(nandc, true);
++ nandc_dev_to_mem(nandc, true);
+
+ for (i = 0; i < num_cw; i++) {
+ flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
+@@ -2763,16 +2717,14 @@ static int qcom_read_id_type_exec(struct
+ clear_read_regs(nandc);
+ clear_bam_transaction(nandc);
+
+- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
+- nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg);
+- nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg);
+- nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
+- nandc->props->is_bam ? 0 : DM_EN);
++ nandc->regs->cmd = q_op.cmd_reg;
++ nandc->regs->addr0 = q_op.addr1_reg;
++ nandc->regs->addr1 = q_op.addr2_reg;
++ nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN);
++ nandc->regs->exec = cpu_to_le32(1);
+
+- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
+-
+- write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
+- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+ read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
+
+@@ -2786,7 +2738,7 @@ static int qcom_read_id_type_exec(struct
+ op_id = q_op.data_instr_idx;
+ len = nand_subop_get_data_len(subop, op_id);
+
+- nandc_read_buffer_sync(nandc, true);
++ nandc_dev_to_mem(nandc, true);
+ memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len);
+
+ err_out:
+@@ -2807,15 +2759,14 @@ static int qcom_misc_cmd_type_exec(struc
+
+ if (q_op.flag == OP_PROGRAM_PAGE) {
+ goto wait_rdy;
+- } else if (q_op.cmd_reg == OP_BLOCK_ERASE) {
+- q_op.cmd_reg |= PAGE_ACC | LAST_PAGE;
+- nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg);
+- nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg);
+- nandc_set_reg(chip, NAND_DEV0_CFG0,
+- host->cfg0_raw & ~(7 << CW_PER_PAGE));
+- nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
++ } else if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE)) {
++ q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE);
++ nandc->regs->addr0 = q_op.addr1_reg;
++ nandc->regs->addr1 = q_op.addr2_reg;
++ nandc->regs->cfg0 = cpu_to_le32(host->cfg0_raw & ~(7 << CW_PER_PAGE));
++ nandc->regs->cfg1 = cpu_to_le32(host->cfg1_raw);
+ instrs = 3;
+- } else if (q_op.cmd_reg != OP_RESET_DEVICE) {
++ } else if (q_op.cmd_reg != cpu_to_le32(OP_RESET_DEVICE)) {
+ return 0;
+ }
+
+@@ -2826,14 +2777,14 @@ static int qcom_misc_cmd_type_exec(struc
+ clear_read_regs(nandc);
+ clear_bam_transaction(nandc);
+
+- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
+- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
++ nandc->regs->cmd = q_op.cmd_reg;
++ nandc->regs->exec = cpu_to_le32(1);
+
+- write_reg_dma(nandc, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
+- if (q_op.cmd_reg == OP_BLOCK_ERASE)
+- write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
++ if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE))
++ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
+
+- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+ read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+ ret = submit_descs(nandc);
+@@ -2864,7 +2815,7 @@ static int qcom_param_page_type_exec(str
+ if (ret)
+ return ret;
+
+- q_op.cmd_reg |= PAGE_ACC | LAST_PAGE;
++ q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE);
+
+ nandc->buf_count = 0;
+ nandc->buf_start = 0;
+@@ -2872,38 +2823,38 @@ static int qcom_param_page_type_exec(str
+ clear_read_regs(nandc);
+ clear_bam_transaction(nandc);
+
+- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
++ nandc->regs->cmd = q_op.cmd_reg;
++ nandc->regs->addr0 = 0;
++ nandc->regs->addr1 = 0;
++
++ nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE |
++ 512 << UD_SIZE_BYTES |
++ 5 << NUM_ADDR_CYCLES |
++ 0 << SPARE_SIZE_BYTES);
++
++ nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES |
++ 0 << CS_ACTIVE_BSY |
++ 17 << BAD_BLOCK_BYTE_NUM |
++ 1 << BAD_BLOCK_IN_SPARE_AREA |
++ 2 << WR_RD_BSY_GAP |
++ 0 << WIDE_FLASH |
++ 1 << DEV0_CFG1_ECC_DISABLE);
+
+- nandc_set_reg(chip, NAND_ADDR0, 0);
+- nandc_set_reg(chip, NAND_ADDR1, 0);
+- nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
+- | 512 << UD_SIZE_BYTES
+- | 5 << NUM_ADDR_CYCLES
+- | 0 << SPARE_SIZE_BYTES);
+- nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
+- | 0 << CS_ACTIVE_BSY
+- | 17 << BAD_BLOCK_BYTE_NUM
+- | 1 << BAD_BLOCK_IN_SPARE_AREA
+- | 2 << WR_RD_BSY_GAP
+- | 0 << WIDE_FLASH
+- | 1 << DEV0_CFG1_ECC_DISABLE);
+- if (!nandc->props->qpic_v2)
+- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
++ if (!nandc->props->qpic_version2)
++ nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
+
+ /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
+- if (!nandc->props->qpic_v2) {
+- nandc_set_reg(chip, NAND_DEV_CMD_VLD,
+- (nandc->vld & ~READ_START_VLD));
+- nandc_set_reg(chip, NAND_DEV_CMD1,
+- (nandc->cmd1 & ~(0xFF << READ_ADDR))
+- | NAND_CMD_PARAM << READ_ADDR);
++ if (!nandc->props->qpic_version2) {
++ nandc->regs->vld = cpu_to_le32((nandc->vld & ~READ_START_VLD));
++ nandc->regs->cmd1 = cpu_to_le32((nandc->cmd1 & ~(0xFF << READ_ADDR))
++ | NAND_CMD_PARAM << READ_ADDR);
+ }
+
+- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
+-
+- if (!nandc->props->qpic_v2) {
+- nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
+- nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
++ nandc->regs->exec = cpu_to_le32(1);
++
++ if (!nandc->props->qpic_version2) {
++ nandc->regs->orig_cmd1 = cpu_to_le32(nandc->cmd1);
++ nandc->regs->orig_vld = cpu_to_le32(nandc->vld);
+ }
+
+ instr = q_op.data_instr;
+@@ -2912,9 +2863,9 @@ static int qcom_param_page_type_exec(str
+
+ nandc_set_read_loc(chip, 0, 0, 0, len, 1);
+
+- if (!nandc->props->qpic_v2) {
+- write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
+- write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
++ if (!nandc->props->qpic_version2) {
++ write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
++ write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
+ }
+
+ nandc->buf_count = len;
+@@ -2926,9 +2877,10 @@ static int qcom_param_page_type_exec(str
+ nandc->buf_count, 0);
+
+ /* restore CMD1 and VLD regs */
+- if (!nandc->props->qpic_v2) {
+- write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
+- write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
++ if (!nandc->props->qpic_version2) {
++ write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
++ write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
++ NAND_BAM_NEXT_SGL);
+ }
+
+ ret = submit_descs(nandc);
+@@ -3017,7 +2969,7 @@ static const struct nand_controller_ops
+
+ static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
+ {
+- if (nandc->props->is_bam) {
++ if (nandc->props->supports_bam) {
+ if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
+ dma_unmap_single(nandc->dev, nandc->reg_read_dma,
+ MAX_REG_RD *
+@@ -3070,7 +3022,7 @@ static int qcom_nandc_alloc(struct qcom_
+ if (!nandc->reg_read_buf)
+ return -ENOMEM;
+
+- if (nandc->props->is_bam) {
++ if (nandc->props->supports_bam) {
+ nandc->reg_read_dma =
+ dma_map_single(nandc->dev, nandc->reg_read_buf,
+ MAX_REG_RD *
+@@ -3151,15 +3103,15 @@ static int qcom_nandc_setup(struct qcom_
+ u32 nand_ctrl;
+
+ /* kill onenand */
+- if (!nandc->props->is_qpic)
++ if (!nandc->props->nandc_part_of_qpic)
+ nandc_write(nandc, SFLASHC_BURST_CFG, 0);
+
+- if (!nandc->props->qpic_v2)
++ if (!nandc->props->qpic_version2)
+ nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
+ NAND_DEV_CMD_VLD_VAL);
+
+ /* enable ADM or BAM DMA */
+- if (nandc->props->is_bam) {
++ if (nandc->props->supports_bam) {
+ nand_ctrl = nandc_read(nandc, NAND_CTRL);
+
+ /*
+@@ -3176,7 +3128,7 @@ static int qcom_nandc_setup(struct qcom_
+ }
+
+ /* save the original values of these registers */
+- if (!nandc->props->qpic_v2) {
++ if (!nandc->props->qpic_version2) {
+ nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
+ nandc->vld = NAND_DEV_CMD_VLD_VAL;
+ }
+@@ -3349,7 +3301,7 @@ static int qcom_nandc_parse_dt(struct pl
+ struct device_node *np = nandc->dev->of_node;
+ int ret;
+
+- if (!nandc->props->is_bam) {
++ if (!nandc->props->supports_bam) {
+ ret = of_property_read_u32(np, "qcom,cmd-crci",
+ &nandc->cmd_crci);
+ if (ret) {
+@@ -3474,30 +3426,30 @@ static void qcom_nandc_remove(struct pla
+
+ static const struct qcom_nandc_props ipq806x_nandc_props = {
+ .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
+- .is_bam = false,
++ .supports_bam = false,
+ .use_codeword_fixup = true,
+ .dev_cmd_reg_start = 0x0,
+ };
+
+ static const struct qcom_nandc_props ipq4019_nandc_props = {
+ .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+- .is_bam = true,
+- .is_qpic = true,
++ .supports_bam = true,
++ .nandc_part_of_qpic = true,
+ .dev_cmd_reg_start = 0x0,
+ };
+
+ static const struct qcom_nandc_props ipq8074_nandc_props = {
+ .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+- .is_bam = true,
+- .is_qpic = true,
++ .supports_bam = true,
++ .nandc_part_of_qpic = true,
+ .dev_cmd_reg_start = 0x7000,
+ };
+
+ static const struct qcom_nandc_props sdx55_nandc_props = {
+ .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+- .is_bam = true,
+- .is_qpic = true,
+- .qpic_v2 = true,
++ .supports_bam = true,
++ .nandc_part_of_qpic = true,
++ .qpic_version2 = true,
+ .dev_cmd_reg_start = 0x7000,
+ };
+
--- /dev/null
+From 1d479f5b345e0c3650fec4dddeef9fc6fab30c8b Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Nov 2024 14:45:01 +0530
+Subject: [PATCH 2/4] mtd: rawnand: qcom: Add qcom prefix to common api
+
+Add qcom prefix to all the api which will be commonly
+used by spi nand driver and raw nand driver.
+
+---
+ drivers/mtd/nand/raw/qcom_nandc.c | 320 +++++++++++++++---------------
+ 1 file changed, 160 insertions(+), 160 deletions(-)
+
+--- a/drivers/mtd/nand/raw/qcom_nandc.c
++++ b/drivers/mtd/nand/raw/qcom_nandc.c
+@@ -53,7 +53,7 @@
+ #define NAND_READ_LOCATION_LAST_CW_2 0xf48
+ #define NAND_READ_LOCATION_LAST_CW_3 0xf4c
+
+-/* dummy register offsets, used by write_reg_dma */
++/* dummy register offsets, used by qcom_write_reg_dma */
+ #define NAND_DEV_CMD1_RESTORE 0xdead
+ #define NAND_DEV_CMD_VLD_RESTORE 0xbeef
+
+@@ -211,7 +211,7 @@
+
+ /*
+ * Flags used in DMA descriptor preparation helper functions
+- * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
++ * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
+ */
+ /* Don't set the EOT in current tx BAM sgl */
+ #define NAND_BAM_NO_EOT BIT(0)
+@@ -550,7 +550,7 @@ struct qcom_nandc_props {
+ };
+
+ /* Frees the BAM transaction memory */
+-static void free_bam_transaction(struct qcom_nand_controller *nandc)
++static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
+ {
+ struct bam_transaction *bam_txn = nandc->bam_txn;
+
+@@ -559,7 +559,7 @@ static void free_bam_transaction(struct
+
+ /* Allocates and Initializes the BAM transaction */
+ static struct bam_transaction *
+-alloc_bam_transaction(struct qcom_nand_controller *nandc)
++qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
+ {
+ struct bam_transaction *bam_txn;
+ size_t bam_txn_size;
+@@ -595,7 +595,7 @@ alloc_bam_transaction(struct qcom_nand_c
+ }
+
+ /* Clears the BAM transaction indexes */
+-static void clear_bam_transaction(struct qcom_nand_controller *nandc)
++static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
+ {
+ struct bam_transaction *bam_txn = nandc->bam_txn;
+
+@@ -614,7 +614,7 @@ static void clear_bam_transaction(struct
+ }
+
+ /* Callback for DMA descriptor completion */
+-static void qpic_bam_dma_done(void *data)
++static void qcom_qpic_bam_dma_done(void *data)
+ {
+ struct bam_transaction *bam_txn = data;
+
+@@ -644,7 +644,7 @@ static void nandc_write(struct qcom_nand
+ iowrite32(val, nandc->base + offset);
+ }
+
+-static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
++static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
+ {
+ if (!nandc->props->supports_bam)
+ return;
+@@ -824,9 +824,9 @@ static void update_rw_regs(struct qcom_n
+ * for BAM. This descriptor will be added in the NAND DMA descriptor queue
+ * which will be submitted to DMA engine.
+ */
+-static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
+- struct dma_chan *chan,
+- unsigned long flags)
++static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
++ struct dma_chan *chan,
++ unsigned long flags)
+ {
+ struct desc_info *desc;
+ struct scatterlist *sgl;
+@@ -903,9 +903,9 @@ static int prepare_bam_async_desc(struct
+ * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
+ * after the current command element.
+ */
+-static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
+- int reg_off, const void *vaddr,
+- int size, unsigned int flags)
++static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
++ int reg_off, const void *vaddr,
++ int size, unsigned int flags)
+ {
+ int bam_ce_size;
+ int i, ret;
+@@ -943,9 +943,9 @@ static int prep_bam_dma_desc_cmd(struct
+ bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
+
+ if (flags & NAND_BAM_NWD) {
+- ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
+- DMA_PREP_FENCE |
+- DMA_PREP_CMD);
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
++ DMA_PREP_FENCE |
++ DMA_PREP_CMD);
+ if (ret)
+ return ret;
+ }
+@@ -958,9 +958,8 @@ static int prep_bam_dma_desc_cmd(struct
+ * Prepares the data descriptor for BAM DMA which will be used for NAND
+ * data reads and writes.
+ */
+-static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
+- const void *vaddr,
+- int size, unsigned int flags)
++static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
++ const void *vaddr, int size, unsigned int flags)
+ {
+ int ret;
+ struct bam_transaction *bam_txn = nandc->bam_txn;
+@@ -979,8 +978,8 @@ static int prep_bam_dma_desc_data(struct
+ * is not set, form the DMA descriptor
+ */
+ if (!(flags & NAND_BAM_NO_EOT)) {
+- ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
+- DMA_PREP_INTERRUPT);
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
++ DMA_PREP_INTERRUPT);
+ if (ret)
+ return ret;
+ }
+@@ -989,9 +988,9 @@ static int prep_bam_dma_desc_data(struct
+ return 0;
+ }
+
+-static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
+- int reg_off, const void *vaddr, int size,
+- bool flow_control)
++static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
++ int reg_off, const void *vaddr, int size,
++ bool flow_control)
+ {
+ struct desc_info *desc;
+ struct dma_async_tx_descriptor *dma_desc;
+@@ -1069,15 +1068,15 @@ err:
+ }
+
+ /*
+- * read_reg_dma: prepares a descriptor to read a given number of
++ * qcom_read_reg_dma: prepares a descriptor to read a given number of
+ * contiguous registers to the reg_read_buf pointer
+ *
+ * @first: offset of the first register in the contiguous block
+ * @num_regs: number of registers to read
+ * @flags: flags to control DMA descriptor preparation
+ */
+-static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
+- int num_regs, unsigned int flags)
++static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
++ int num_regs, unsigned int flags)
+ {
+ bool flow_control = false;
+ void *vaddr;
+@@ -1089,18 +1088,18 @@ static int read_reg_dma(struct qcom_nand
+ first = dev_cmd_reg_addr(nandc, first);
+
+ if (nandc->props->supports_bam)
+- return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
++ return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
+ num_regs, flags);
+
+ if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
+ flow_control = true;
+
+- return prep_adm_dma_desc(nandc, true, first, vaddr,
++ return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
+ num_regs * sizeof(u32), flow_control);
+ }
+
+ /*
+- * write_reg_dma: prepares a descriptor to write a given number of
++ * qcom_write_reg_dma: prepares a descriptor to write a given number of
+ * contiguous registers
+ *
+ * @vaddr: contiguous memory from where register value will
+@@ -1109,8 +1108,8 @@ static int read_reg_dma(struct qcom_nand
+ * @num_regs: number of registers to write
+ * @flags: flags to control DMA descriptor preparation
+ */
+-static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
+- int first, int num_regs, unsigned int flags)
++static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
++ int first, int num_regs, unsigned int flags)
+ {
+ bool flow_control = false;
+
+@@ -1124,18 +1123,18 @@ static int write_reg_dma(struct qcom_nan
+ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
+
+ if (nandc->props->supports_bam)
+- return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
++ return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
+ num_regs, flags);
+
+ if (first == NAND_FLASH_CMD)
+ flow_control = true;
+
+- return prep_adm_dma_desc(nandc, false, first, vaddr,
++ return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
+ num_regs * sizeof(u32), flow_control);
+ }
+
+ /*
+- * read_data_dma: prepares a DMA descriptor to transfer data from the
++ * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the
+ * controller's internal buffer to the buffer 'vaddr'
+ *
+ * @reg_off: offset within the controller's data buffer
+@@ -1143,17 +1142,17 @@ static int write_reg_dma(struct qcom_nan
+ * @size: DMA transaction size in bytes
+ * @flags: flags to control DMA descriptor preparation
+ */
+-static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+- const u8 *vaddr, int size, unsigned int flags)
++static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
++ const u8 *vaddr, int size, unsigned int flags)
+ {
+ if (nandc->props->supports_bam)
+- return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
++ return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
+
+- return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
++ return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
+ }
+
+ /*
+- * write_data_dma: prepares a DMA descriptor to transfer data from
++ * qcom_write_data_dma: prepares a DMA descriptor to transfer data from
+ * 'vaddr' to the controller's internal buffer
+ *
+ * @reg_off: offset within the controller's data buffer
+@@ -1161,13 +1160,13 @@ static int read_data_dma(struct qcom_nan
+ * @size: DMA transaction size in bytes
+ * @flags: flags to control DMA descriptor preparation
+ */
+-static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+- const u8 *vaddr, int size, unsigned int flags)
++static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
++ const u8 *vaddr, int size, unsigned int flags)
+ {
+ if (nandc->props->supports_bam)
+- return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
++ return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
+
+- return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
++ return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
+ }
+
+ /*
+@@ -1178,14 +1177,14 @@ static void config_nand_page_read(struct
+ {
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+- write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
+- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++ qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
++ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
+ if (!nandc->props->qpic_version2)
+- write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
+- write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr,
+- NAND_ERASED_CW_DETECT_CFG, 1, 0);
+- write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set,
+- NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
++ qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr,
++ NAND_ERASED_CW_DETECT_CFG, 1, 0);
++ qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set,
++ NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
+ }
+
+ /*
+@@ -1204,17 +1203,17 @@ config_nand_cw_read(struct nand_chip *ch
+ reg = &nandc->regs->read_location_last0;
+
+ if (nandc->props->supports_bam)
+- write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
+
+- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+ if (use_ecc) {
+- read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
+- read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
+- NAND_BAM_NEXT_SGL);
++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
++ qcom_read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
++ NAND_BAM_NEXT_SGL);
+ } else {
+- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+ }
+ }
+
+@@ -1238,11 +1237,11 @@ static void config_nand_page_write(struc
+ {
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+- write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
+- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++ qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
++ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
+ if (!nandc->props->qpic_version2)
+- write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1,
+- NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1,
++ NAND_BAM_NEXT_SGL);
+ }
+
+ /*
+@@ -1253,17 +1252,18 @@ static void config_nand_cw_write(struct
+ {
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+- write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
+- write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
++ qcom_write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1,
++ NAND_BAM_NEXT_SGL);
+ }
+
+ /* helpers to submit/free our list of dma descriptors */
+-static int submit_descs(struct qcom_nand_controller *nandc)
++static int qcom_submit_descs(struct qcom_nand_controller *nandc)
+ {
+ struct desc_info *desc, *n;
+ dma_cookie_t cookie = 0;
+@@ -1272,21 +1272,21 @@ static int submit_descs(struct qcom_nand
+
+ if (nandc->props->supports_bam) {
+ if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
+- ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
+ if (ret)
+ goto err_unmap_free_desc;
+ }
+
+ if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
+- ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
+- DMA_PREP_INTERRUPT);
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
++ DMA_PREP_INTERRUPT);
+ if (ret)
+ goto err_unmap_free_desc;
+ }
+
+ if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
+- ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
+- DMA_PREP_CMD);
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
++ DMA_PREP_CMD);
+ if (ret)
+ goto err_unmap_free_desc;
+ }
+@@ -1296,7 +1296,7 @@ static int submit_descs(struct qcom_nand
+ cookie = dmaengine_submit(desc->dma_desc);
+
+ if (nandc->props->supports_bam) {
+- bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
++ bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
+ bam_txn->last_cmd_desc->callback_param = bam_txn;
+
+ dma_async_issue_pending(nandc->tx_chan);
+@@ -1314,7 +1314,7 @@ static int submit_descs(struct qcom_nand
+ err_unmap_free_desc:
+ /*
+ * Unmap the dma sg_list and free the desc allocated by both
+- * prepare_bam_async_desc() and prep_adm_dma_desc() functions.
++ * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
+ */
+ list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
+ list_del(&desc->node);
+@@ -1333,10 +1333,10 @@ err_unmap_free_desc:
+ }
+
+ /* reset the register read buffer for next NAND operation */
+-static void clear_read_regs(struct qcom_nand_controller *nandc)
++static void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
+ {
+ nandc->reg_read_pos = 0;
+- nandc_dev_to_mem(nandc, false);
++ qcom_nandc_dev_to_mem(nandc, false);
+ }
+
+ /*
+@@ -1400,7 +1400,7 @@ static int check_flash_errors(struct qco
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+ int i;
+
+- nandc_dev_to_mem(nandc, true);
++ qcom_nandc_dev_to_mem(nandc, true);
+
+ for (i = 0; i < cw_cnt; i++) {
+ u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
+@@ -1427,13 +1427,13 @@ qcom_nandc_read_cw_raw(struct mtd_info *
+ nand_read_page_op(chip, page, 0, NULL, 0);
+ nandc->buf_count = 0;
+ nandc->buf_start = 0;
+- clear_read_regs(nandc);
++ qcom_clear_read_regs(nandc);
+ host->use_ecc = false;
+
+ if (nandc->props->qpic_version2)
+ raw_cw = ecc->steps - 1;
+
+- clear_bam_transaction(nandc);
++ qcom_clear_bam_transaction(nandc);
+ set_address(host, host->cw_size * cw, page);
+ update_rw_regs(host, 1, true, raw_cw);
+ config_nand_page_read(chip);
+@@ -1466,18 +1466,18 @@ qcom_nandc_read_cw_raw(struct mtd_info *
+
+ config_nand_cw_read(chip, false, raw_cw);
+
+- read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
++ qcom_read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
+ reg_off += data_size1;
+
+- read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
++ qcom_read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
+ reg_off += oob_size1;
+
+- read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
++ qcom_read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
+ reg_off += data_size2;
+
+- read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
++ qcom_read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure to read raw cw %d\n", cw);
+ return ret;
+@@ -1575,7 +1575,7 @@ static int parse_read_errors(struct qcom
+ u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
+
+ buf = (struct read_stats *)nandc->reg_read_buf;
+- nandc_dev_to_mem(nandc, true);
++ qcom_nandc_dev_to_mem(nandc, true);
+
+ for (i = 0; i < ecc->steps; i++, buf++) {
+ u32 flash, buffer, erased_cw;
+@@ -1704,8 +1704,8 @@ static int read_page_ecc(struct qcom_nan
+ config_nand_cw_read(chip, true, i);
+
+ if (data_buf)
+- read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
+- data_size, 0);
++ qcom_read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
++ data_size, 0);
+
+ /*
+ * when ecc is enabled, the controller doesn't read the real
+@@ -1720,8 +1720,8 @@ static int read_page_ecc(struct qcom_nan
+ for (j = 0; j < host->bbm_size; j++)
+ *oob_buf++ = 0xff;
+
+- read_data_dma(nandc, FLASH_BUF_ACC + data_size,
+- oob_buf, oob_size, 0);
++ qcom_read_data_dma(nandc, FLASH_BUF_ACC + data_size,
++ oob_buf, oob_size, 0);
+ }
+
+ if (data_buf)
+@@ -1730,7 +1730,7 @@ static int read_page_ecc(struct qcom_nan
+ oob_buf += oob_size;
+ }
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure to read page/oob\n");
+ return ret;
+@@ -1751,7 +1751,7 @@ static int copy_last_cw(struct qcom_nand
+ int size;
+ int ret;
+
+- clear_read_regs(nandc);
++ qcom_clear_read_regs(nandc);
+
+ size = host->use_ecc ? host->cw_data : host->cw_size;
+
+@@ -1763,9 +1763,9 @@ static int copy_last_cw(struct qcom_nand
+
+ config_nand_single_cw_page_read(chip, host->use_ecc, ecc->steps - 1);
+
+- read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
++ qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret)
+ dev_err(nandc->dev, "failed to copy last codeword\n");
+
+@@ -1851,14 +1851,14 @@ static int qcom_nandc_read_page(struct n
+ nandc->buf_count = 0;
+ nandc->buf_start = 0;
+ host->use_ecc = true;
+- clear_read_regs(nandc);
++ qcom_clear_read_regs(nandc);
+ set_address(host, 0, page);
+ update_rw_regs(host, ecc->steps, true, 0);
+
+ data_buf = buf;
+ oob_buf = oob_required ? chip->oob_poi : NULL;
+
+- clear_bam_transaction(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ return read_page_ecc(host, data_buf, oob_buf, page);
+ }
+@@ -1899,8 +1899,8 @@ static int qcom_nandc_read_oob(struct na
+ if (host->nr_boot_partitions)
+ qcom_nandc_codeword_fixup(host, page);
+
+- clear_read_regs(nandc);
+- clear_bam_transaction(nandc);
++ qcom_clear_read_regs(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ host->use_ecc = true;
+ set_address(host, 0, page);
+@@ -1927,8 +1927,8 @@ static int qcom_nandc_write_page(struct
+ set_address(host, 0, page);
+ nandc->buf_count = 0;
+ nandc->buf_start = 0;
+- clear_read_regs(nandc);
+- clear_bam_transaction(nandc);
++ qcom_clear_read_regs(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ data_buf = (u8 *)buf;
+ oob_buf = chip->oob_poi;
+@@ -1949,8 +1949,8 @@ static int qcom_nandc_write_page(struct
+ oob_size = ecc->bytes;
+ }
+
+- write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
+- i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
++ qcom_write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
++ i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
+
+ /*
+ * when ECC is enabled, we don't really need to write anything
+@@ -1962,8 +1962,8 @@ static int qcom_nandc_write_page(struct
+ if (qcom_nandc_is_last_cw(ecc, i)) {
+ oob_buf += host->bbm_size;
+
+- write_data_dma(nandc, FLASH_BUF_ACC + data_size,
+- oob_buf, oob_size, 0);
++ qcom_write_data_dma(nandc, FLASH_BUF_ACC + data_size,
++ oob_buf, oob_size, 0);
+ }
+
+ config_nand_cw_write(chip);
+@@ -1972,7 +1972,7 @@ static int qcom_nandc_write_page(struct
+ oob_buf += oob_size;
+ }
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure to write page\n");
+ return ret;
+@@ -1997,8 +1997,8 @@ static int qcom_nandc_write_page_raw(str
+ qcom_nandc_codeword_fixup(host, page);
+
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+- clear_read_regs(nandc);
+- clear_bam_transaction(nandc);
++ qcom_clear_read_regs(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ data_buf = (u8 *)buf;
+ oob_buf = chip->oob_poi;
+@@ -2024,28 +2024,28 @@ static int qcom_nandc_write_page_raw(str
+ oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+ }
+
+- write_data_dma(nandc, reg_off, data_buf, data_size1,
+- NAND_BAM_NO_EOT);
++ qcom_write_data_dma(nandc, reg_off, data_buf, data_size1,
++ NAND_BAM_NO_EOT);
+ reg_off += data_size1;
+ data_buf += data_size1;
+
+- write_data_dma(nandc, reg_off, oob_buf, oob_size1,
+- NAND_BAM_NO_EOT);
++ qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size1,
++ NAND_BAM_NO_EOT);
+ reg_off += oob_size1;
+ oob_buf += oob_size1;
+
+- write_data_dma(nandc, reg_off, data_buf, data_size2,
+- NAND_BAM_NO_EOT);
++ qcom_write_data_dma(nandc, reg_off, data_buf, data_size2,
++ NAND_BAM_NO_EOT);
+ reg_off += data_size2;
+ data_buf += data_size2;
+
+- write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
++ qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
+ oob_buf += oob_size2;
+
+ config_nand_cw_write(chip);
+ }
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure to write raw page\n");
+ return ret;
+@@ -2075,7 +2075,7 @@ static int qcom_nandc_write_oob(struct n
+ qcom_nandc_codeword_fixup(host, page);
+
+ host->use_ecc = true;
+- clear_bam_transaction(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ /* calculate the data and oob size for the last codeword/step */
+ data_size = ecc->size - ((ecc->steps - 1) << 2);
+@@ -2090,11 +2090,11 @@ static int qcom_nandc_write_oob(struct n
+ update_rw_regs(host, 1, false, 0);
+
+ config_nand_page_write(chip);
+- write_data_dma(nandc, FLASH_BUF_ACC,
+- nandc->data_buffer, data_size + oob_size, 0);
++ qcom_write_data_dma(nandc, FLASH_BUF_ACC,
++ nandc->data_buffer, data_size + oob_size, 0);
+ config_nand_cw_write(chip);
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure to write oob\n");
+ return ret;
+@@ -2121,7 +2121,7 @@ static int qcom_nandc_block_bad(struct n
+ */
+ host->use_ecc = false;
+
+- clear_bam_transaction(nandc);
++ qcom_clear_bam_transaction(nandc);
+ ret = copy_last_cw(host, page);
+ if (ret)
+ goto err;
+@@ -2148,8 +2148,8 @@ static int qcom_nandc_block_markbad(stru
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int page, ret;
+
+- clear_read_regs(nandc);
+- clear_bam_transaction(nandc);
++ qcom_clear_read_regs(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ /*
+ * to mark the BBM as bad, we flash the entire last codeword with 0s.
+@@ -2166,11 +2166,11 @@ static int qcom_nandc_block_markbad(stru
+ update_rw_regs(host, 1, false, ecc->steps - 1);
+
+ config_nand_page_write(chip);
+- write_data_dma(nandc, FLASH_BUF_ACC,
+- nandc->data_buffer, host->cw_size, 0);
++ qcom_write_data_dma(nandc, FLASH_BUF_ACC,
++ nandc->data_buffer, host->cw_size, 0);
+ config_nand_cw_write(chip);
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure to update BBM\n");
+ return ret;
+@@ -2410,14 +2410,14 @@ static int qcom_nand_attach_chip(struct
+ mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
+ /* Free the initially allocated BAM transaction for reading the ONFI params */
+ if (nandc->props->supports_bam)
+- free_bam_transaction(nandc);
++ qcom_free_bam_transaction(nandc);
+
+ nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
+ cwperpage);
+
+ /* Now allocate the BAM transaction based on updated max_cwperpage */
+ if (nandc->props->supports_bam) {
+- nandc->bam_txn = alloc_bam_transaction(nandc);
++ nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
+ if (!nandc->bam_txn) {
+ dev_err(nandc->dev,
+ "failed to allocate bam transaction\n");
+@@ -2617,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nan
+ unsigned long start = jiffies + msecs_to_jiffies(time_ms);
+ u32 flash;
+
+- nandc_dev_to_mem(nandc, true);
++ qcom_nandc_dev_to_mem(nandc, true);
+
+ do {
+ flash = le32_to_cpu(nandc->reg_read_buf[0]);
+@@ -2657,23 +2657,23 @@ static int qcom_read_status_exec(struct
+ nandc->buf_start = 0;
+ host->use_ecc = false;
+
+- clear_read_regs(nandc);
+- clear_bam_transaction(nandc);
++ qcom_clear_read_regs(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ nandc->regs->cmd = q_op.cmd_reg;
+ nandc->regs->exec = cpu_to_le32(1);
+
+- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure in submitting status descriptor\n");
+ goto err_out;
+ }
+
+- nandc_dev_to_mem(nandc, true);
++ qcom_nandc_dev_to_mem(nandc, true);
+
+ for (i = 0; i < num_cw; i++) {
+ flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
+@@ -2714,8 +2714,8 @@ static int qcom_read_id_type_exec(struct
+ nandc->buf_start = 0;
+ host->use_ecc = false;
+
+- clear_read_regs(nandc);
+- clear_bam_transaction(nandc);
++ qcom_clear_read_regs(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ nandc->regs->cmd = q_op.cmd_reg;
+ nandc->regs->addr0 = q_op.addr1_reg;
+@@ -2723,12 +2723,12 @@ static int qcom_read_id_type_exec(struct
+ nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN);
+ nandc->regs->exec = cpu_to_le32(1);
+
+- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
+- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+- read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
++ qcom_read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure in submitting read id descriptor\n");
+ goto err_out;
+@@ -2738,7 +2738,7 @@ static int qcom_read_id_type_exec(struct
+ op_id = q_op.data_instr_idx;
+ len = nand_subop_get_data_len(subop, op_id);
+
+- nandc_dev_to_mem(nandc, true);
++ qcom_nandc_dev_to_mem(nandc, true);
+ memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len);
+
+ err_out:
+@@ -2774,20 +2774,20 @@ static int qcom_misc_cmd_type_exec(struc
+ nandc->buf_start = 0;
+ host->use_ecc = false;
+
+- clear_read_regs(nandc);
+- clear_bam_transaction(nandc);
++ qcom_clear_read_regs(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ nandc->regs->cmd = q_op.cmd_reg;
+ nandc->regs->exec = cpu_to_le32(1);
+
+- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
+ if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE))
+- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
+
+- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure in submitting misc descriptor\n");
+ goto err_out;
+@@ -2820,8 +2820,8 @@ static int qcom_param_page_type_exec(str
+ nandc->buf_count = 0;
+ nandc->buf_start = 0;
+ host->use_ecc = false;
+- clear_read_regs(nandc);
+- clear_bam_transaction(nandc);
++ qcom_clear_read_regs(nandc);
++ qcom_clear_bam_transaction(nandc);
+
+ nandc->regs->cmd = q_op.cmd_reg;
+ nandc->regs->addr0 = 0;
+@@ -2864,8 +2864,8 @@ static int qcom_param_page_type_exec(str
+ nandc_set_read_loc(chip, 0, 0, 0, len, 1);
+
+ if (!nandc->props->qpic_version2) {
+- write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
+- write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
++ qcom_write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
+ }
+
+ nandc->buf_count = len;
+@@ -2873,17 +2873,17 @@ static int qcom_param_page_type_exec(str
+
+ config_nand_single_cw_page_read(chip, false, 0);
+
+- read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
+- nandc->buf_count, 0);
++ qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
++ nandc->buf_count, 0);
+
+ /* restore CMD1 and VLD regs */
+ if (!nandc->props->qpic_version2) {
+- write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
+- write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
+- NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
++ qcom_write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
++ NAND_BAM_NEXT_SGL);
+ }
+
+- ret = submit_descs(nandc);
++ ret = qcom_submit_descs(nandc);
+ if (ret) {
+ dev_err(nandc->dev, "failure in submitting param page descriptor\n");
+ goto err_out;
+@@ -3067,7 +3067,7 @@ static int qcom_nandc_alloc(struct qcom_
+ * maximum codeword size
+ */
+ nandc->max_cwperpage = 1;
+- nandc->bam_txn = alloc_bam_transaction(nandc);
++ nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
+ if (!nandc->bam_txn) {
+ dev_err(nandc->dev,
+ "failed to allocate bam transaction\n");
--- /dev/null
+From fdf3ee5c6e5278dab4f60b998b47ed2d510bf80f Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Nov 2024 14:45:02 +0530
+Subject: [PATCH 3/4] mtd: nand: Add qpic_common API file
+
+Add qpic_common.c file which hold all the common
+qpic APIs which will be used by both qpic raw nand
+driver and qpic spi nand driver.
+
+---
+ drivers/mtd/nand/Makefile | 2 +-
+ drivers/mtd/nand/qpic_common.c | 759 ++++++++++++++++++
+ drivers/mtd/nand/raw/qcom_nandc.c | 1092 +-------------------------
+ include/linux/mtd/nand-qpic-common.h | 468 +++++++++++
+ 4 files changed, 1240 insertions(+), 1081 deletions(-)
+ create mode 100644 drivers/mtd/nand/qpic_common.c
+ create mode 100644 include/linux/mtd/nand-qpic-common.h
+
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -3,7 +3,7 @@
+ nandcore-objs := core.o bbt.o
+ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
+ obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
+-
++obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o
+ obj-y += onenand/
+ obj-y += raw/
+ obj-y += spi/
+--- /dev/null
++++ b/drivers/mtd/nand/qpic_common.c
+@@ -0,0 +1,759 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
++ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved
++ */
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/dma/qcom_adm.h>
++#include <linux/dma/qcom_bam_dma.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/nand-qpic-common.h>
++
++/**
++ * qcom_free_bam_transaction() - Frees the BAM transaction memory
++ * @nandc: qpic nand controller
++ *
++ * This function frees the bam transaction memory
++ */
++void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
++{
++ struct bam_transaction *bam_txn = nandc->bam_txn;
++
++ kfree(bam_txn);
++}
++EXPORT_SYMBOL(qcom_free_bam_transaction);
++
++/**
++ * qcom_alloc_bam_transaction() - allocate BAM transaction
++ * @nandc: qpic nand controller
++ *
++ * This function will allocate and initialize the BAM transaction structure
++ */
++struct bam_transaction *
++qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
++{
++ struct bam_transaction *bam_txn;
++ size_t bam_txn_size;
++ unsigned int num_cw = nandc->max_cwperpage;
++ void *bam_txn_buf;
++
++ bam_txn_size =
++ sizeof(*bam_txn) + num_cw *
++ ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
++ (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
++ (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
++
++ bam_txn_buf = kzalloc(bam_txn_size, GFP_KERNEL);
++ if (!bam_txn_buf)
++ return NULL;
++
++ bam_txn = bam_txn_buf;
++ bam_txn_buf += sizeof(*bam_txn);
++
++ bam_txn->bam_ce = bam_txn_buf;
++ bam_txn_buf +=
++ sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
++
++ bam_txn->cmd_sgl = bam_txn_buf;
++ bam_txn_buf +=
++ sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
++
++ bam_txn->data_sgl = bam_txn_buf;
++
++ init_completion(&bam_txn->txn_done);
++
++ return bam_txn;
++}
++EXPORT_SYMBOL(qcom_alloc_bam_transaction);
++
++/**
++ * qcom_clear_bam_transaction() - Clears the BAM transaction
++ * @nandc: qpic nand controller
++ *
++ * This function will clear the BAM transaction indexes.
++ */
++void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
++{
++ struct bam_transaction *bam_txn = nandc->bam_txn;
++
++ if (!nandc->props->supports_bam)
++ return;
++
++ memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
++ bam_txn->last_data_desc = NULL;
++
++ sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
++ QPIC_PER_CW_CMD_SGL);
++ sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
++ QPIC_PER_CW_DATA_SGL);
++
++ reinit_completion(&bam_txn->txn_done);
++}
++EXPORT_SYMBOL(qcom_clear_bam_transaction);
++
++/**
++ * qcom_qpic_bam_dma_done() - Callback for DMA descriptor completion
++ * @data: data pointer
++ *
++ * This function is a callback for DMA descriptor completion
++ */
++void qcom_qpic_bam_dma_done(void *data)
++{
++ struct bam_transaction *bam_txn = data;
++
++ complete(&bam_txn->txn_done);
++}
++EXPORT_SYMBOL(qcom_qpic_bam_dma_done);
++
++/**
++ * qcom_nandc_dev_to_mem() - Check for dma sync for cpu or device
++ * @nandc: qpic nand controller
++ * @is_cpu: cpu or Device
++ *
++ * This function will check for dma sync for cpu or device
++ */
++inline void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
++{
++ if (!nandc->props->supports_bam)
++ return;
++
++ if (is_cpu)
++ dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
++ MAX_REG_RD *
++ sizeof(*nandc->reg_read_buf),
++ DMA_FROM_DEVICE);
++ else
++ dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
++ MAX_REG_RD *
++ sizeof(*nandc->reg_read_buf),
++ DMA_FROM_DEVICE);
++}
++EXPORT_SYMBOL(qcom_nandc_dev_to_mem);
++
++/**
++ * qcom_prepare_bam_async_desc() - Prepare DMA descriptor
++ * @nandc: qpic nand controller
++ * @chan: dma channel
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function maps the scatter gather list for DMA transfer and forms the
++ * DMA descriptor for BAM.This descriptor will be added in the NAND DMA
++ * descriptor queue which will be submitted to DMA engine.
++ */
++int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
++ struct dma_chan *chan, unsigned long flags)
++{
++ struct desc_info *desc;
++ struct scatterlist *sgl;
++ unsigned int sgl_cnt;
++ int ret;
++ struct bam_transaction *bam_txn = nandc->bam_txn;
++ enum dma_transfer_direction dir_eng;
++ struct dma_async_tx_descriptor *dma_desc;
++
++ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
++ if (!desc)
++ return -ENOMEM;
++
++ if (chan == nandc->cmd_chan) {
++ sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
++ sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
++ bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
++ dir_eng = DMA_MEM_TO_DEV;
++ desc->dir = DMA_TO_DEVICE;
++ } else if (chan == nandc->tx_chan) {
++ sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
++ sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
++ bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
++ dir_eng = DMA_MEM_TO_DEV;
++ desc->dir = DMA_TO_DEVICE;
++ } else {
++ sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
++ sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
++ bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
++ dir_eng = DMA_DEV_TO_MEM;
++ desc->dir = DMA_FROM_DEVICE;
++ }
++
++ sg_mark_end(sgl + sgl_cnt - 1);
++ ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
++ if (ret == 0) {
++ dev_err(nandc->dev, "failure in mapping desc\n");
++ kfree(desc);
++ return -ENOMEM;
++ }
++
++ desc->sgl_cnt = sgl_cnt;
++ desc->bam_sgl = sgl;
++
++ dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
++ flags);
++
++ if (!dma_desc) {
++ dev_err(nandc->dev, "failure in prep desc\n");
++ dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
++ kfree(desc);
++ return -EINVAL;
++ }
++
++ desc->dma_desc = dma_desc;
++
++ /* update last data/command descriptor */
++ if (chan == nandc->cmd_chan)
++ bam_txn->last_cmd_desc = dma_desc;
++ else
++ bam_txn->last_data_desc = dma_desc;
++
++ list_add_tail(&desc->node, &nandc->desc_list);
++
++ return 0;
++}
++EXPORT_SYMBOL(qcom_prepare_bam_async_desc);
++
++/**
++ * qcom_prep_bam_dma_desc_cmd() - Prepares the command descriptor for BAM DMA
++ * @nandc: qpic nand controller
++ * @read: read or write type
++ * @reg_off: offset within the controller's data buffer
++ * @vaddr: virtual address of the buffer we want to write to
++ * @size: DMA transaction size in bytes
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares the command descriptor for BAM DMA
++ * which will be used for NAND register reads and writes.
++ */
++int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
++ int reg_off, const void *vaddr,
++ int size, unsigned int flags)
++{
++ int bam_ce_size;
++ int i, ret;
++ struct bam_cmd_element *bam_ce_buffer;
++ struct bam_transaction *bam_txn = nandc->bam_txn;
++
++ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
++
++ /* fill the command desc */
++ for (i = 0; i < size; i++) {
++ if (read)
++ bam_prep_ce(&bam_ce_buffer[i],
++ nandc_reg_phys(nandc, reg_off + 4 * i),
++ BAM_READ_COMMAND,
++ reg_buf_dma_addr(nandc,
++ (__le32 *)vaddr + i));
++ else
++ bam_prep_ce_le32(&bam_ce_buffer[i],
++ nandc_reg_phys(nandc, reg_off + 4 * i),
++ BAM_WRITE_COMMAND,
++ *((__le32 *)vaddr + i));
++ }
++
++ bam_txn->bam_ce_pos += size;
++
++ /* use the separate sgl after this command */
++ if (flags & NAND_BAM_NEXT_SGL) {
++ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
++ bam_ce_size = (bam_txn->bam_ce_pos -
++ bam_txn->bam_ce_start) *
++ sizeof(struct bam_cmd_element);
++ sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
++ bam_ce_buffer, bam_ce_size);
++ bam_txn->cmd_sgl_pos++;
++ bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
++
++ if (flags & NAND_BAM_NWD) {
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
++ DMA_PREP_FENCE | DMA_PREP_CMD);
++ if (ret)
++ return ret;
++ }
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(qcom_prep_bam_dma_desc_cmd);
++
++/**
++ * qcom_prep_bam_dma_desc_data() - Prepares the data descriptor for BAM DMA
++ * @nandc: qpic nand controller
++ * @read: read or write type
++ * @vaddr: virtual address of the buffer we want to write to
++ * @size: DMA transaction size in bytes
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares the data descriptor for BAM DMA which
++ * will be used for NAND data reads and writes.
++ */
++int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
++ const void *vaddr, int size, unsigned int flags)
++{
++ int ret;
++ struct bam_transaction *bam_txn = nandc->bam_txn;
++
++ if (read) {
++ sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
++ vaddr, size);
++ bam_txn->rx_sgl_pos++;
++ } else {
++ sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
++ vaddr, size);
++ bam_txn->tx_sgl_pos++;
++
++ /*
++ * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
++ * is not set, form the DMA descriptor
++ */
++ if (!(flags & NAND_BAM_NO_EOT)) {
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
++ DMA_PREP_INTERRUPT);
++ if (ret)
++ return ret;
++ }
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(qcom_prep_bam_dma_desc_data);
++
++/**
++ * qcom_prep_adm_dma_desc() - Prepare descriptor for adma
++ * @nandc: qpic nand controller
++ * @read: read or write type
++ * @reg_off: offset within the controller's data buffer
++ * @vaddr: virtual address of the buffer we want to write to
++ * @size: adm dma transaction size in bytes
++ * @flow_control: flow controller
++ *
++ * This function will prepare descriptor for adma
++ */
++int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
++ int reg_off, const void *vaddr, int size,
++ bool flow_control)
++{
++ struct qcom_adm_peripheral_config periph_conf = {};
++ struct dma_async_tx_descriptor *dma_desc;
++ struct dma_slave_config slave_conf = {0};
++ enum dma_transfer_direction dir_eng;
++ struct desc_info *desc;
++ struct scatterlist *sgl;
++ int ret;
++
++ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
++ if (!desc)
++ return -ENOMEM;
++
++ sgl = &desc->adm_sgl;
++
++ sg_init_one(sgl, vaddr, size);
++
++ if (read) {
++ dir_eng = DMA_DEV_TO_MEM;
++ desc->dir = DMA_FROM_DEVICE;
++ } else {
++ dir_eng = DMA_MEM_TO_DEV;
++ desc->dir = DMA_TO_DEVICE;
++ }
++
++ ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
++ if (!ret) {
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ slave_conf.device_fc = flow_control;
++ if (read) {
++ slave_conf.src_maxburst = 16;
++ slave_conf.src_addr = nandc->base_dma + reg_off;
++ if (nandc->data_crci) {
++ periph_conf.crci = nandc->data_crci;
++ slave_conf.peripheral_config = &periph_conf;
++ slave_conf.peripheral_size = sizeof(periph_conf);
++ }
++ } else {
++ slave_conf.dst_maxburst = 16;
++ slave_conf.dst_addr = nandc->base_dma + reg_off;
++ if (nandc->cmd_crci) {
++ periph_conf.crci = nandc->cmd_crci;
++ slave_conf.peripheral_config = &periph_conf;
++ slave_conf.peripheral_size = sizeof(periph_conf);
++ }
++ }
++
++ ret = dmaengine_slave_config(nandc->chan, &slave_conf);
++ if (ret) {
++ dev_err(nandc->dev, "failed to configure dma channel\n");
++ goto err;
++ }
++
++ dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
++ if (!dma_desc) {
++ dev_err(nandc->dev, "failed to prepare desc\n");
++ ret = -EINVAL;
++ goto err;
++ }
++
++ desc->dma_desc = dma_desc;
++
++ list_add_tail(&desc->node, &nandc->desc_list);
++
++ return 0;
++err:
++ kfree(desc);
++
++ return ret;
++}
++EXPORT_SYMBOL(qcom_prep_adm_dma_desc);
++
++/**
++ * qcom_read_reg_dma() - read a given number of registers to the reg_read_buf pointer
++ * @nandc: qpic nand controller
++ * @first: offset of the first register in the contiguous block
++ * @num_regs: number of registers to read
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares a descriptor to read a given number of
++ * contiguous registers to the reg_read_buf pointer.
++ */
++int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
++ int num_regs, unsigned int flags)
++{
++ bool flow_control = false;
++ void *vaddr;
++
++ vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
++ nandc->reg_read_pos += num_regs;
++
++ if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
++ first = dev_cmd_reg_addr(nandc, first);
++
++ if (nandc->props->supports_bam)
++ return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
++ num_regs, flags);
++
++ if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
++ flow_control = true;
++
++ return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
++ num_regs * sizeof(u32), flow_control);
++}
++EXPORT_SYMBOL(qcom_read_reg_dma);
++
++/**
++ * qcom_write_reg_dma() - write a given number of registers
++ * @nandc: qpic nand controller
++ * @vaddr: contiguous memory from where register value will
++ * be written
++ * @first: offset of the first register in the contiguous block
++ * @num_regs: number of registers to write
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares a descriptor to write a given number of
++ * contiguous registers
++ */
++int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
++ int first, int num_regs, unsigned int flags)
++{
++ bool flow_control = false;
++
++ if (first == NAND_EXEC_CMD)
++ flags |= NAND_BAM_NWD;
++
++ if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
++ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
++
++ if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
++ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
++
++ if (nandc->props->supports_bam)
++ return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
++ num_regs, flags);
++
++ if (first == NAND_FLASH_CMD)
++ flow_control = true;
++
++ return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
++ num_regs * sizeof(u32), flow_control);
++}
++EXPORT_SYMBOL(qcom_write_reg_dma);
++
++/**
++ * qcom_read_data_dma() - transfer data
++ * @nandc: qpic nand controller
++ * @reg_off: offset within the controller's data buffer
++ * @vaddr: virtual address of the buffer we want to write to
++ * @size: DMA transaction size in bytes
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares a DMA descriptor to transfer data from the
++ * controller's internal buffer to the buffer 'vaddr'
++ */
++int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
++ const u8 *vaddr, int size, unsigned int flags)
++{
++ if (nandc->props->supports_bam)
++ return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
++
++ return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
++}
++EXPORT_SYMBOL(qcom_read_data_dma);
++
++/**
++ * qcom_write_data_dma() - transfer data
++ * @nandc: qpic nand controller
++ * @reg_off: offset within the controller's data buffer
++ * @vaddr: virtual address of the buffer we want to read from
++ * @size: DMA transaction size in bytes
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares a DMA descriptor to transfer data from
++ * 'vaddr' to the controller's internal buffer
++ */
++int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
++ const u8 *vaddr, int size, unsigned int flags)
++{
++ if (nandc->props->supports_bam)
++ return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
++
++ return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
++}
++EXPORT_SYMBOL(qcom_write_data_dma);
++
++/**
++ * qcom_submit_descs() - submit dma descriptor
++ * @nandc: qpic nand controller
++ *
++ * This function will submit all the prepared dma descriptor
++ * cmd or data descriptor
++ */
++int qcom_submit_descs(struct qcom_nand_controller *nandc)
++{
++ struct desc_info *desc, *n;
++ dma_cookie_t cookie = 0;
++ struct bam_transaction *bam_txn = nandc->bam_txn;
++ int ret = 0;
++
++ if (nandc->props->supports_bam) {
++ if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
++ if (ret)
++ goto err_unmap_free_desc;
++ }
++
++ if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
++ DMA_PREP_INTERRUPT);
++ if (ret)
++ goto err_unmap_free_desc;
++ }
++
++ if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
++ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
++ DMA_PREP_CMD);
++ if (ret)
++ goto err_unmap_free_desc;
++ }
++ }
++
++ list_for_each_entry(desc, &nandc->desc_list, node)
++ cookie = dmaengine_submit(desc->dma_desc);
++
++ if (nandc->props->supports_bam) {
++ bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
++ bam_txn->last_cmd_desc->callback_param = bam_txn;
++
++ dma_async_issue_pending(nandc->tx_chan);
++ dma_async_issue_pending(nandc->rx_chan);
++ dma_async_issue_pending(nandc->cmd_chan);
++
++ if (!wait_for_completion_timeout(&bam_txn->txn_done,
++ QPIC_NAND_COMPLETION_TIMEOUT))
++ ret = -ETIMEDOUT;
++ } else {
++ if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
++ ret = -ETIMEDOUT;
++ }
++
++err_unmap_free_desc:
++ /*
++ * Unmap the dma sg_list and free the desc allocated by both
++ * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
++ */
++ list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
++ list_del(&desc->node);
++
++ if (nandc->props->supports_bam)
++ dma_unmap_sg(nandc->dev, desc->bam_sgl,
++ desc->sgl_cnt, desc->dir);
++ else
++ dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
++ desc->dir);
++
++ kfree(desc);
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL(qcom_submit_descs);
++
++/**
++ * qcom_clear_read_regs() - reset the read register buffer
++ * @nandc: qpic nand controller
++ *
++ * This function reset the register read buffer for next NAND operation
++ */
++void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
++{
++ nandc->reg_read_pos = 0;
++ qcom_nandc_dev_to_mem(nandc, false);
++}
++EXPORT_SYMBOL(qcom_clear_read_regs);
++
++/**
++ * qcom_nandc_unalloc() - unallocate qpic nand controller
++ * @nandc: qpic nand controller
++ *
++ * This function will unallocate memory alloacted for qpic nand controller
++ */
++void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
++{
++ if (nandc->props->supports_bam) {
++ if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
++ dma_unmap_single(nandc->dev, nandc->reg_read_dma,
++ MAX_REG_RD *
++ sizeof(*nandc->reg_read_buf),
++ DMA_FROM_DEVICE);
++
++ if (nandc->tx_chan)
++ dma_release_channel(nandc->tx_chan);
++
++ if (nandc->rx_chan)
++ dma_release_channel(nandc->rx_chan);
++
++ if (nandc->cmd_chan)
++ dma_release_channel(nandc->cmd_chan);
++ } else {
++ if (nandc->chan)
++ dma_release_channel(nandc->chan);
++ }
++}
++EXPORT_SYMBOL(qcom_nandc_unalloc);
++
++/**
++ * qcom_nandc_alloc() - Allocate qpic nand controller
++ * @nandc: qpic nand controller
++ *
++ * This function will allocate memory for qpic nand controller
++ */
++int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
++{
++ int ret;
++
++ ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
++ if (ret) {
++ dev_err(nandc->dev, "failed to set DMA mask\n");
++ return ret;
++ }
++
++ /*
++ * we use the internal buffer for reading ONFI params, reading small
++ * data like ID and status, and preforming read-copy-write operations
++ * when writing to a codeword partially. 532 is the maximum possible
++ * size of a codeword for our nand controller
++ */
++ nandc->buf_size = 532;
++
++ nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
++ if (!nandc->data_buffer)
++ return -ENOMEM;
++
++ nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
++ if (!nandc->regs)
++ return -ENOMEM;
++
++ nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
++ sizeof(*nandc->reg_read_buf),
++ GFP_KERNEL);
++ if (!nandc->reg_read_buf)
++ return -ENOMEM;
++
++ if (nandc->props->supports_bam) {
++ nandc->reg_read_dma =
++ dma_map_single(nandc->dev, nandc->reg_read_buf,
++ MAX_REG_RD *
++ sizeof(*nandc->reg_read_buf),
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
++ dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
++ return -EIO;
++ }
++
++ nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
++ if (IS_ERR(nandc->tx_chan)) {
++ ret = PTR_ERR(nandc->tx_chan);
++ nandc->tx_chan = NULL;
++ dev_err_probe(nandc->dev, ret,
++ "tx DMA channel request failed\n");
++ goto unalloc;
++ }
++
++ nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
++ if (IS_ERR(nandc->rx_chan)) {
++ ret = PTR_ERR(nandc->rx_chan);
++ nandc->rx_chan = NULL;
++ dev_err_probe(nandc->dev, ret,
++ "rx DMA channel request failed\n");
++ goto unalloc;
++ }
++
++ nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
++ if (IS_ERR(nandc->cmd_chan)) {
++ ret = PTR_ERR(nandc->cmd_chan);
++ nandc->cmd_chan = NULL;
++ dev_err_probe(nandc->dev, ret,
++ "cmd DMA channel request failed\n");
++ goto unalloc;
++ }
++
++ /*
++ * Initially allocate BAM transaction to read ONFI param page.
++ * After detecting all the devices, this BAM transaction will
++ * be freed and the next BAM transaction will be allocated with
++ * maximum codeword size
++ */
++ nandc->max_cwperpage = 1;
++ nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
++ if (!nandc->bam_txn) {
++ dev_err(nandc->dev,
++ "failed to allocate bam transaction\n");
++ ret = -ENOMEM;
++ goto unalloc;
++ }
++ } else {
++ nandc->chan = dma_request_chan(nandc->dev, "rxtx");
++ if (IS_ERR(nandc->chan)) {
++ ret = PTR_ERR(nandc->chan);
++ nandc->chan = NULL;
++ dev_err_probe(nandc->dev, ret,
++ "rxtx DMA channel request failed\n");
++ return ret;
++ }
++ }
++
++ INIT_LIST_HEAD(&nandc->desc_list);
++ INIT_LIST_HEAD(&nandc->host_list);
++
++ return 0;
++unalloc:
++ qcom_nandc_unalloc(nandc);
++ return ret;
++}
++EXPORT_SYMBOL(qcom_nandc_alloc);
++
++MODULE_DESCRIPTION("QPIC controller common api");
++MODULE_LICENSE("GPL");
+--- a/drivers/mtd/nand/raw/qcom_nandc.c
++++ b/drivers/mtd/nand/raw/qcom_nandc.c
+@@ -15,417 +15,7 @@
+ #include <linux/of.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+-
+-/* NANDc reg offsets */
+-#define NAND_FLASH_CMD 0x00
+-#define NAND_ADDR0 0x04
+-#define NAND_ADDR1 0x08
+-#define NAND_FLASH_CHIP_SELECT 0x0c
+-#define NAND_EXEC_CMD 0x10
+-#define NAND_FLASH_STATUS 0x14
+-#define NAND_BUFFER_STATUS 0x18
+-#define NAND_DEV0_CFG0 0x20
+-#define NAND_DEV0_CFG1 0x24
+-#define NAND_DEV0_ECC_CFG 0x28
+-#define NAND_AUTO_STATUS_EN 0x2c
+-#define NAND_DEV1_CFG0 0x30
+-#define NAND_DEV1_CFG1 0x34
+-#define NAND_READ_ID 0x40
+-#define NAND_READ_STATUS 0x44
+-#define NAND_DEV_CMD0 0xa0
+-#define NAND_DEV_CMD1 0xa4
+-#define NAND_DEV_CMD2 0xa8
+-#define NAND_DEV_CMD_VLD 0xac
+-#define SFLASHC_BURST_CFG 0xe0
+-#define NAND_ERASED_CW_DETECT_CFG 0xe8
+-#define NAND_ERASED_CW_DETECT_STATUS 0xec
+-#define NAND_EBI2_ECC_BUF_CFG 0xf0
+-#define FLASH_BUF_ACC 0x100
+-
+-#define NAND_CTRL 0xf00
+-#define NAND_VERSION 0xf08
+-#define NAND_READ_LOCATION_0 0xf20
+-#define NAND_READ_LOCATION_1 0xf24
+-#define NAND_READ_LOCATION_2 0xf28
+-#define NAND_READ_LOCATION_3 0xf2c
+-#define NAND_READ_LOCATION_LAST_CW_0 0xf40
+-#define NAND_READ_LOCATION_LAST_CW_1 0xf44
+-#define NAND_READ_LOCATION_LAST_CW_2 0xf48
+-#define NAND_READ_LOCATION_LAST_CW_3 0xf4c
+-
+-/* dummy register offsets, used by qcom_write_reg_dma */
+-#define NAND_DEV_CMD1_RESTORE 0xdead
+-#define NAND_DEV_CMD_VLD_RESTORE 0xbeef
+-
+-/* NAND_FLASH_CMD bits */
+-#define PAGE_ACC BIT(4)
+-#define LAST_PAGE BIT(5)
+-
+-/* NAND_FLASH_CHIP_SELECT bits */
+-#define NAND_DEV_SEL 0
+-#define DM_EN BIT(2)
+-
+-/* NAND_FLASH_STATUS bits */
+-#define FS_OP_ERR BIT(4)
+-#define FS_READY_BSY_N BIT(5)
+-#define FS_MPU_ERR BIT(8)
+-#define FS_DEVICE_STS_ERR BIT(16)
+-#define FS_DEVICE_WP BIT(23)
+-
+-/* NAND_BUFFER_STATUS bits */
+-#define BS_UNCORRECTABLE_BIT BIT(8)
+-#define BS_CORRECTABLE_ERR_MSK 0x1f
+-
+-/* NAND_DEVn_CFG0 bits */
+-#define DISABLE_STATUS_AFTER_WRITE 4
+-#define CW_PER_PAGE 6
+-#define UD_SIZE_BYTES 9
+-#define UD_SIZE_BYTES_MASK GENMASK(18, 9)
+-#define ECC_PARITY_SIZE_BYTES_RS 19
+-#define SPARE_SIZE_BYTES 23
+-#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
+-#define NUM_ADDR_CYCLES 27
+-#define STATUS_BFR_READ 30
+-#define SET_RD_MODE_AFTER_STATUS 31
+-
+-/* NAND_DEVn_CFG0 bits */
+-#define DEV0_CFG1_ECC_DISABLE 0
+-#define WIDE_FLASH 1
+-#define NAND_RECOVERY_CYCLES 2
+-#define CS_ACTIVE_BSY 5
+-#define BAD_BLOCK_BYTE_NUM 6
+-#define BAD_BLOCK_IN_SPARE_AREA 16
+-#define WR_RD_BSY_GAP 17
+-#define ENABLE_BCH_ECC 27
+-
+-/* NAND_DEV0_ECC_CFG bits */
+-#define ECC_CFG_ECC_DISABLE 0
+-#define ECC_SW_RESET 1
+-#define ECC_MODE 4
+-#define ECC_PARITY_SIZE_BYTES_BCH 8
+-#define ECC_NUM_DATA_BYTES 16
+-#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
+-#define ECC_FORCE_CLK_OPEN 30
+-
+-/* NAND_DEV_CMD1 bits */
+-#define READ_ADDR 0
+-
+-/* NAND_DEV_CMD_VLD bits */
+-#define READ_START_VLD BIT(0)
+-#define READ_STOP_VLD BIT(1)
+-#define WRITE_START_VLD BIT(2)
+-#define ERASE_START_VLD BIT(3)
+-#define SEQ_READ_START_VLD BIT(4)
+-
+-/* NAND_EBI2_ECC_BUF_CFG bits */
+-#define NUM_STEPS 0
+-
+-/* NAND_ERASED_CW_DETECT_CFG bits */
+-#define ERASED_CW_ECC_MASK 1
+-#define AUTO_DETECT_RES 0
+-#define MASK_ECC BIT(ERASED_CW_ECC_MASK)
+-#define RESET_ERASED_DET BIT(AUTO_DETECT_RES)
+-#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES)
+-#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC)
+-#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC)
+-
+-/* NAND_ERASED_CW_DETECT_STATUS bits */
+-#define PAGE_ALL_ERASED BIT(7)
+-#define CODEWORD_ALL_ERASED BIT(6)
+-#define PAGE_ERASED BIT(5)
+-#define CODEWORD_ERASED BIT(4)
+-#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED)
+-#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
+-
+-/* NAND_READ_LOCATION_n bits */
+-#define READ_LOCATION_OFFSET 0
+-#define READ_LOCATION_SIZE 16
+-#define READ_LOCATION_LAST 31
+-
+-/* Version Mask */
+-#define NAND_VERSION_MAJOR_MASK 0xf0000000
+-#define NAND_VERSION_MAJOR_SHIFT 28
+-#define NAND_VERSION_MINOR_MASK 0x0fff0000
+-#define NAND_VERSION_MINOR_SHIFT 16
+-
+-/* NAND OP_CMDs */
+-#define OP_PAGE_READ 0x2
+-#define OP_PAGE_READ_WITH_ECC 0x3
+-#define OP_PAGE_READ_WITH_ECC_SPARE 0x4
+-#define OP_PAGE_READ_ONFI_READ 0x5
+-#define OP_PROGRAM_PAGE 0x6
+-#define OP_PAGE_PROGRAM_WITH_ECC 0x7
+-#define OP_PROGRAM_PAGE_SPARE 0x9
+-#define OP_BLOCK_ERASE 0xa
+-#define OP_CHECK_STATUS 0xc
+-#define OP_FETCH_ID 0xb
+-#define OP_RESET_DEVICE 0xd
+-
+-/* Default Value for NAND_DEV_CMD_VLD */
+-#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
+- ERASE_START_VLD | SEQ_READ_START_VLD)
+-
+-/* NAND_CTRL bits */
+-#define BAM_MODE_EN BIT(0)
+-
+-/*
+- * the NAND controller performs reads/writes with ECC in 516 byte chunks.
+- * the driver calls the chunks 'step' or 'codeword' interchangeably
+- */
+-#define NANDC_STEP_SIZE 512
+-
+-/*
+- * the largest page size we support is 8K, this will have 16 steps/codewords
+- * of 512 bytes each
+- */
+-#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE)
+-
+-/* we read at most 3 registers per codeword scan */
+-#define MAX_REG_RD (3 * MAX_NUM_STEPS)
+-
+-/* ECC modes supported by the controller */
+-#define ECC_NONE BIT(0)
+-#define ECC_RS_4BIT BIT(1)
+-#define ECC_BCH_4BIT BIT(2)
+-#define ECC_BCH_8BIT BIT(3)
+-
+-/*
+- * Returns the actual register address for all NAND_DEV_ registers
+- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
+- */
+-#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
+-
+-/* Returns the NAND register physical address */
+-#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
+-
+-/* Returns the dma address for reg read buffer */
+-#define reg_buf_dma_addr(chip, vaddr) \
+- ((chip)->reg_read_dma + \
+- ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
+-
+-#define QPIC_PER_CW_CMD_ELEMENTS 32
+-#define QPIC_PER_CW_CMD_SGL 32
+-#define QPIC_PER_CW_DATA_SGL 8
+-
+-#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
+-
+-/*
+- * Flags used in DMA descriptor preparation helper functions
+- * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
+- */
+-/* Don't set the EOT in current tx BAM sgl */
+-#define NAND_BAM_NO_EOT BIT(0)
+-/* Set the NWD flag in current BAM sgl */
+-#define NAND_BAM_NWD BIT(1)
+-/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
+-#define NAND_BAM_NEXT_SGL BIT(2)
+-/*
+- * Erased codeword status is being used two times in single transfer so this
+- * flag will determine the current value of erased codeword status register
+- */
+-#define NAND_ERASED_CW_SET BIT(4)
+-
+-#define MAX_ADDRESS_CYCLE 5
+-
+-/*
+- * This data type corresponds to the BAM transaction which will be used for all
+- * NAND transfers.
+- * @bam_ce - the array of BAM command elements
+- * @cmd_sgl - sgl for NAND BAM command pipe
+- * @data_sgl - sgl for NAND BAM consumer/producer pipe
+- * @last_data_desc - last DMA desc in data channel (tx/rx).
+- * @last_cmd_desc - last DMA desc in command channel.
+- * @txn_done - completion for NAND transfer.
+- * @bam_ce_pos - the index in bam_ce which is available for next sgl
+- * @bam_ce_start - the index in bam_ce which marks the start position ce
+- * for current sgl. It will be used for size calculation
+- * for current sgl
+- * @cmd_sgl_pos - current index in command sgl.
+- * @cmd_sgl_start - start index in command sgl.
+- * @tx_sgl_pos - current index in data sgl for tx.
+- * @tx_sgl_start - start index in data sgl for tx.
+- * @rx_sgl_pos - current index in data sgl for rx.
+- * @rx_sgl_start - start index in data sgl for rx.
+- */
+-struct bam_transaction {
+- struct bam_cmd_element *bam_ce;
+- struct scatterlist *cmd_sgl;
+- struct scatterlist *data_sgl;
+- struct dma_async_tx_descriptor *last_data_desc;
+- struct dma_async_tx_descriptor *last_cmd_desc;
+- struct completion txn_done;
+- u32 bam_ce_pos;
+- u32 bam_ce_start;
+- u32 cmd_sgl_pos;
+- u32 cmd_sgl_start;
+- u32 tx_sgl_pos;
+- u32 tx_sgl_start;
+- u32 rx_sgl_pos;
+- u32 rx_sgl_start;
+-};
+-
+-/*
+- * This data type corresponds to the nand dma descriptor
+- * @dma_desc - low level DMA engine descriptor
+- * @list - list for desc_info
+- *
+- * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
+- * ADM
+- * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
+- * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
+- * @dir - DMA transfer direction
+- */
+-struct desc_info {
+- struct dma_async_tx_descriptor *dma_desc;
+- struct list_head node;
+-
+- union {
+- struct scatterlist adm_sgl;
+- struct {
+- struct scatterlist *bam_sgl;
+- int sgl_cnt;
+- };
+- };
+- enum dma_data_direction dir;
+-};
+-
+-/*
+- * holds the current register values that we want to write. acts as a contiguous
+- * chunk of memory which we use to write the controller registers through DMA.
+- */
+-struct nandc_regs {
+- __le32 cmd;
+- __le32 addr0;
+- __le32 addr1;
+- __le32 chip_sel;
+- __le32 exec;
+-
+- __le32 cfg0;
+- __le32 cfg1;
+- __le32 ecc_bch_cfg;
+-
+- __le32 clrflashstatus;
+- __le32 clrreadstatus;
+-
+- __le32 cmd1;
+- __le32 vld;
+-
+- __le32 orig_cmd1;
+- __le32 orig_vld;
+-
+- __le32 ecc_buf_cfg;
+- __le32 read_location0;
+- __le32 read_location1;
+- __le32 read_location2;
+- __le32 read_location3;
+- __le32 read_location_last0;
+- __le32 read_location_last1;
+- __le32 read_location_last2;
+- __le32 read_location_last3;
+-
+- __le32 erased_cw_detect_cfg_clr;
+- __le32 erased_cw_detect_cfg_set;
+-};
+-
+-/*
+- * NAND controller data struct
+- *
+- * @dev: parent device
+- *
+- * @base: MMIO base
+- *
+- * @core_clk: controller clock
+- * @aon_clk: another controller clock
+- *
+- * @regs: a contiguous chunk of memory for DMA register
+- * writes. contains the register values to be
+- * written to controller
+- *
+- * @props: properties of current NAND controller,
+- * initialized via DT match data
+- *
+- * @controller: base controller structure
+- * @host_list: list containing all the chips attached to the
+- * controller
+- *
+- * @chan: dma channel
+- * @cmd_crci: ADM DMA CRCI for command flow control
+- * @data_crci: ADM DMA CRCI for data flow control
+- *
+- * @desc_list: DMA descriptor list (list of desc_infos)
+- *
+- * @data_buffer: our local DMA buffer for page read/writes,
+- * used when we can't use the buffer provided
+- * by upper layers directly
+- * @reg_read_buf: local buffer for reading back registers via DMA
+- *
+- * @base_phys: physical base address of controller registers
+- * @base_dma: dma base address of controller registers
+- * @reg_read_dma: contains dma address for register read buffer
+- *
+- * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
+- * functions
+- * @max_cwperpage: maximum QPIC codewords required. calculated
+- * from all connected NAND devices pagesize
+- *
+- * @reg_read_pos: marker for data read in reg_read_buf
+- *
+- * @cmd1/vld: some fixed controller register values
+- *
+- * @exec_opwrite: flag to select correct number of code word
+- * while reading status
+- */
+-struct qcom_nand_controller {
+- struct device *dev;
+-
+- void __iomem *base;
+-
+- struct clk *core_clk;
+- struct clk *aon_clk;
+-
+- struct nandc_regs *regs;
+- struct bam_transaction *bam_txn;
+-
+- const struct qcom_nandc_props *props;
+-
+- struct nand_controller controller;
+- struct list_head host_list;
+-
+- union {
+- /* will be used only by QPIC for BAM DMA */
+- struct {
+- struct dma_chan *tx_chan;
+- struct dma_chan *rx_chan;
+- struct dma_chan *cmd_chan;
+- };
+-
+- /* will be used only by EBI2 for ADM DMA */
+- struct {
+- struct dma_chan *chan;
+- unsigned int cmd_crci;
+- unsigned int data_crci;
+- };
+- };
+-
+- struct list_head desc_list;
+-
+- u8 *data_buffer;
+- __le32 *reg_read_buf;
+-
+- phys_addr_t base_phys;
+- dma_addr_t base_dma;
+- dma_addr_t reg_read_dma;
+-
+- int buf_size;
+- int buf_count;
+- int buf_start;
+- unsigned int max_cwperpage;
+-
+- int reg_read_pos;
+-
+- u32 cmd1, vld;
+- bool exec_opwrite;
+-};
++#include <linux/mtd/nand-qpic-common.h>
+
+ /*
+ * NAND special boot partitions
+@@ -530,97 +120,6 @@ struct qcom_nand_host {
+ bool bch_enabled;
+ };
+
+-/*
+- * This data type corresponds to the NAND controller properties which varies
+- * among different NAND controllers.
+- * @ecc_modes - ecc mode for NAND
+- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
+- * @supports_bam - whether NAND controller is using Bus Access Manager (BAM)
+- * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
+- * @qpic_version2 - flag to indicate QPIC IP version 2
+- * @use_codeword_fixup - whether NAND has different layout for boot partitions
+- */
+-struct qcom_nandc_props {
+- u32 ecc_modes;
+- u32 dev_cmd_reg_start;
+- bool supports_bam;
+- bool nandc_part_of_qpic;
+- bool qpic_version2;
+- bool use_codeword_fixup;
+-};
+-
+-/* Frees the BAM transaction memory */
+-static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
+-{
+- struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+- devm_kfree(nandc->dev, bam_txn);
+-}
+-
+-/* Allocates and Initializes the BAM transaction */
+-static struct bam_transaction *
+-qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
+-{
+- struct bam_transaction *bam_txn;
+- size_t bam_txn_size;
+- unsigned int num_cw = nandc->max_cwperpage;
+- void *bam_txn_buf;
+-
+- bam_txn_size =
+- sizeof(*bam_txn) + num_cw *
+- ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
+- (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
+- (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
+-
+- bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
+- if (!bam_txn_buf)
+- return NULL;
+-
+- bam_txn = bam_txn_buf;
+- bam_txn_buf += sizeof(*bam_txn);
+-
+- bam_txn->bam_ce = bam_txn_buf;
+- bam_txn_buf +=
+- sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
+-
+- bam_txn->cmd_sgl = bam_txn_buf;
+- bam_txn_buf +=
+- sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
+-
+- bam_txn->data_sgl = bam_txn_buf;
+-
+- init_completion(&bam_txn->txn_done);
+-
+- return bam_txn;
+-}
+-
+-/* Clears the BAM transaction indexes */
+-static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
+-{
+- struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+- if (!nandc->props->supports_bam)
+- return;
+-
+- memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
+- bam_txn->last_data_desc = NULL;
+-
+- sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
+- QPIC_PER_CW_CMD_SGL);
+- sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
+- QPIC_PER_CW_DATA_SGL);
+-
+- reinit_completion(&bam_txn->txn_done);
+-}
+-
+-/* Callback for DMA descriptor completion */
+-static void qcom_qpic_bam_dma_done(void *data)
+-{
+- struct bam_transaction *bam_txn = data;
+-
+- complete(&bam_txn->txn_done);
+-}
+-
+ static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
+ {
+ return container_of(chip, struct qcom_nand_host, chip);
+@@ -629,8 +128,8 @@ static struct qcom_nand_host *to_qcom_na
+ static struct qcom_nand_controller *
+ get_qcom_nand_controller(struct nand_chip *chip)
+ {
+- return container_of(chip->controller, struct qcom_nand_controller,
+- controller);
++ return (struct qcom_nand_controller *)
++ ((u8 *)chip->controller - sizeof(struct qcom_nand_controller));
+ }
+
+ static u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
+@@ -644,23 +143,6 @@ static void nandc_write(struct qcom_nand
+ iowrite32(val, nandc->base + offset);
+ }
+
+-static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
+-{
+- if (!nandc->props->supports_bam)
+- return;
+-
+- if (is_cpu)
+- dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
+- MAX_REG_RD *
+- sizeof(*nandc->reg_read_buf),
+- DMA_FROM_DEVICE);
+- else
+- dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
+- MAX_REG_RD *
+- sizeof(*nandc->reg_read_buf),
+- DMA_FROM_DEVICE);
+-}
+-
+ /* Helper to check whether this is the last CW or not */
+ static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
+ {
+@@ -820,356 +302,6 @@ static void update_rw_regs(struct qcom_n
+ }
+
+ /*
+- * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
+- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
+- * which will be submitted to DMA engine.
+- */
+-static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
+- struct dma_chan *chan,
+- unsigned long flags)
+-{
+- struct desc_info *desc;
+- struct scatterlist *sgl;
+- unsigned int sgl_cnt;
+- int ret;
+- struct bam_transaction *bam_txn = nandc->bam_txn;
+- enum dma_transfer_direction dir_eng;
+- struct dma_async_tx_descriptor *dma_desc;
+-
+- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+- if (!desc)
+- return -ENOMEM;
+-
+- if (chan == nandc->cmd_chan) {
+- sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
+- sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
+- bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
+- dir_eng = DMA_MEM_TO_DEV;
+- desc->dir = DMA_TO_DEVICE;
+- } else if (chan == nandc->tx_chan) {
+- sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
+- sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
+- bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
+- dir_eng = DMA_MEM_TO_DEV;
+- desc->dir = DMA_TO_DEVICE;
+- } else {
+- sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
+- sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
+- bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
+- dir_eng = DMA_DEV_TO_MEM;
+- desc->dir = DMA_FROM_DEVICE;
+- }
+-
+- sg_mark_end(sgl + sgl_cnt - 1);
+- ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+- if (ret == 0) {
+- dev_err(nandc->dev, "failure in mapping desc\n");
+- kfree(desc);
+- return -ENOMEM;
+- }
+-
+- desc->sgl_cnt = sgl_cnt;
+- desc->bam_sgl = sgl;
+-
+- dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
+- flags);
+-
+- if (!dma_desc) {
+- dev_err(nandc->dev, "failure in prep desc\n");
+- dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+- kfree(desc);
+- return -EINVAL;
+- }
+-
+- desc->dma_desc = dma_desc;
+-
+- /* update last data/command descriptor */
+- if (chan == nandc->cmd_chan)
+- bam_txn->last_cmd_desc = dma_desc;
+- else
+- bam_txn->last_data_desc = dma_desc;
+-
+- list_add_tail(&desc->node, &nandc->desc_list);
+-
+- return 0;
+-}
+-
+-/*
+- * Prepares the command descriptor for BAM DMA which will be used for NAND
+- * register reads and writes. The command descriptor requires the command
+- * to be formed in command element type so this function uses the command
+- * element from bam transaction ce array and fills the same with required
+- * data. A single SGL can contain multiple command elements so
+- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
+- * after the current command element.
+- */
+-static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
+- int reg_off, const void *vaddr,
+- int size, unsigned int flags)
+-{
+- int bam_ce_size;
+- int i, ret;
+- struct bam_cmd_element *bam_ce_buffer;
+- struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+- bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
+-
+- /* fill the command desc */
+- for (i = 0; i < size; i++) {
+- if (read)
+- bam_prep_ce(&bam_ce_buffer[i],
+- nandc_reg_phys(nandc, reg_off + 4 * i),
+- BAM_READ_COMMAND,
+- reg_buf_dma_addr(nandc,
+- (__le32 *)vaddr + i));
+- else
+- bam_prep_ce_le32(&bam_ce_buffer[i],
+- nandc_reg_phys(nandc, reg_off + 4 * i),
+- BAM_WRITE_COMMAND,
+- *((__le32 *)vaddr + i));
+- }
+-
+- bam_txn->bam_ce_pos += size;
+-
+- /* use the separate sgl after this command */
+- if (flags & NAND_BAM_NEXT_SGL) {
+- bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
+- bam_ce_size = (bam_txn->bam_ce_pos -
+- bam_txn->bam_ce_start) *
+- sizeof(struct bam_cmd_element);
+- sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
+- bam_ce_buffer, bam_ce_size);
+- bam_txn->cmd_sgl_pos++;
+- bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
+-
+- if (flags & NAND_BAM_NWD) {
+- ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
+- DMA_PREP_FENCE |
+- DMA_PREP_CMD);
+- if (ret)
+- return ret;
+- }
+- }
+-
+- return 0;
+-}
+-
+-/*
+- * Prepares the data descriptor for BAM DMA which will be used for NAND
+- * data reads and writes.
+- */
+-static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
+- const void *vaddr, int size, unsigned int flags)
+-{
+- int ret;
+- struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+- if (read) {
+- sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
+- vaddr, size);
+- bam_txn->rx_sgl_pos++;
+- } else {
+- sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
+- vaddr, size);
+- bam_txn->tx_sgl_pos++;
+-
+- /*
+- * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
+- * is not set, form the DMA descriptor
+- */
+- if (!(flags & NAND_BAM_NO_EOT)) {
+- ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
+- DMA_PREP_INTERRUPT);
+- if (ret)
+- return ret;
+- }
+- }
+-
+- return 0;
+-}
+-
+-static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
+- int reg_off, const void *vaddr, int size,
+- bool flow_control)
+-{
+- struct desc_info *desc;
+- struct dma_async_tx_descriptor *dma_desc;
+- struct scatterlist *sgl;
+- struct dma_slave_config slave_conf;
+- struct qcom_adm_peripheral_config periph_conf = {};
+- enum dma_transfer_direction dir_eng;
+- int ret;
+-
+- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+- if (!desc)
+- return -ENOMEM;
+-
+- sgl = &desc->adm_sgl;
+-
+- sg_init_one(sgl, vaddr, size);
+-
+- if (read) {
+- dir_eng = DMA_DEV_TO_MEM;
+- desc->dir = DMA_FROM_DEVICE;
+- } else {
+- dir_eng = DMA_MEM_TO_DEV;
+- desc->dir = DMA_TO_DEVICE;
+- }
+-
+- ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
+- if (ret == 0) {
+- ret = -ENOMEM;
+- goto err;
+- }
+-
+- memset(&slave_conf, 0x00, sizeof(slave_conf));
+-
+- slave_conf.device_fc = flow_control;
+- if (read) {
+- slave_conf.src_maxburst = 16;
+- slave_conf.src_addr = nandc->base_dma + reg_off;
+- if (nandc->data_crci) {
+- periph_conf.crci = nandc->data_crci;
+- slave_conf.peripheral_config = &periph_conf;
+- slave_conf.peripheral_size = sizeof(periph_conf);
+- }
+- } else {
+- slave_conf.dst_maxburst = 16;
+- slave_conf.dst_addr = nandc->base_dma + reg_off;
+- if (nandc->cmd_crci) {
+- periph_conf.crci = nandc->cmd_crci;
+- slave_conf.peripheral_config = &periph_conf;
+- slave_conf.peripheral_size = sizeof(periph_conf);
+- }
+- }
+-
+- ret = dmaengine_slave_config(nandc->chan, &slave_conf);
+- if (ret) {
+- dev_err(nandc->dev, "failed to configure dma channel\n");
+- goto err;
+- }
+-
+- dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
+- if (!dma_desc) {
+- dev_err(nandc->dev, "failed to prepare desc\n");
+- ret = -EINVAL;
+- goto err;
+- }
+-
+- desc->dma_desc = dma_desc;
+-
+- list_add_tail(&desc->node, &nandc->desc_list);
+-
+- return 0;
+-err:
+- kfree(desc);
+-
+- return ret;
+-}
+-
+-/*
+- * qcom_read_reg_dma: prepares a descriptor to read a given number of
+- * contiguous registers to the reg_read_buf pointer
+- *
+- * @first: offset of the first register in the contiguous block
+- * @num_regs: number of registers to read
+- * @flags: flags to control DMA descriptor preparation
+- */
+-static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
+- int num_regs, unsigned int flags)
+-{
+- bool flow_control = false;
+- void *vaddr;
+-
+- vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
+- nandc->reg_read_pos += num_regs;
+-
+- if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
+- first = dev_cmd_reg_addr(nandc, first);
+-
+- if (nandc->props->supports_bam)
+- return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
+- num_regs, flags);
+-
+- if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
+- flow_control = true;
+-
+- return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
+- num_regs * sizeof(u32), flow_control);
+-}
+-
+-/*
+- * qcom_write_reg_dma: prepares a descriptor to write a given number of
+- * contiguous registers
+- *
+- * @vaddr: contiguous memory from where register value will
+- * be written
+- * @first: offset of the first register in the contiguous block
+- * @num_regs: number of registers to write
+- * @flags: flags to control DMA descriptor preparation
+- */
+-static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
+- int first, int num_regs, unsigned int flags)
+-{
+- bool flow_control = false;
+-
+- if (first == NAND_EXEC_CMD)
+- flags |= NAND_BAM_NWD;
+-
+- if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
+- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
+-
+- if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
+- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
+-
+- if (nandc->props->supports_bam)
+- return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
+- num_regs, flags);
+-
+- if (first == NAND_FLASH_CMD)
+- flow_control = true;
+-
+- return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
+- num_regs * sizeof(u32), flow_control);
+-}
+-
+-/*
+- * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the
+- * controller's internal buffer to the buffer 'vaddr'
+- *
+- * @reg_off: offset within the controller's data buffer
+- * @vaddr: virtual address of the buffer we want to write to
+- * @size: DMA transaction size in bytes
+- * @flags: flags to control DMA descriptor preparation
+- */
+-static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+- const u8 *vaddr, int size, unsigned int flags)
+-{
+- if (nandc->props->supports_bam)
+- return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
+-
+- return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
+-}
+-
+-/*
+- * qcom_write_data_dma: prepares a DMA descriptor to transfer data from
+- * 'vaddr' to the controller's internal buffer
+- *
+- * @reg_off: offset within the controller's data buffer
+- * @vaddr: virtual address of the buffer we want to read from
+- * @size: DMA transaction size in bytes
+- * @flags: flags to control DMA descriptor preparation
+- */
+-static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+- const u8 *vaddr, int size, unsigned int flags)
+-{
+- if (nandc->props->supports_bam)
+- return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
+-
+- return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
+-}
+-
+-/*
+ * Helper to prepare DMA descriptors for configuring registers
+ * before reading a NAND page.
+ */
+@@ -1262,83 +394,6 @@ static void config_nand_cw_write(struct
+ NAND_BAM_NEXT_SGL);
+ }
+
+-/* helpers to submit/free our list of dma descriptors */
+-static int qcom_submit_descs(struct qcom_nand_controller *nandc)
+-{
+- struct desc_info *desc, *n;
+- dma_cookie_t cookie = 0;
+- struct bam_transaction *bam_txn = nandc->bam_txn;
+- int ret = 0;
+-
+- if (nandc->props->supports_bam) {
+- if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
+- ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
+- if (ret)
+- goto err_unmap_free_desc;
+- }
+-
+- if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
+- ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
+- DMA_PREP_INTERRUPT);
+- if (ret)
+- goto err_unmap_free_desc;
+- }
+-
+- if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
+- ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
+- DMA_PREP_CMD);
+- if (ret)
+- goto err_unmap_free_desc;
+- }
+- }
+-
+- list_for_each_entry(desc, &nandc->desc_list, node)
+- cookie = dmaengine_submit(desc->dma_desc);
+-
+- if (nandc->props->supports_bam) {
+- bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
+- bam_txn->last_cmd_desc->callback_param = bam_txn;
+-
+- dma_async_issue_pending(nandc->tx_chan);
+- dma_async_issue_pending(nandc->rx_chan);
+- dma_async_issue_pending(nandc->cmd_chan);
+-
+- if (!wait_for_completion_timeout(&bam_txn->txn_done,
+- QPIC_NAND_COMPLETION_TIMEOUT))
+- ret = -ETIMEDOUT;
+- } else {
+- if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
+- ret = -ETIMEDOUT;
+- }
+-
+-err_unmap_free_desc:
+- /*
+- * Unmap the dma sg_list and free the desc allocated by both
+- * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
+- */
+- list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
+- list_del(&desc->node);
+-
+- if (nandc->props->supports_bam)
+- dma_unmap_sg(nandc->dev, desc->bam_sgl,
+- desc->sgl_cnt, desc->dir);
+- else
+- dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
+- desc->dir);
+-
+- kfree(desc);
+- }
+-
+- return ret;
+-}
+-
+-/* reset the register read buffer for next NAND operation */
+-static void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
+-{
+- nandc->reg_read_pos = 0;
+- qcom_nandc_dev_to_mem(nandc, false);
+-}
+-
+ /*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+@@ -2967,141 +2022,14 @@ static const struct nand_controller_ops
+ .exec_op = qcom_nand_exec_op,
+ };
+
+-static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
+-{
+- if (nandc->props->supports_bam) {
+- if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
+- dma_unmap_single(nandc->dev, nandc->reg_read_dma,
+- MAX_REG_RD *
+- sizeof(*nandc->reg_read_buf),
+- DMA_FROM_DEVICE);
+-
+- if (nandc->tx_chan)
+- dma_release_channel(nandc->tx_chan);
+-
+- if (nandc->rx_chan)
+- dma_release_channel(nandc->rx_chan);
+-
+- if (nandc->cmd_chan)
+- dma_release_channel(nandc->cmd_chan);
+- } else {
+- if (nandc->chan)
+- dma_release_channel(nandc->chan);
+- }
+-}
+-
+-static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
+-{
+- int ret;
+-
+- ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
+- if (ret) {
+- dev_err(nandc->dev, "failed to set DMA mask\n");
+- return ret;
+- }
+-
+- /*
+- * we use the internal buffer for reading ONFI params, reading small
+- * data like ID and status, and preforming read-copy-write operations
+- * when writing to a codeword partially. 532 is the maximum possible
+- * size of a codeword for our nand controller
+- */
+- nandc->buf_size = 532;
+-
+- nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
+- if (!nandc->data_buffer)
+- return -ENOMEM;
+-
+- nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
+- if (!nandc->regs)
+- return -ENOMEM;
+-
+- nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
+- sizeof(*nandc->reg_read_buf),
+- GFP_KERNEL);
+- if (!nandc->reg_read_buf)
+- return -ENOMEM;
+-
+- if (nandc->props->supports_bam) {
+- nandc->reg_read_dma =
+- dma_map_single(nandc->dev, nandc->reg_read_buf,
+- MAX_REG_RD *
+- sizeof(*nandc->reg_read_buf),
+- DMA_FROM_DEVICE);
+- if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
+- dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
+- return -EIO;
+- }
+-
+- nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
+- if (IS_ERR(nandc->tx_chan)) {
+- ret = PTR_ERR(nandc->tx_chan);
+- nandc->tx_chan = NULL;
+- dev_err_probe(nandc->dev, ret,
+- "tx DMA channel request failed\n");
+- goto unalloc;
+- }
+-
+- nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
+- if (IS_ERR(nandc->rx_chan)) {
+- ret = PTR_ERR(nandc->rx_chan);
+- nandc->rx_chan = NULL;
+- dev_err_probe(nandc->dev, ret,
+- "rx DMA channel request failed\n");
+- goto unalloc;
+- }
+-
+- nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
+- if (IS_ERR(nandc->cmd_chan)) {
+- ret = PTR_ERR(nandc->cmd_chan);
+- nandc->cmd_chan = NULL;
+- dev_err_probe(nandc->dev, ret,
+- "cmd DMA channel request failed\n");
+- goto unalloc;
+- }
+-
+- /*
+- * Initially allocate BAM transaction to read ONFI param page.
+- * After detecting all the devices, this BAM transaction will
+- * be freed and the next BAM transaction will be allocated with
+- * maximum codeword size
+- */
+- nandc->max_cwperpage = 1;
+- nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
+- if (!nandc->bam_txn) {
+- dev_err(nandc->dev,
+- "failed to allocate bam transaction\n");
+- ret = -ENOMEM;
+- goto unalloc;
+- }
+- } else {
+- nandc->chan = dma_request_chan(nandc->dev, "rxtx");
+- if (IS_ERR(nandc->chan)) {
+- ret = PTR_ERR(nandc->chan);
+- nandc->chan = NULL;
+- dev_err_probe(nandc->dev, ret,
+- "rxtx DMA channel request failed\n");
+- return ret;
+- }
+- }
+-
+- INIT_LIST_HEAD(&nandc->desc_list);
+- INIT_LIST_HEAD(&nandc->host_list);
+-
+- nand_controller_init(&nandc->controller);
+- nandc->controller.ops = &qcom_nandc_ops;
+-
+- return 0;
+-unalloc:
+- qcom_nandc_unalloc(nandc);
+- return ret;
+-}
+-
+ /* one time setup of a few nand controller registers */
+ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
+ {
+ u32 nand_ctrl;
+
++ nand_controller_init(nandc->controller);
++ nandc->controller->ops = &qcom_nandc_ops;
++
+ /* kill onenand */
+ if (!nandc->props->nandc_part_of_qpic)
+ nandc_write(nandc, SFLASHC_BURST_CFG, 0);
+@@ -3240,7 +2168,7 @@ static int qcom_nand_host_init_and_regis
+ chip->legacy.block_bad = qcom_nandc_block_bad;
+ chip->legacy.block_markbad = qcom_nandc_block_markbad;
+
+- chip->controller = &nandc->controller;
++ chip->controller = nandc->controller;
+ chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA |
+ NAND_SKIP_BBTSCAN;
+
+@@ -3323,17 +2251,21 @@ static int qcom_nandc_parse_dt(struct pl
+ static int qcom_nandc_probe(struct platform_device *pdev)
+ {
+ struct qcom_nand_controller *nandc;
++ struct nand_controller *controller;
+ const void *dev_data;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret;
+
+- nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
++ nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc) + sizeof(*controller),
++ GFP_KERNEL);
+ if (!nandc)
+ return -ENOMEM;
++ controller = (struct nand_controller *)&nandc[1];
+
+ platform_set_drvdata(pdev, nandc);
+ nandc->dev = dev;
++ nandc->controller = controller;
+
+ dev_data = of_device_get_match_data(dev);
+ if (!dev_data) {
+--- /dev/null
++++ b/include/linux/mtd/nand-qpic-common.h
+@@ -0,0 +1,468 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * QCOM QPIC common APIs header file
++ *
++ * Copyright (c) 2023 Qualcomm Inc.
++ *
++ */
++#ifndef __MTD_NAND_QPIC_COMMON_H__
++#define __MTD_NAND_QPIC_COMMON_H__
++
++/* NANDc reg offsets */
++#define NAND_FLASH_CMD 0x00
++#define NAND_ADDR0 0x04
++#define NAND_ADDR1 0x08
++#define NAND_FLASH_CHIP_SELECT 0x0c
++#define NAND_EXEC_CMD 0x10
++#define NAND_FLASH_STATUS 0x14
++#define NAND_BUFFER_STATUS 0x18
++#define NAND_DEV0_CFG0 0x20
++#define NAND_DEV0_CFG1 0x24
++#define NAND_DEV0_ECC_CFG 0x28
++#define NAND_AUTO_STATUS_EN 0x2c
++#define NAND_DEV1_CFG0 0x30
++#define NAND_DEV1_CFG1 0x34
++#define NAND_READ_ID 0x40
++#define NAND_READ_STATUS 0x44
++#define NAND_DEV_CMD0 0xa0
++#define NAND_DEV_CMD1 0xa4
++#define NAND_DEV_CMD2 0xa8
++#define NAND_DEV_CMD_VLD 0xac
++#define SFLASHC_BURST_CFG 0xe0
++#define NAND_ERASED_CW_DETECT_CFG 0xe8
++#define NAND_ERASED_CW_DETECT_STATUS 0xec
++#define NAND_EBI2_ECC_BUF_CFG 0xf0
++#define FLASH_BUF_ACC 0x100
++
++#define NAND_CTRL 0xf00
++#define NAND_VERSION 0xf08
++#define NAND_READ_LOCATION_0 0xf20
++#define NAND_READ_LOCATION_1 0xf24
++#define NAND_READ_LOCATION_2 0xf28
++#define NAND_READ_LOCATION_3 0xf2c
++#define NAND_READ_LOCATION_LAST_CW_0 0xf40
++#define NAND_READ_LOCATION_LAST_CW_1 0xf44
++#define NAND_READ_LOCATION_LAST_CW_2 0xf48
++#define NAND_READ_LOCATION_LAST_CW_3 0xf4c
++
++/* dummy register offsets, used by qcom_write_reg_dma */
++#define NAND_DEV_CMD1_RESTORE 0xdead
++#define NAND_DEV_CMD_VLD_RESTORE 0xbeef
++
++/* NAND_FLASH_CMD bits */
++#define PAGE_ACC BIT(4)
++#define LAST_PAGE BIT(5)
++
++/* NAND_FLASH_CHIP_SELECT bits */
++#define NAND_DEV_SEL 0
++#define DM_EN BIT(2)
++
++/* NAND_FLASH_STATUS bits */
++#define FS_OP_ERR BIT(4)
++#define FS_READY_BSY_N BIT(5)
++#define FS_MPU_ERR BIT(8)
++#define FS_DEVICE_STS_ERR BIT(16)
++#define FS_DEVICE_WP BIT(23)
++
++/* NAND_BUFFER_STATUS bits */
++#define BS_UNCORRECTABLE_BIT BIT(8)
++#define BS_CORRECTABLE_ERR_MSK 0x1f
++
++/* NAND_DEVn_CFG0 bits */
++#define DISABLE_STATUS_AFTER_WRITE 4
++#define CW_PER_PAGE 6
++#define UD_SIZE_BYTES 9
++#define UD_SIZE_BYTES_MASK GENMASK(18, 9)
++#define ECC_PARITY_SIZE_BYTES_RS 19
++#define SPARE_SIZE_BYTES 23
++#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
++#define NUM_ADDR_CYCLES 27
++#define STATUS_BFR_READ 30
++#define SET_RD_MODE_AFTER_STATUS 31
++
++/* NAND_DEVn_CFG0 bits */
++#define DEV0_CFG1_ECC_DISABLE 0
++#define WIDE_FLASH 1
++#define NAND_RECOVERY_CYCLES 2
++#define CS_ACTIVE_BSY 5
++#define BAD_BLOCK_BYTE_NUM 6
++#define BAD_BLOCK_IN_SPARE_AREA 16
++#define WR_RD_BSY_GAP 17
++#define ENABLE_BCH_ECC 27
++
++/* NAND_DEV0_ECC_CFG bits */
++#define ECC_CFG_ECC_DISABLE 0
++#define ECC_SW_RESET 1
++#define ECC_MODE 4
++#define ECC_PARITY_SIZE_BYTES_BCH 8
++#define ECC_NUM_DATA_BYTES 16
++#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
++#define ECC_FORCE_CLK_OPEN 30
++
++/* NAND_DEV_CMD1 bits */
++#define READ_ADDR 0
++
++/* NAND_DEV_CMD_VLD bits */
++#define READ_START_VLD BIT(0)
++#define READ_STOP_VLD BIT(1)
++#define WRITE_START_VLD BIT(2)
++#define ERASE_START_VLD BIT(3)
++#define SEQ_READ_START_VLD BIT(4)
++
++/* NAND_EBI2_ECC_BUF_CFG bits */
++#define NUM_STEPS 0
++
++/* NAND_ERASED_CW_DETECT_CFG bits */
++#define ERASED_CW_ECC_MASK 1
++#define AUTO_DETECT_RES 0
++#define MASK_ECC BIT(ERASED_CW_ECC_MASK)
++#define RESET_ERASED_DET BIT(AUTO_DETECT_RES)
++#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES)
++#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC)
++#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC)
++
++/* NAND_ERASED_CW_DETECT_STATUS bits */
++#define PAGE_ALL_ERASED BIT(7)
++#define CODEWORD_ALL_ERASED BIT(6)
++#define PAGE_ERASED BIT(5)
++#define CODEWORD_ERASED BIT(4)
++#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED)
++#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
++
++/* NAND_READ_LOCATION_n bits */
++#define READ_LOCATION_OFFSET 0
++#define READ_LOCATION_SIZE 16
++#define READ_LOCATION_LAST 31
++
++/* Version Mask */
++#define NAND_VERSION_MAJOR_MASK 0xf0000000
++#define NAND_VERSION_MAJOR_SHIFT 28
++#define NAND_VERSION_MINOR_MASK 0x0fff0000
++#define NAND_VERSION_MINOR_SHIFT 16
++
++/* NAND OP_CMDs */
++#define OP_PAGE_READ 0x2
++#define OP_PAGE_READ_WITH_ECC 0x3
++#define OP_PAGE_READ_WITH_ECC_SPARE 0x4
++#define OP_PAGE_READ_ONFI_READ 0x5
++#define OP_PROGRAM_PAGE 0x6
++#define OP_PAGE_PROGRAM_WITH_ECC 0x7
++#define OP_PROGRAM_PAGE_SPARE 0x9
++#define OP_BLOCK_ERASE 0xa
++#define OP_CHECK_STATUS 0xc
++#define OP_FETCH_ID 0xb
++#define OP_RESET_DEVICE 0xd
++
++/* Default Value for NAND_DEV_CMD_VLD */
++#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
++ ERASE_START_VLD | SEQ_READ_START_VLD)
++
++/* NAND_CTRL bits */
++#define BAM_MODE_EN BIT(0)
++
++/*
++ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
++ * the driver calls the chunks 'step' or 'codeword' interchangeably
++ */
++#define NANDC_STEP_SIZE 512
++
++/*
++ * the largest page size we support is 8K, this will have 16 steps/codewords
++ * of 512 bytes each
++ */
++#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE)
++
++/* we read at most 3 registers per codeword scan */
++#define MAX_REG_RD (3 * MAX_NUM_STEPS)
++
++/* ECC modes supported by the controller */
++#define ECC_NONE BIT(0)
++#define ECC_RS_4BIT BIT(1)
++#define ECC_BCH_4BIT BIT(2)
++#define ECC_BCH_8BIT BIT(3)
++
++/*
++ * Returns the actual register address for all NAND_DEV_ registers
++ * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
++ */
++#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
++
++/* Returns the NAND register physical address */
++#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
++
++/* Returns the dma address for reg read buffer */
++#define reg_buf_dma_addr(chip, vaddr) \
++ ((chip)->reg_read_dma + \
++ ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
++
++#define QPIC_PER_CW_CMD_ELEMENTS 32
++#define QPIC_PER_CW_CMD_SGL 32
++#define QPIC_PER_CW_DATA_SGL 8
++
++#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
++
++/*
++ * Flags used in DMA descriptor preparation helper functions
++ * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
++ */
++/* Don't set the EOT in current tx BAM sgl */
++#define NAND_BAM_NO_EOT BIT(0)
++/* Set the NWD flag in current BAM sgl */
++#define NAND_BAM_NWD BIT(1)
++/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
++#define NAND_BAM_NEXT_SGL BIT(2)
++/*
++ * Erased codeword status is being used two times in single transfer so this
++ * flag will determine the current value of erased codeword status register
++ */
++#define NAND_ERASED_CW_SET BIT(4)
++
++#define MAX_ADDRESS_CYCLE 5
++
++/*
++ * This data type corresponds to the BAM transaction which will be used for all
++ * NAND transfers.
++ * @bam_ce - the array of BAM command elements
++ * @cmd_sgl - sgl for NAND BAM command pipe
++ * @data_sgl - sgl for NAND BAM consumer/producer pipe
++ * @last_data_desc - last DMA desc in data channel (tx/rx).
++ * @last_cmd_desc - last DMA desc in command channel.
++ * @txn_done - completion for NAND transfer.
++ * @bam_ce_pos - the index in bam_ce which is available for next sgl
++ * @bam_ce_start - the index in bam_ce which marks the start position ce
++ * for current sgl. It will be used for size calculation
++ * for current sgl
++ * @cmd_sgl_pos - current index in command sgl.
++ * @cmd_sgl_start - start index in command sgl.
++ * @tx_sgl_pos - current index in data sgl for tx.
++ * @tx_sgl_start - start index in data sgl for tx.
++ * @rx_sgl_pos - current index in data sgl for rx.
++ * @rx_sgl_start - start index in data sgl for rx.
++ */
++struct bam_transaction {
++ struct bam_cmd_element *bam_ce;
++ struct scatterlist *cmd_sgl;
++ struct scatterlist *data_sgl;
++ struct dma_async_tx_descriptor *last_data_desc;
++ struct dma_async_tx_descriptor *last_cmd_desc;
++ struct completion txn_done;
++ u32 bam_ce_pos;
++ u32 bam_ce_start;
++ u32 cmd_sgl_pos;
++ u32 cmd_sgl_start;
++ u32 tx_sgl_pos;
++ u32 tx_sgl_start;
++ u32 rx_sgl_pos;
++ u32 rx_sgl_start;
++};
++
++/*
++ * This data type corresponds to the nand dma descriptor
++ * @dma_desc - low level DMA engine descriptor
++ * @list - list for desc_info
++ *
++ * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
++ * ADM
++ * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
++ * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
++ * @dir - DMA transfer direction
++ */
++struct desc_info {
++ struct dma_async_tx_descriptor *dma_desc;
++ struct list_head node;
++
++ union {
++ struct scatterlist adm_sgl;
++ struct {
++ struct scatterlist *bam_sgl;
++ int sgl_cnt;
++ };
++ };
++ enum dma_data_direction dir;
++};
++
++/*
++ * holds the current register values that we want to write. acts as a contiguous
++ * chunk of memory which we use to write the controller registers through DMA.
++ */
++struct nandc_regs {
++ __le32 cmd;
++ __le32 addr0;
++ __le32 addr1;
++ __le32 chip_sel;
++ __le32 exec;
++
++ __le32 cfg0;
++ __le32 cfg1;
++ __le32 ecc_bch_cfg;
++
++ __le32 clrflashstatus;
++ __le32 clrreadstatus;
++
++ __le32 cmd1;
++ __le32 vld;
++
++ __le32 orig_cmd1;
++ __le32 orig_vld;
++
++ __le32 ecc_buf_cfg;
++ __le32 read_location0;
++ __le32 read_location1;
++ __le32 read_location2;
++ __le32 read_location3;
++ __le32 read_location_last0;
++ __le32 read_location_last1;
++ __le32 read_location_last2;
++ __le32 read_location_last3;
++
++ __le32 erased_cw_detect_cfg_clr;
++ __le32 erased_cw_detect_cfg_set;
++};
++
++/*
++ * NAND controller data struct
++ *
++ * @dev: parent device
++ *
++ * @base: MMIO base
++ *
++ * @core_clk: controller clock
++ * @aon_clk: another controller clock
++ *
++ * @regs: a contiguous chunk of memory for DMA register
++ * writes. contains the register values to be
++ * written to controller
++ *
++ * @props: properties of current NAND controller,
++ * initialized via DT match data
++ *
++ * @controller: base controller structure
++ * @host_list: list containing all the chips attached to the
++ * controller
++ *
++ * @chan: dma channel
++ * @cmd_crci: ADM DMA CRCI for command flow control
++ * @data_crci: ADM DMA CRCI for data flow control
++ *
++ * @desc_list: DMA descriptor list (list of desc_infos)
++ *
++ * @data_buffer: our local DMA buffer for page read/writes,
++ * used when we can't use the buffer provided
++ * by upper layers directly
++ * @reg_read_buf: local buffer for reading back registers via DMA
++ *
++ * @base_phys: physical base address of controller registers
++ * @base_dma: dma base address of controller registers
++ * @reg_read_dma: contains dma address for register read buffer
++ *
++ * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
++ * functions
++ * @max_cwperpage: maximum QPIC codewords required. calculated
++ * from all connected NAND devices pagesize
++ *
++ * @reg_read_pos: marker for data read in reg_read_buf
++ *
++ * @cmd1/vld: some fixed controller register values
++ *
++ * @exec_opwrite: flag to select correct number of code word
++ * while reading status
++ */
++struct qcom_nand_controller {
++ struct device *dev;
++
++ void __iomem *base;
++
++ struct clk *core_clk;
++ struct clk *aon_clk;
++
++ struct nandc_regs *regs;
++ struct bam_transaction *bam_txn;
++
++ const struct qcom_nandc_props *props;
++
++ struct nand_controller *controller;
++ struct list_head host_list;
++
++ union {
++ /* will be used only by QPIC for BAM DMA */
++ struct {
++ struct dma_chan *tx_chan;
++ struct dma_chan *rx_chan;
++ struct dma_chan *cmd_chan;
++ };
++
++ /* will be used only by EBI2 for ADM DMA */
++ struct {
++ struct dma_chan *chan;
++ unsigned int cmd_crci;
++ unsigned int data_crci;
++ };
++ };
++
++ struct list_head desc_list;
++
++ u8 *data_buffer;
++ __le32 *reg_read_buf;
++
++ phys_addr_t base_phys;
++ dma_addr_t base_dma;
++ dma_addr_t reg_read_dma;
++
++ int buf_size;
++ int buf_count;
++ int buf_start;
++ unsigned int max_cwperpage;
++
++ int reg_read_pos;
++
++ u32 cmd1, vld;
++ bool exec_opwrite;
++};
++
++/*
++ * This data type corresponds to the NAND controller properties which varies
++ * among different NAND controllers.
++ * @ecc_modes - ecc mode for NAND
++ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
++ * @supports_bam - whether NAND controller is using BAM
++ * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
++ * @qpic_version2 - flag to indicate QPIC IP version 2
++ * @use_codeword_fixup - whether NAND has different layout for boot partitions
++ */
++struct qcom_nandc_props {
++ u32 ecc_modes;
++ u32 dev_cmd_reg_start;
++ bool supports_bam;
++ bool nandc_part_of_qpic;
++ bool qpic_version2;
++ bool use_codeword_fixup;
++};
++
++void qcom_free_bam_transaction(struct qcom_nand_controller *nandc);
++struct bam_transaction *qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc);
++void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc);
++void qcom_qpic_bam_dma_done(void *data);
++void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu);
++int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
++ struct dma_chan *chan, unsigned long flags);
++int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
++ int reg_off, const void *vaddr, int size, unsigned int flags);
++int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
++ const void *vaddr, int size, unsigned int flags);
++int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, int reg_off,
++ const void *vaddr, int size, bool flow_control);
++int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, int num_regs,
++ unsigned int flags);
++int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, int first,
++ int num_regs, unsigned int flags);
++int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr,
++ int size, unsigned int flags);
++int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr,
++ int size, unsigned int flags);
++int qcom_submit_descs(struct qcom_nand_controller *nandc);
++void qcom_clear_read_regs(struct qcom_nand_controller *nandc);
++void qcom_nandc_unalloc(struct qcom_nand_controller *nandc);
++int qcom_nandc_alloc(struct qcom_nand_controller *nandc);
++#endif
++
--- /dev/null
+From 0c08080fd71cd5dd59643104b39d3c89d793ab3c Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Nov 2024 14:45:03 +0530
+Subject: [PATCH 4/4] mtd: rawnand: qcom: use FIELD_PREP and GENMASK
+
+Use the bitfield macro FIELD_PREP, and GENMASK to
+do the shift and mask in one go. This makes the code
+more readable.
+
+---
+ drivers/mtd/nand/raw/qcom_nandc.c | 97 ++++++++++++++--------------
+ include/linux/mtd/nand-qpic-common.h | 31 +++++----
+ 2 files changed, 67 insertions(+), 61 deletions(-)
+
+--- a/drivers/mtd/nand/raw/qcom_nandc.c
++++ b/drivers/mtd/nand/raw/qcom_nandc.c
+@@ -281,7 +281,7 @@ static void update_rw_regs(struct qcom_n
+ (num_cw - 1) << CW_PER_PAGE);
+
+ cfg1 = cpu_to_le32(host->cfg1_raw);
+- ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
++ ecc_bch_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
+ }
+
+ nandc->regs->cmd = cmd;
+@@ -1494,42 +1494,41 @@ static int qcom_nand_attach_chip(struct
+ host->cw_size = host->cw_data + ecc->bytes;
+ bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
+
+- host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
+- | host->cw_data << UD_SIZE_BYTES
+- | 0 << DISABLE_STATUS_AFTER_WRITE
+- | 5 << NUM_ADDR_CYCLES
+- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
+- | 0 << STATUS_BFR_READ
+- | 1 << SET_RD_MODE_AFTER_STATUS
+- | host->spare_bytes << SPARE_SIZE_BYTES;
+-
+- host->cfg1 = 7 << NAND_RECOVERY_CYCLES
+- | 0 << CS_ACTIVE_BSY
+- | bad_block_byte << BAD_BLOCK_BYTE_NUM
+- | 0 << BAD_BLOCK_IN_SPARE_AREA
+- | 2 << WR_RD_BSY_GAP
+- | wide_bus << WIDE_FLASH
+- | host->bch_enabled << ENABLE_BCH_ECC;
+-
+- host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
+- | host->cw_size << UD_SIZE_BYTES
+- | 5 << NUM_ADDR_CYCLES
+- | 0 << SPARE_SIZE_BYTES;
+-
+- host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
+- | 0 << CS_ACTIVE_BSY
+- | 17 << BAD_BLOCK_BYTE_NUM
+- | 1 << BAD_BLOCK_IN_SPARE_AREA
+- | 2 << WR_RD_BSY_GAP
+- | wide_bus << WIDE_FLASH
+- | 1 << DEV0_CFG1_ECC_DISABLE;
+-
+- host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
+- | 0 << ECC_SW_RESET
+- | host->cw_data << ECC_NUM_DATA_BYTES
+- | 1 << ECC_FORCE_CLK_OPEN
+- | ecc_mode << ECC_MODE
+- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
++ host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
++ FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_data) |
++ FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 0) |
++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
++ FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, host->ecc_bytes_hw) |
++ FIELD_PREP(STATUS_BFR_READ, 0) |
++ FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) |
++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, host->spare_bytes);
++
++ host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) |
++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) |
++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
++ FIELD_PREP(WIDE_FLASH, wide_bus) |
++ FIELD_PREP(ENABLE_BCH_ECC, host->bch_enabled);
++
++ host->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
++ FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_size) |
++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
++
++ host->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
++ FIELD_PREP(CS_ACTIVE_BSY, 0) |
++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
++ FIELD_PREP(WIDE_FLASH, wide_bus) |
++ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
++
++ host->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !host->bch_enabled) |
++ FIELD_PREP(ECC_SW_RESET, 0) |
++ FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, host->cw_data) |
++ FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
++ FIELD_PREP(ECC_MODE_MASK, ecc_mode) |
++ FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, host->ecc_bytes_hw);
+
+ if (!nandc->props->qpic_version2)
+ host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+@@ -1882,21 +1881,21 @@ static int qcom_param_page_type_exec(str
+ nandc->regs->addr0 = 0;
+ nandc->regs->addr1 = 0;
+
+- nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE |
+- 512 << UD_SIZE_BYTES |
+- 5 << NUM_ADDR_CYCLES |
+- 0 << SPARE_SIZE_BYTES);
+-
+- nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES |
+- 0 << CS_ACTIVE_BSY |
+- 17 << BAD_BLOCK_BYTE_NUM |
+- 1 << BAD_BLOCK_IN_SPARE_AREA |
+- 2 << WR_RD_BSY_GAP |
+- 0 << WIDE_FLASH |
+- 1 << DEV0_CFG1_ECC_DISABLE);
++ host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
++ FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
++
++ host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
++ FIELD_PREP(CS_ACTIVE_BSY, 0) |
++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
++ FIELD_PREP(WIDE_FLASH, 0) |
++ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
+
+ if (!nandc->props->qpic_version2)
+- nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
++ nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
+
+ /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
+ if (!nandc->props->qpic_version2) {
+--- a/include/linux/mtd/nand-qpic-common.h
++++ b/include/linux/mtd/nand-qpic-common.h
+@@ -70,35 +70,42 @@
+ #define BS_CORRECTABLE_ERR_MSK 0x1f
+
+ /* NAND_DEVn_CFG0 bits */
+-#define DISABLE_STATUS_AFTER_WRITE 4
++#define DISABLE_STATUS_AFTER_WRITE BIT(4)
+ #define CW_PER_PAGE 6
++#define CW_PER_PAGE_MASK GENMASK(8, 6)
+ #define UD_SIZE_BYTES 9
+ #define UD_SIZE_BYTES_MASK GENMASK(18, 9)
+-#define ECC_PARITY_SIZE_BYTES_RS 19
++#define ECC_PARITY_SIZE_BYTES_RS GENMASK(22, 19)
+ #define SPARE_SIZE_BYTES 23
+ #define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
+ #define NUM_ADDR_CYCLES 27
+-#define STATUS_BFR_READ 30
+-#define SET_RD_MODE_AFTER_STATUS 31
++#define NUM_ADDR_CYCLES_MASK GENMASK(29, 27)
++#define STATUS_BFR_READ BIT(30)
++#define SET_RD_MODE_AFTER_STATUS BIT(31)
+
+ /* NAND_DEVn_CFG0 bits */
+-#define DEV0_CFG1_ECC_DISABLE 0
+-#define WIDE_FLASH 1
++#define DEV0_CFG1_ECC_DISABLE BIT(0)
++#define WIDE_FLASH BIT(1)
+ #define NAND_RECOVERY_CYCLES 2
+-#define CS_ACTIVE_BSY 5
++#define NAND_RECOVERY_CYCLES_MASK GENMASK(4, 2)
++#define CS_ACTIVE_BSY BIT(5)
+ #define BAD_BLOCK_BYTE_NUM 6
+-#define BAD_BLOCK_IN_SPARE_AREA 16
++#define BAD_BLOCK_BYTE_NUM_MASK GENMASK(15, 6)
++#define BAD_BLOCK_IN_SPARE_AREA BIT(16)
+ #define WR_RD_BSY_GAP 17
+-#define ENABLE_BCH_ECC 27
++#define WR_RD_BSY_GAP_MASK GENMASK(22, 17)
++#define ENABLE_BCH_ECC BIT(27)
+
+ /* NAND_DEV0_ECC_CFG bits */
+-#define ECC_CFG_ECC_DISABLE 0
+-#define ECC_SW_RESET 1
++#define ECC_CFG_ECC_DISABLE BIT(0)
++#define ECC_SW_RESET BIT(1)
+ #define ECC_MODE 4
++#define ECC_MODE_MASK GENMASK(5, 4)
+ #define ECC_PARITY_SIZE_BYTES_BCH 8
++#define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8)
+ #define ECC_NUM_DATA_BYTES 16
+ #define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
+-#define ECC_FORCE_CLK_OPEN 30
++#define ECC_FORCE_CLK_OPEN BIT(30)
+
+ /* NAND_DEV_CMD1 bits */
+ #define READ_ADDR 0
--- /dev/null
+From 9d4ffbcfde283f2a87ea45128ddf7e6651facdd9 Mon Sep 17 00:00:00 2001
+Date: Fri, 7 Feb 2025 20:42:38 +0100
+Subject: [PATCH] mtd: rawnand: qcom: fix broken config in
+ qcom_param_page_type_exec
+
+Fix broken config in qcom_param_page_type_exec caused by copy-paste error
+from commit 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
+
+In qcom_param_page_type_exec the value needs to be set to
+nandc->regs->cfg0 instead of host->cfg0. This wrong configuration caused
+the Qcom NANDC driver to malfunction on any device that makes use of it
+(IPQ806x, IPQ40xx, IPQ807x, IPQ60xx) with the following error:
+
+[ 0.885369] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xaa
+[ 0.885909] nand: Micron NAND 256MiB 1,8V 8-bit
+[ 0.892499] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
+[ 0.896823] nand: ECC (step, strength) = (512, 8) does not fit in OOB
+[ 0.896836] qcom-nandc 79b0000.nand-controller: No valid ECC settings possible
+[ 0.910996] bam-dma-engine 7984000.dma-controller: Cannot free busy channel
+[ 0.918070] qcom-nandc: probe of 79b0000.nand-controller failed with error -28
+
+Restore original configuration fix the problem and makes the driver work
+again.
+
+Fixes: 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
+---
+ drivers/mtd/nand/raw/qcom_nandc.c | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+--- a/drivers/mtd/nand/raw/qcom_nandc.c
++++ b/drivers/mtd/nand/raw/qcom_nandc.c
+@@ -1881,18 +1881,18 @@ static int qcom_param_page_type_exec(str
+ nandc->regs->addr0 = 0;
+ nandc->regs->addr1 = 0;
+
+- host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
+- FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
+- FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
+- FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
++ nandc->regs->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
++ FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
+
+- host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
+- FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
+- FIELD_PREP(CS_ACTIVE_BSY, 0) |
+- FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
+- FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
+- FIELD_PREP(WIDE_FLASH, 0) |
+- FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
++ nandc->regs->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
++ FIELD_PREP(CS_ACTIVE_BSY, 0) |
++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
++ FIELD_PREP(WIDE_FLASH, 0) |
++ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
+
+ if (!nandc->props->qpic_version2)
+ nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
--- /dev/null
+From b9371866799d67a80be0ea9e01bd41987db22f26 Mon Sep 17 00:00:00 2001
+Date: Mon, 6 Jan 2025 18:45:58 +0530
+Subject: [PATCH] mtd: rawnand: qcom: Fix build issue on x86 architecture
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fix a buffer overflow issue in qcom_clear_bam_transaction by using
+struct_group to group related fields and avoid FORTIFY_SOURCE warnings.
+
+On x86 architecture, the following error occurs due to warnings being
+treated as errors:
+
+In function ‘fortify_memset_chk’,
+ inlined from ‘qcom_clear_bam_transaction’ at
+drivers/mtd/nand/qpic_common.c:88:2:
+./include/linux/fortify-string.h:480:25: error: call to ‘__write_overflow_field’
+declared with attribute warning: detected write beyond size of field
+(1st parameter); maybe use struct_group()? [-Werror=attribute-warning]
+ 480 | __write_overflow_field(p_size_field, size);
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ LD [M] drivers/mtd/nand/nandcore.o
+ CC [M] drivers/w1/masters/mxc_w1.o
+cc1: all warnings being treated as errors
+
+This patch addresses the issue by grouping the related fields in
+struct bam_transaction using struct_group and updating the memset call
+accordingly.
+
+Fixes: 8c52932da5e6 ("mtd: rawnand: qcom: cleanup qcom_nandc driver")
+---
+ drivers/mtd/nand/qpic_common.c | 2 +-
+ include/linux/mtd/nand-qpic-common.h | 19 +++++++++++--------
+ 2 files changed, 12 insertions(+), 9 deletions(-)
+
+--- a/drivers/mtd/nand/qpic_common.c
++++ b/drivers/mtd/nand/qpic_common.c
+@@ -85,7 +85,7 @@ void qcom_clear_bam_transaction(struct q
+ if (!nandc->props->supports_bam)
+ return;
+
+- memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
++ memset(&bam_txn->bam_positions, 0, sizeof(bam_txn->bam_positions));
+ bam_txn->last_data_desc = NULL;
+
+ sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
+--- a/include/linux/mtd/nand-qpic-common.h
++++ b/include/linux/mtd/nand-qpic-common.h
+@@ -254,14 +254,17 @@ struct bam_transaction {
+ struct dma_async_tx_descriptor *last_data_desc;
+ struct dma_async_tx_descriptor *last_cmd_desc;
+ struct completion txn_done;
+- u32 bam_ce_pos;
+- u32 bam_ce_start;
+- u32 cmd_sgl_pos;
+- u32 cmd_sgl_start;
+- u32 tx_sgl_pos;
+- u32 tx_sgl_start;
+- u32 rx_sgl_pos;
+- u32 rx_sgl_start;
++ struct_group(bam_positions,
++ u32 bam_ce_pos;
++ u32 bam_ce_start;
++ u32 cmd_sgl_pos;
++ u32 cmd_sgl_start;
++ u32 tx_sgl_pos;
++ u32 tx_sgl_start;
++ u32 rx_sgl_pos;
++ u32 rx_sgl_start;
++
++ );
+ };
+
+ /*
--- /dev/null
+From 7304d1909080ef0c9da703500a97f46c98393fcd Mon Sep 17 00:00:00 2001
+Date: Mon, 24 Feb 2025 16:44:14 +0530
+Subject: [PATCH] spi: spi-qpic: add driver for QCOM SPI NAND flash Interface
+
+This driver implements support for the SPI-NAND mode of QCOM NAND Flash
+Interface as a SPI-MEM controller with pipelined ECC capability.
+
+---
+ drivers/mtd/nand/Makefile | 4 +
+ drivers/spi/Kconfig | 9 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/spi-qpic-snand.c | 1631 ++++++++++++++++++++++++++
+ include/linux/mtd/nand-qpic-common.h | 7 +
+ 5 files changed, 1652 insertions(+)
+ create mode 100644 drivers/spi/spi-qpic-snand.c
+
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -3,7 +3,11 @@
+ nandcore-objs := core.o bbt.o
+ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
+ obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
++ifeq ($(CONFIG_SPI_QPIC_SNAND),y)
++obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o
++else
+ obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o
++endif
+ obj-y += onenand/
+ obj-y += raw/
+ obj-y += spi/
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -898,6 +898,15 @@ config SPI_QCOM_QSPI
+ help
+ QSPI(Quad SPI) driver for Qualcomm QSPI controller.
+
++config SPI_QPIC_SNAND
++ bool "QPIC SNAND controller"
++ depends on ARCH_QCOM || COMPILE_TEST
++ select MTD
++ help
++ QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller.
++ QPIC controller supports both parallel nand and serial nand.
++ This config will enable serial nand driver for QPIC controller.
++
+ config SPI_QUP
+ tristate "Qualcomm SPI controller with QUP interface"
+ depends on ARCH_QCOM || COMPILE_TEST
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -114,6 +114,7 @@ obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-
+ obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
+ obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o
+ obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o
++obj-$(CONFIG_SPI_QPIC_SNAND) += spi-qpic-snand.o
+ obj-$(CONFIG_SPI_QUP) += spi-qup.o
+ obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
+ obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o
+--- /dev/null
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -0,0 +1,1631 @@
++/*
++ * SPDX-License-Identifier: GPL-2.0
++ *
++ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
++ *
++ * Authors:
++ */
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/dma/qcom_adm.h>
++#include <linux/dma/qcom_bam_dma.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/nand-qpic-common.h>
++#include <linux/mtd/spinand.h>
++#include <linux/bitfield.h>
++
++#define NAND_FLASH_SPI_CFG 0xc0
++#define NAND_NUM_ADDR_CYCLES 0xc4
++#define NAND_BUSY_CHECK_WAIT_CNT 0xc8
++#define NAND_FLASH_FEATURES 0xf64
++
++/* QSPI NAND config reg bits */
++#define LOAD_CLK_CNTR_INIT_EN BIT(28)
++#define CLK_CNTR_INIT_VAL_VEC 0x924
++#define CLK_CNTR_INIT_VAL_VEC_MASK GENMASK(27, 16)
++#define FEA_STATUS_DEV_ADDR 0xc0
++#define FEA_STATUS_DEV_ADDR_MASK GENMASK(15, 8)
++#define SPI_CFG BIT(0)
++#define SPI_NUM_ADDR 0xDA4DB
++#define SPI_WAIT_CNT 0x10
++#define QPIC_QSPI_NUM_CS 1
++#define SPI_TRANSFER_MODE_x1 BIT(29)
++#define SPI_TRANSFER_MODE_x4 (3 << 29)
++#define SPI_WP BIT(28)
++#define SPI_HOLD BIT(27)
++#define QPIC_SET_FEATURE BIT(31)
++
++#define SPINAND_RESET 0xff
++#define SPINAND_READID 0x9f
++#define SPINAND_GET_FEATURE 0x0f
++#define SPINAND_SET_FEATURE 0x1f
++#define SPINAND_READ 0x13
++#define SPINAND_ERASE 0xd8
++#define SPINAND_WRITE_EN 0x06
++#define SPINAND_PROGRAM_EXECUTE 0x10
++#define SPINAND_PROGRAM_LOAD 0x84
++
++#define ACC_FEATURE 0xe
++#define BAD_BLOCK_MARKER_SIZE 0x2
++#define OOB_BUF_SIZE 128
++#define ecceng_to_qspi(eng) container_of(eng, struct qpic_spi_nand, ecc_eng)
++
++struct qpic_snand_op {
++ u32 cmd_reg;
++ u32 addr1_reg;
++ u32 addr2_reg;
++};
++
++struct snandc_read_status {
++ __le32 snandc_flash;
++ __le32 snandc_buffer;
++ __le32 snandc_erased_cw;
++};
++
++/*
++ * ECC state struct
++ * @corrected: ECC corrected
++ * @bitflips: Max bit flip
++ * @failed: ECC failed
++ */
++struct qcom_ecc_stats {
++ u32 corrected;
++ u32 bitflips;
++ u32 failed;
++};
++
++struct qpic_ecc {
++ struct device *dev;
++ int ecc_bytes_hw;
++ int spare_bytes;
++ int bbm_size;
++ int ecc_mode;
++ int bytes;
++ int steps;
++ int step_size;
++ int strength;
++ int cw_size;
++ int cw_data;
++ u32 cfg0;
++ u32 cfg1;
++ u32 cfg0_raw;
++ u32 cfg1_raw;
++ u32 ecc_buf_cfg;
++ u32 ecc_bch_cfg;
++ u32 clrflashstatus;
++ u32 clrreadstatus;
++ bool bch_enabled;
++};
++
++struct qpic_spi_nand {
++ struct qcom_nand_controller *snandc;
++ struct spi_controller *ctlr;
++ struct mtd_info *mtd;
++ struct clk *iomacro_clk;
++ struct qpic_ecc *ecc;
++ struct qcom_ecc_stats ecc_stats;
++ struct nand_ecc_engine ecc_eng;
++ u8 *data_buf;
++ u8 *oob_buf;
++ u32 wlen;
++ __le32 addr1;
++ __le32 addr2;
++ __le32 cmd;
++ u32 num_cw;
++ bool oob_rw;
++ bool page_rw;
++ bool raw_rw;
++};
++
++static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc,
++ int reg, int cw_offset, int read_size,
++ int is_last_read_loc)
++{
++ __le32 locreg_val;
++ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
++ ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
++ << READ_LOCATION_LAST));
++
++ locreg_val = cpu_to_le32(val);
++
++ if (reg == NAND_READ_LOCATION_0)
++ snandc->regs->read_location0 = locreg_val;
++ else if (reg == NAND_READ_LOCATION_1)
++ snandc->regs->read_location1 = locreg_val;
++ else if (reg == NAND_READ_LOCATION_2)
++ snandc->regs->read_location1 = locreg_val;
++ else if (reg == NAND_READ_LOCATION_3)
++ snandc->regs->read_location3 = locreg_val;
++}
++
++static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc,
++ int reg, int cw_offset, int read_size,
++ int is_last_read_loc)
++{
++ __le32 locreg_val;
++ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
++ ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
++ << READ_LOCATION_LAST));
++
++ locreg_val = cpu_to_le32(val);
++
++ if (reg == NAND_READ_LOCATION_LAST_CW_0)
++ snandc->regs->read_location_last0 = locreg_val;
++ else if (reg == NAND_READ_LOCATION_LAST_CW_1)
++ snandc->regs->read_location_last1 = locreg_val;
++ else if (reg == NAND_READ_LOCATION_LAST_CW_2)
++ snandc->regs->read_location_last2 = locreg_val;
++ else if (reg == NAND_READ_LOCATION_LAST_CW_3)
++ snandc->regs->read_location_last3 = locreg_val;
++}
++
++static struct qcom_nand_controller *nand_to_qcom_snand(struct nand_device *nand)
++{
++ struct nand_ecc_engine *eng = nand->ecc.engine;
++ struct qpic_spi_nand *qspi = ecceng_to_qspi(eng);
++
++ return qspi->snandc;
++}
++
++static int qcom_spi_init(struct qcom_nand_controller *snandc)
++{
++ u32 snand_cfg_val = 0x0;
++ int ret;
++
++ snand_cfg_val = FIELD_PREP(CLK_CNTR_INIT_VAL_VEC_MASK, CLK_CNTR_INIT_VAL_VEC) |
++ FIELD_PREP(LOAD_CLK_CNTR_INIT_EN, 0) |
++ FIELD_PREP(FEA_STATUS_DEV_ADDR_MASK, FEA_STATUS_DEV_ADDR) |
++ FIELD_PREP(SPI_CFG, 0);
++
++ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
++ snandc->regs->num_addr_cycle = cpu_to_le32(SPI_NUM_ADDR);
++ snandc->regs->busy_wait_cnt = cpu_to_le32(SPI_WAIT_CNT);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
++
++ snand_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN;
++ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->num_addr_cycle, NAND_NUM_ADDR_CYCLES, 1, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->busy_wait_cnt, NAND_BUSY_CHECK_WAIT_CNT, 1,
++ NAND_BAM_NEXT_SGL);
++
++ ret = qcom_submit_descs(snandc);
++ if (ret) {
++ dev_err(snandc->dev, "failure in submitting spi init descriptor\n");
++ return ret;
++ }
++
++ return ret;
++}
++
++static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct nand_device *nand = mtd_to_nanddev(mtd);
++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++ struct qpic_ecc *qecc = snandc->qspi->ecc;
++
++ if (section > 1)
++ return -ERANGE;
++
++ oobregion->length = qecc->ecc_bytes_hw + qecc->spare_bytes;
++ oobregion->offset = mtd->oobsize - oobregion->length;
++
++ return 0;
++}
++
++static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct nand_device *nand = mtd_to_nanddev(mtd);
++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++ struct qpic_ecc *qecc = snandc->qspi->ecc;
++
++ if (section)
++ return -ERANGE;
++
++ oobregion->length = qecc->steps * 4;
++ oobregion->offset = ((qecc->steps - 1) * qecc->bytes) + qecc->bbm_size;
++
++ return 0;
++}
++
++static const struct mtd_ooblayout_ops qcom_spi_ooblayout = {
++ .ecc = qcom_spi_ooblayout_ecc,
++ .free = qcom_spi_ooblayout_free,
++};
++
++static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
++{
++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++ struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
++ struct mtd_info *mtd = nanddev_to_mtd(nand);
++ int cwperpage, bad_block_byte;
++ struct qpic_ecc *ecc_cfg;
++
++ cwperpage = mtd->writesize / NANDC_STEP_SIZE;
++ snandc->qspi->num_cw = cwperpage;
++
++ ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
++ if (!ecc_cfg)
++ return -ENOMEM;
++ snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
++ GFP_KERNEL);
++ if (!snandc->qspi->oob_buf)
++ return -ENOMEM;
++
++ memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
++
++ nand->ecc.ctx.priv = ecc_cfg;
++ snandc->qspi->mtd = mtd;
++
++ ecc_cfg->ecc_bytes_hw = 7;
++ ecc_cfg->spare_bytes = 4;
++ ecc_cfg->bbm_size = 1;
++ ecc_cfg->bch_enabled = true;
++ ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
++
++ ecc_cfg->steps = 4;
++ ecc_cfg->strength = 4;
++ ecc_cfg->step_size = 512;
++ ecc_cfg->cw_data = 516;
++ ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
++ bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;
++
++ mtd_set_ooblayout(mtd, &qcom_spi_ooblayout);
++
++ ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
++ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) |
++ FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) |
++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
++ FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, ecc_cfg->ecc_bytes_hw) |
++ FIELD_PREP(STATUS_BFR_READ, 0) |
++ FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) |
++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, ecc_cfg->spare_bytes);
++
++ ecc_cfg->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
++ FIELD_PREP(CS_ACTIVE_BSY, 0) |
++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) |
++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) |
++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
++ FIELD_PREP(WIDE_FLASH, 0) |
++ FIELD_PREP(ENABLE_BCH_ECC, ecc_cfg->bch_enabled);
++
++ ecc_cfg->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
++ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_size) |
++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
++
++ ecc_cfg->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
++ FIELD_PREP(CS_ACTIVE_BSY, 0) |
++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
++ FIELD_PREP(WIDE_FLASH, 0) |
++ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
++
++ ecc_cfg->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !ecc_cfg->bch_enabled) |
++ FIELD_PREP(ECC_SW_RESET, 0) |
++ FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
++ FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
++ FIELD_PREP(ECC_MODE_MASK, 0) |
++ FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
++
++ ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
++ ecc_cfg->clrflashstatus = FS_READY_BSY_N;
++ ecc_cfg->clrreadstatus = 0xc0;
++
++ conf->step_size = ecc_cfg->step_size;
++ conf->strength = ecc_cfg->strength;
++
++ snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET);
++ snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET);
++
++ dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n",
++ ecc_cfg->strength, ecc_cfg->step_size);
++
++ return 0;
++}
++
++static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand)
++{
++ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
++
++ kfree(ecc_cfg);
++}
++
++static int qcom_spi_ecc_prepare_io_req_pipelined(struct nand_device *nand,
++ struct nand_page_io_req *req)
++{
++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
++
++ snandc->qspi->ecc = ecc_cfg;
++ snandc->qspi->raw_rw = false;
++ snandc->qspi->oob_rw = false;
++ snandc->qspi->page_rw = false;
++
++ if (req->datalen)
++ snandc->qspi->page_rw = true;
++
++ if (req->ooblen)
++ snandc->qspi->oob_rw = true;
++
++ if (req->mode == MTD_OPS_RAW)
++ snandc->qspi->raw_rw = true;
++
++ return 0;
++}
++
++static int qcom_spi_ecc_finish_io_req_pipelined(struct nand_device *nand,
++ struct nand_page_io_req *req)
++{
++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++ struct mtd_info *mtd = nanddev_to_mtd(nand);
++
++ if (req->mode == MTD_OPS_RAW || req->type != NAND_PAGE_READ)
++ return 0;
++
++ if (snandc->qspi->ecc_stats.failed)
++ mtd->ecc_stats.failed += snandc->qspi->ecc_stats.failed;
++ else
++ mtd->ecc_stats.corrected += snandc->qspi->ecc_stats.corrected;
++
++ if (snandc->qspi->ecc_stats.failed)
++ return -EBADMSG;
++ else
++ return snandc->qspi->ecc_stats.bitflips;
++}
++
++static struct nand_ecc_engine_ops qcom_spi_ecc_engine_ops_pipelined = {
++ .init_ctx = qcom_spi_ecc_init_ctx_pipelined,
++ .cleanup_ctx = qcom_spi_ecc_cleanup_ctx_pipelined,
++ .prepare_io_req = qcom_spi_ecc_prepare_io_req_pipelined,
++ .finish_io_req = qcom_spi_ecc_finish_io_req_pipelined,
++};
++
++/* helper to configure location register values */
++static void qcom_spi_set_read_loc(struct qcom_nand_controller *snandc, int cw, int reg,
++ int cw_offset, int read_size, int is_last_read_loc)
++{
++ int reg_base = NAND_READ_LOCATION_0;
++ int num_cw = snandc->qspi->num_cw;
++
++ if (cw == (num_cw - 1))
++ reg_base = NAND_READ_LOCATION_LAST_CW_0;
++
++ reg_base += reg * 4;
++
++ if (cw == (num_cw - 1))
++ return qcom_spi_set_read_loc_last(snandc, reg_base, cw_offset,
++ read_size, is_last_read_loc);
++ else
++ return qcom_spi_set_read_loc_first(snandc, reg_base, cw_offset,
++ read_size, is_last_read_loc);
++}
++
++static void
++qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int cw)
++{
++ __le32 *reg = &snandc->regs->read_location0;
++ int num_cw = snandc->qspi->num_cw;
++
++ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
++ if (cw == (num_cw - 1)) {
++ reg = &snandc->regs->read_location_last0;
++ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4,
++ NAND_BAM_NEXT_SGL);
++ }
++
++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0);
++ qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1,
++ NAND_BAM_NEXT_SGL);
++}
++
++static int qcom_spi_block_erase(struct qcom_nand_controller *snandc)
++{
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ int ret;
++
++ snandc->buf_count = 0;
++ snandc->buf_start = 0;
++ qcom_clear_read_regs(snandc);
++ qcom_clear_bam_transaction(snandc);
++
++ snandc->regs->cmd = snandc->qspi->cmd;
++ snandc->regs->addr0 = snandc->qspi->addr1;
++ snandc->regs->addr1 = snandc->qspi->addr2;
++ snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE));
++ snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw);
++ snandc->regs->exec = cpu_to_le32(1);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++ ret = qcom_submit_descs(snandc);
++ if (ret) {
++ dev_err(snandc->dev, "failure to erase block\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *snandc,
++ bool use_ecc, int cw)
++{
++ __le32 *reg = &snandc->regs->read_location0;
++ int num_cw = snandc->qspi->num_cw;
++
++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
++ NAND_ERASED_CW_DETECT_CFG, 1, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
++ NAND_ERASED_CW_DETECT_CFG, 1,
++ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++
++ if (cw == (num_cw - 1)) {
++ reg = &snandc->regs->read_location_last0;
++ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, NAND_BAM_NEXT_SGL);
++ }
++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0);
++}
++
++static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ struct mtd_info *mtd = snandc->qspi->mtd;
++ int size, ret = 0;
++ int col, bbpos;
++ u32 cfg0, cfg1, ecc_bch_cfg;
++ u32 num_cw = snandc->qspi->num_cw;
++
++ qcom_clear_bam_transaction(snandc);
++ qcom_clear_read_regs(snandc);
++
++ size = ecc_cfg->cw_size;
++ col = ecc_cfg->cw_size * (num_cw - 1);
++
++ memset(snandc->data_buffer, 0xff, size);
++ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
++ snandc->regs->addr1 = snandc->qspi->addr2;
++
++ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
++ 0 << CW_PER_PAGE;
++ cfg1 = ecc_cfg->cfg1_raw;
++ ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
++
++ snandc->regs->cmd = snandc->qspi->cmd;
++ snandc->regs->cfg0 = cpu_to_le32(cfg0);
++ snandc->regs->cfg1 = cpu_to_le32(cfg1);
++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++ snandc->regs->exec = cpu_to_le32(1);
++
++ qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1);
++
++ qcom_spi_config_single_cw_page_read(snandc, false, num_cw - 1);
++
++ qcom_read_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, size, 0);
++
++ ret = qcom_submit_descs(snandc);
++ if (ret) {
++ dev_err(snandc->dev, "failed to read last cw\n");
++ return ret;
++ }
++
++ qcom_nandc_dev_to_mem(snandc, true);
++ u32 flash = le32_to_cpu(snandc->reg_read_buf[0]);
++
++ if (flash & (FS_OP_ERR | FS_MPU_ERR))
++ return -EIO;
++
++ bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
++
++ if (snandc->data_buffer[bbpos] == 0xff)
++ snandc->data_buffer[bbpos + 1] = 0xff;
++ if (snandc->data_buffer[bbpos] != 0xff)
++ snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos];
++
++ memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes);
++
++ return ret;
++}
++
++static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf)
++{
++ struct snandc_read_status *buf;
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ int i, num_cw = snandc->qspi->num_cw;
++ bool flash_op_err = false, erased;
++ unsigned int max_bitflips = 0;
++ unsigned int uncorrectable_cws = 0;
++
++ snandc->qspi->ecc_stats.failed = 0;
++ snandc->qspi->ecc_stats.corrected = 0;
++
++ qcom_nandc_dev_to_mem(snandc, true);
++ buf = (struct snandc_read_status *)snandc->reg_read_buf;
++
++ for (i = 0; i < num_cw; i++, buf++) {
++ u32 flash, buffer, erased_cw;
++ int data_len, oob_len;
++
++ if (i == (num_cw - 1)) {
++ data_len = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
++ oob_len = num_cw << 2;
++ } else {
++ data_len = ecc_cfg->cw_data;
++ oob_len = 0;
++ }
++
++ flash = le32_to_cpu(buf->snandc_flash);
++ buffer = le32_to_cpu(buf->snandc_buffer);
++ erased_cw = le32_to_cpu(buf->snandc_erased_cw);
++
++ if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
++ if (ecc_cfg->bch_enabled)
++ erased = (erased_cw & ERASED_CW) == ERASED_CW;
++ else
++ erased = false;
++
++ if (!erased)
++ uncorrectable_cws |= BIT(i);
++
++ } else if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
++ flash_op_err = true;
++ } else {
++ unsigned int stat;
++
++ stat = buffer & BS_CORRECTABLE_ERR_MSK;
++ snandc->qspi->ecc_stats.corrected += stat;
++ max_bitflips = max(max_bitflips, stat);
++ }
++
++ if (data_buf)
++ data_buf += data_len;
++ if (oob_buf)
++ oob_buf += oob_len + ecc_cfg->bytes;
++ }
++
++ if (flash_op_err)
++ return -EIO;
++
++ if (!uncorrectable_cws)
++ snandc->qspi->ecc_stats.bitflips = max_bitflips;
++ else
++ snandc->qspi->ecc_stats.failed++;
++
++ return 0;
++}
++
++static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt)
++{
++ int i;
++
++ qcom_nandc_dev_to_mem(snandc, true);
++
++ for (i = 0; i < cw_cnt; i++) {
++ u32 flash = le32_to_cpu(snandc->reg_read_buf[i]);
++
++ if (flash & (FS_OP_ERR | FS_MPU_ERR))
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf,
++ u8 *oob_buf, int cw)
++{
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ struct mtd_info *mtd = snandc->qspi->mtd;
++ int data_size1, data_size2, oob_size1, oob_size2;
++ int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
++ int raw_cw = cw;
++ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
++ int col;
++
++ snandc->buf_count = 0;
++ snandc->buf_start = 0;
++ qcom_clear_read_regs(snandc);
++ qcom_clear_bam_transaction(snandc);
++ raw_cw = num_cw - 1;
++
++ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
++ 0 << CW_PER_PAGE;
++ cfg1 = ecc_cfg->cfg1_raw;
++ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
++
++ col = ecc_cfg->cw_size * cw;
++
++ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
++ snandc->regs->addr1 = snandc->qspi->addr2;
++ snandc->regs->cmd = snandc->qspi->cmd;
++ snandc->regs->cfg0 = cpu_to_le32(cfg0);
++ snandc->regs->cfg1 = cpu_to_le32(cfg1);
++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++ snandc->regs->exec = cpu_to_le32(1);
++
++ qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
++ NAND_ERASED_CW_DETECT_CFG, 1, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
++ NAND_ERASED_CW_DETECT_CFG, 1,
++ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++
++ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
++ oob_size1 = ecc_cfg->bbm_size;
++
++ if (cw == (num_cw - 1)) {
++ data_size2 = NANDC_STEP_SIZE - data_size1 -
++ ((num_cw - 1) * 4);
++ oob_size2 = (num_cw * 4) + ecc_cfg->ecc_bytes_hw +
++ ecc_cfg->spare_bytes;
++ } else {
++ data_size2 = ecc_cfg->cw_data - data_size1;
++ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
++ }
++
++ qcom_spi_set_read_loc(snandc, cw, 0, read_loc, data_size1, 0);
++ read_loc += data_size1;
++
++ qcom_spi_set_read_loc(snandc, cw, 1, read_loc, oob_size1, 0);
++ read_loc += oob_size1;
++
++ qcom_spi_set_read_loc(snandc, cw, 2, read_loc, data_size2, 0);
++ read_loc += data_size2;
++
++ qcom_spi_set_read_loc(snandc, cw, 3, read_loc, oob_size2, 1);
++
++ qcom_spi_config_cw_read(snandc, false, raw_cw);
++
++ qcom_read_data_dma(snandc, reg_off, data_buf, data_size1, 0);
++ reg_off += data_size1;
++
++ qcom_read_data_dma(snandc, reg_off, oob_buf, oob_size1, 0);
++ reg_off += oob_size1;
++
++ qcom_read_data_dma(snandc, reg_off, data_buf + data_size1, data_size2, 0);
++ reg_off += data_size2;
++
++ qcom_read_data_dma(snandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
++
++ ret = qcom_submit_descs(snandc);
++ if (ret) {
++ dev_err(snandc->dev, "failure to read raw cw %d\n", cw);
++ return ret;
++ }
++
++ return qcom_spi_check_raw_flash_errors(snandc, 1);
++}
++
++static int qcom_spi_read_page_raw(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ u8 *data_buf = NULL, *oob_buf = NULL;
++ int ret, cw;
++ u32 num_cw = snandc->qspi->num_cw;
++
++ if (snandc->qspi->page_rw)
++ data_buf = op->data.buf.in;
++
++ oob_buf = snandc->qspi->oob_buf;
++ memset(oob_buf, 0xff, OOB_BUF_SIZE);
++
++ for (cw = 0; cw < num_cw; cw++) {
++ ret = qcom_spi_read_cw_raw(snandc, data_buf, oob_buf, cw);
++ if (ret)
++ return ret;
++
++ if (data_buf)
++ data_buf += ecc_cfg->cw_data;
++ if (oob_buf)
++ oob_buf += ecc_cfg->bytes;
++ }
++
++ return 0;
++}
++
++static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
++ int ret, i;
++ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
++
++ data_buf = op->data.buf.in;
++ data_buf_start = data_buf;
++
++ oob_buf = snandc->qspi->oob_buf;
++ oob_buf_start = oob_buf;
++
++ snandc->buf_count = 0;
++ snandc->buf_start = 0;
++ qcom_clear_read_regs(snandc);
++
++ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
++ (num_cw - 1) << CW_PER_PAGE;
++ cfg1 = ecc_cfg->cfg1;
++ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
++
++ snandc->regs->addr0 = snandc->qspi->addr1;
++ snandc->regs->addr1 = snandc->qspi->addr2;
++ snandc->regs->cmd = snandc->qspi->cmd;
++ snandc->regs->cfg0 = cpu_to_le32(cfg0);
++ snandc->regs->cfg1 = cpu_to_le32(cfg1);
++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++ snandc->regs->exec = cpu_to_le32(1);
++
++ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
++
++ qcom_clear_bam_transaction(snandc);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
++ NAND_ERASED_CW_DETECT_CFG, 1, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
++ NAND_ERASED_CW_DETECT_CFG, 1,
++ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++
++ for (i = 0; i < num_cw; i++) {
++ int data_size, oob_size;
++
++ if (i == (num_cw - 1)) {
++ data_size = 512 - ((num_cw - 1) << 2);
++ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
++ ecc_cfg->spare_bytes;
++ } else {
++ data_size = ecc_cfg->cw_data;
++ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
++ }
++
++ if (data_buf && oob_buf) {
++ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 0);
++ qcom_spi_set_read_loc(snandc, i, 1, data_size, oob_size, 1);
++ } else if (data_buf) {
++ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 1);
++ } else {
++ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
++ }
++
++ qcom_spi_config_cw_read(snandc, true, i);
++
++ if (data_buf)
++ qcom_read_data_dma(snandc, FLASH_BUF_ACC, data_buf,
++ data_size, 0);
++ if (oob_buf) {
++ int j;
++
++ for (j = 0; j < ecc_cfg->bbm_size; j++)
++ *oob_buf++ = 0xff;
++
++ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
++ oob_buf, oob_size, 0);
++ }
++
++ if (data_buf)
++ data_buf += data_size;
++ if (oob_buf)
++ oob_buf += oob_size;
++ }
++
++ ret = qcom_submit_descs(snandc);
++ if (ret) {
++ dev_err(snandc->dev, "failure to read page\n");
++ return ret;
++ }
++
++ return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
++}
++
++static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
++ int ret, i;
++ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
++
++ oob_buf = op->data.buf.in;
++ oob_buf_start = oob_buf;
++
++ data_buf_start = data_buf;
++
++ snandc->buf_count = 0;
++ snandc->buf_start = 0;
++ qcom_clear_read_regs(snandc);
++ qcom_clear_bam_transaction(snandc);
++
++ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
++ (num_cw - 1) << CW_PER_PAGE;
++ cfg1 = ecc_cfg->cfg1;
++ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
++
++ snandc->regs->addr0 = snandc->qspi->addr1;
++ snandc->regs->addr1 = snandc->qspi->addr2;
++ snandc->regs->cmd = snandc->qspi->cmd;
++ snandc->regs->cfg0 = cpu_to_le32(cfg0);
++ snandc->regs->cfg1 = cpu_to_le32(cfg1);
++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++ snandc->regs->exec = cpu_to_le32(1);
++
++ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
++ NAND_ERASED_CW_DETECT_CFG, 1, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
++ NAND_ERASED_CW_DETECT_CFG, 1,
++ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++
++ for (i = 0; i < num_cw; i++) {
++ int data_size, oob_size;
++
++ if (i == (num_cw - 1)) {
++ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
++ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
++ ecc_cfg->spare_bytes;
++ } else {
++ data_size = ecc_cfg->cw_data;
++ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
++ }
++
++ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
++
++ qcom_spi_config_cw_read(snandc, true, i);
++
++ if (oob_buf) {
++ int j;
++
++ for (j = 0; j < ecc_cfg->bbm_size; j++)
++ *oob_buf++ = 0xff;
++
++ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
++ oob_buf, oob_size, 0);
++ }
++
++ if (oob_buf)
++ oob_buf += oob_size;
++ }
++
++ ret = qcom_submit_descs(snandc);
++ if (ret) {
++ dev_err(snandc->dev, "failure to read oob\n");
++ return ret;
++ }
++
++ return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
++}
++
++static int qcom_spi_read_page(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
++ return qcom_spi_read_page_raw(snandc, op);
++
++ if (snandc->qspi->page_rw)
++ return qcom_spi_read_page_ecc(snandc, op);
++
++ if (snandc->qspi->oob_rw && snandc->qspi->raw_rw)
++ return qcom_spi_read_last_cw(snandc, op);
++
++ if (snandc->qspi->oob_rw)
++ return qcom_spi_read_page_oob(snandc, op);
++
++ return 0;
++}
++
++static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc)
++{
++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG,
++ 1, NAND_BAM_NEXT_SGL);
++}
++
++static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc)
++{
++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
++ qcom_write_reg_dma(snandc, &snandc->regs->clrreadstatus, NAND_READ_STATUS, 1,
++ NAND_BAM_NEXT_SGL);
++}
++
++static int qcom_spi_program_raw(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ struct mtd_info *mtd = snandc->qspi->mtd;
++ u8 *data_buf = NULL, *oob_buf = NULL;
++ int i, ret;
++ int num_cw = snandc->qspi->num_cw;
++ u32 cfg0, cfg1, ecc_bch_cfg;
++
++ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
++ (num_cw - 1) << CW_PER_PAGE;
++ cfg1 = ecc_cfg->cfg1_raw;
++ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
++
++ data_buf = snandc->qspi->data_buf;
++
++ oob_buf = snandc->qspi->oob_buf;
++ memset(oob_buf, 0xff, OOB_BUF_SIZE);
++
++ snandc->buf_count = 0;
++ snandc->buf_start = 0;
++ qcom_clear_read_regs(snandc);
++ qcom_clear_bam_transaction(snandc);
++
++ snandc->regs->addr0 = snandc->qspi->addr1;
++ snandc->regs->addr1 = snandc->qspi->addr2;
++ snandc->regs->cmd = snandc->qspi->cmd;
++ snandc->regs->cfg0 = cpu_to_le32(cfg0);
++ snandc->regs->cfg1 = cpu_to_le32(cfg1);
++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++ snandc->regs->exec = cpu_to_le32(1);
++
++ qcom_spi_config_page_write(snandc);
++
++ for (i = 0; i < num_cw; i++) {
++ int data_size1, data_size2, oob_size1, oob_size2;
++ int reg_off = FLASH_BUF_ACC;
++
++ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
++ oob_size1 = ecc_cfg->bbm_size;
++
++ if (i == (num_cw - 1)) {
++ data_size2 = NANDC_STEP_SIZE - data_size1 -
++ ((num_cw - 1) << 2);
++ oob_size2 = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
++ ecc_cfg->spare_bytes;
++ } else {
++ data_size2 = ecc_cfg->cw_data - data_size1;
++ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
++ }
++
++ qcom_write_data_dma(snandc, reg_off, data_buf, data_size1,
++ NAND_BAM_NO_EOT);
++ reg_off += data_size1;
++ data_buf += data_size1;
++
++ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size1,
++ NAND_BAM_NO_EOT);
++ oob_buf += oob_size1;
++ reg_off += oob_size1;
++
++ qcom_write_data_dma(snandc, reg_off, data_buf, data_size2,
++ NAND_BAM_NO_EOT);
++ reg_off += data_size2;
++ data_buf += data_size2;
++
++ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size2, 0);
++ oob_buf += oob_size2;
++
++ qcom_spi_config_cw_write(snandc);
++ }
++
++ ret = qcom_submit_descs(snandc);
++ if (ret) {
++ dev_err(snandc->dev, "failure to write raw page\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ u8 *data_buf = NULL, *oob_buf = NULL;
++ int i, ret;
++ int num_cw = snandc->qspi->num_cw;
++ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
++
++ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
++ (num_cw - 1) << CW_PER_PAGE;
++ cfg1 = ecc_cfg->cfg1;
++ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
++ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
++
++ if (snandc->qspi->data_buf)
++ data_buf = snandc->qspi->data_buf;
++
++ oob_buf = snandc->qspi->oob_buf;
++
++ snandc->buf_count = 0;
++ snandc->buf_start = 0;
++ qcom_clear_read_regs(snandc);
++ qcom_clear_bam_transaction(snandc);
++
++ snandc->regs->addr0 = snandc->qspi->addr1;
++ snandc->regs->addr1 = snandc->qspi->addr2;
++ snandc->regs->cmd = snandc->qspi->cmd;
++ snandc->regs->cfg0 = cpu_to_le32(cfg0);
++ snandc->regs->cfg1 = cpu_to_le32(cfg1);
++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
++ snandc->regs->exec = cpu_to_le32(1);
++
++ qcom_spi_config_page_write(snandc);
++
++ for (i = 0; i < num_cw; i++) {
++ int data_size, oob_size;
++
++ if (i == (num_cw - 1)) {
++ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
++ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
++ ecc_cfg->spare_bytes;
++ } else {
++ data_size = ecc_cfg->cw_data;
++ oob_size = ecc_cfg->bytes;
++ }
++
++ if (data_buf)
++ qcom_write_data_dma(snandc, FLASH_BUF_ACC, data_buf, data_size,
++ i == (num_cw - 1) ? NAND_BAM_NO_EOT : 0);
++
++ if (i == (num_cw - 1)) {
++ if (oob_buf) {
++ oob_buf += ecc_cfg->bbm_size;
++ qcom_write_data_dma(snandc, FLASH_BUF_ACC + data_size,
++ oob_buf, oob_size, 0);
++ }
++ }
++
++ qcom_spi_config_cw_write(snandc);
++
++ if (data_buf)
++ data_buf += data_size;
++ if (oob_buf)
++ oob_buf += oob_size;
++ }
++
++ ret = qcom_submit_descs(snandc);
++ if (ret) {
++ dev_err(snandc->dev, "failure to write page\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static int qcom_spi_program_oob(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++ u8 *oob_buf = NULL;
++ int ret, col, data_size, oob_size;
++ int num_cw = snandc->qspi->num_cw;
++ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
++
++ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
++ (num_cw - 1) << CW_PER_PAGE;
++ cfg1 = ecc_cfg->cfg1;
++ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
++ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
++
++ col = ecc_cfg->cw_size * (num_cw - 1);
++
++ oob_buf = snandc->qspi->data_buf;
++
++ snandc->buf_count = 0;
++ snandc->buf_start = 0;
++ qcom_clear_read_regs(snandc);
++ qcom_clear_bam_transaction(snandc);
++ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
++ snandc->regs->addr1 = snandc->qspi->addr2;
++ snandc->regs->cmd = snandc->qspi->cmd;
++ snandc->regs->cfg0 = cpu_to_le32(cfg0);
++ snandc->regs->cfg1 = cpu_to_le32(cfg1);
++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
++ snandc->regs->exec = cpu_to_le32(1);
++
++ /* calculate the data and oob size for the last codeword/step */
++ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
++ oob_size = snandc->qspi->mtd->oobavail;
++
++ memset(snandc->data_buffer, 0xff, ecc_cfg->cw_data);
++ /* override new oob content to last codeword */
++ mtd_ooblayout_get_databytes(snandc->qspi->mtd, snandc->data_buffer + data_size,
++ oob_buf, 0, snandc->qspi->mtd->oobavail);
++ qcom_spi_config_page_write(snandc);
++ qcom_write_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, data_size + oob_size, 0);
++ qcom_spi_config_cw_write(snandc);
++
++ ret = qcom_submit_descs(snandc);
++ if (ret) {
++ dev_err(snandc->dev, "failure to write oob\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static int qcom_spi_program_execute(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
++ return qcom_spi_program_raw(snandc, op);
++
++ if (snandc->qspi->page_rw)
++ return qcom_spi_program_ecc(snandc, op);
++
++ if (snandc->qspi->oob_rw)
++ return qcom_spi_program_oob(snandc, op);
++
++ return 0;
++}
++
++static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd)
++{
++ switch (opcode) {
++ case SPINAND_RESET:
++ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE);
++ break;
++ case SPINAND_READID:
++ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID);
++ break;
++ case SPINAND_GET_FEATURE:
++ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE);
++ break;
++ case SPINAND_SET_FEATURE:
++ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE |
++ QPIC_SET_FEATURE);
++ break;
++ case SPINAND_READ:
++ if (snandc->qspi->raw_rw) {
++ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
++ SPI_WP | SPI_HOLD | OP_PAGE_READ);
++ } else {
++ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
++ SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC);
++ }
++
++ break;
++ case SPINAND_ERASE:
++ *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP |
++ SPI_HOLD | SPI_TRANSFER_MODE_x1;
++ break;
++ case SPINAND_WRITE_EN:
++ *cmd = SPINAND_WRITE_EN;
++ break;
++ case SPINAND_PROGRAM_EXECUTE:
++ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
++ SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
++ break;
++ case SPINAND_PROGRAM_LOAD:
++ *cmd = SPINAND_PROGRAM_LOAD;
++ break;
++ default:
++ dev_err(snandc->dev, "Opcode not supported: %u\n", opcode);
++ return -EOPNOTSUPP;
++ }
++
++ return 0;
++}
++
++static int qcom_spi_write_page(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ int ret;
++ u32 cmd;
++
++ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
++ if (ret < 0)
++ return ret;
++
++ if (op->cmd.opcode == SPINAND_PROGRAM_LOAD)
++ snandc->qspi->data_buf = (u8 *)op->data.buf.out;
++
++ return 0;
++}
++
++static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
++ const struct spi_mem_op *op)
++{
++ struct qpic_snand_op s_op = {};
++ u32 cmd;
++ int ret, opcode;
++
++ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
++ if (ret < 0)
++ return ret;
++
++ s_op.cmd_reg = cmd;
++ s_op.addr1_reg = op->addr.val;
++ s_op.addr2_reg = 0;
++
++ opcode = op->cmd.opcode;
++
++ switch (opcode) {
++ case SPINAND_WRITE_EN:
++ return 0;
++ case SPINAND_PROGRAM_EXECUTE:
++ s_op.addr1_reg = op->addr.val << 16;
++ s_op.addr2_reg = op->addr.val >> 16 & 0xff;
++ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
++ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
++ snandc->qspi->cmd = cpu_to_le32(cmd);
++ return qcom_spi_program_execute(snandc, op);
++ case SPINAND_READ:
++ s_op.addr1_reg = (op->addr.val << 16);
++ s_op.addr2_reg = op->addr.val >> 16 & 0xff;
++ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
++ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
++ snandc->qspi->cmd = cpu_to_le32(cmd);
++ return 0;
++ case SPINAND_ERASE:
++ s_op.addr2_reg = (op->addr.val >> 16) & 0xffff;
++ s_op.addr1_reg = op->addr.val;
++ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16);
++ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
++ snandc->qspi->cmd = cpu_to_le32(cmd);
++ qcom_spi_block_erase(snandc);
++ return 0;
++ default:
++ break;
++ }
++
++ snandc->buf_count = 0;
++ snandc->buf_start = 0;
++ qcom_clear_read_regs(snandc);
++ qcom_clear_bam_transaction(snandc);
++
++ snandc->regs->cmd = cpu_to_le32(s_op.cmd_reg);
++ snandc->regs->exec = cpu_to_le32(1);
++ snandc->regs->addr0 = cpu_to_le32(s_op.addr1_reg);
++ snandc->regs->addr1 = cpu_to_le32(s_op.addr2_reg);
++
++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++ ret = qcom_submit_descs(snandc);
++ if (ret)
++ dev_err(snandc->dev, "failure in submitting cmd descriptor\n");
++
++ return ret;
++}
++
++static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_mem_op *op)
++{
++ int ret, val, opcode;
++ bool copy = false, copy_ftr = false;
++
++ ret = qcom_spi_send_cmdaddr(snandc, op);
++ if (ret)
++ return ret;
++
++ snandc->buf_count = 0;
++ snandc->buf_start = 0;
++ qcom_clear_read_regs(snandc);
++ qcom_clear_bam_transaction(snandc);
++ opcode = op->cmd.opcode;
++
++ switch (opcode) {
++ case SPINAND_READID:
++ snandc->buf_count = 4;
++ qcom_read_reg_dma(snandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
++ copy = true;
++ break;
++ case SPINAND_GET_FEATURE:
++ snandc->buf_count = 4;
++ qcom_read_reg_dma(snandc, NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
++ copy_ftr = true;
++ break;
++ case SPINAND_SET_FEATURE:
++ snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out);
++ qcom_write_reg_dma(snandc, &snandc->regs->flash_feature,
++ NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
++ break;
++ case SPINAND_PROGRAM_EXECUTE:
++ case SPINAND_WRITE_EN:
++ case SPINAND_RESET:
++ case SPINAND_ERASE:
++ case SPINAND_READ:
++ return 0;
++ default:
++ return -EOPNOTSUPP;
++ }
++
++ ret = qcom_submit_descs(snandc);
++ if (ret)
++ dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode);
++
++ if (copy) {
++ qcom_nandc_dev_to_mem(snandc, true);
++ memcpy(op->data.buf.in, snandc->reg_read_buf, snandc->buf_count);
++ }
++
++ if (copy_ftr) {
++ qcom_nandc_dev_to_mem(snandc, true);
++ val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf);
++ val >>= 8;
++ memcpy(op->data.buf.in, &val, snandc->buf_count);
++ }
++
++ return ret;
++}
++
++static bool qcom_spi_is_page_op(const struct spi_mem_op *op)
++{
++ if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && op->addr.buswidth != 4)
++ return false;
++
++ if (op->data.dir == SPI_MEM_DATA_IN) {
++ if (op->addr.buswidth == 4 && op->data.buswidth == 4)
++ return true;
++
++ if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
++ return true;
++
++ } else if (op->data.dir == SPI_MEM_DATA_OUT) {
++ if (op->data.buswidth == 4)
++ return true;
++ if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
++ return true;
++ }
++
++ return false;
++}
++
++static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
++{
++ if (!spi_mem_default_supports_op(mem, op))
++ return false;
++
++ if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1)
++ return false;
++
++ if (qcom_spi_is_page_op(op))
++ return true;
++
++ return ((!op->addr.nbytes || op->addr.buswidth == 1) &&
++ (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
++ (!op->data.nbytes || op->data.buswidth == 1));
++}
++
++static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
++{
++ struct qcom_nand_controller *snandc = spi_controller_get_devdata(mem->spi->controller);
++
++ dev_dbg(snandc->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode,
++ op->addr.val, op->addr.buswidth, op->addr.nbytes,
++ op->data.buswidth, op->data.nbytes);
++
++ if (qcom_spi_is_page_op(op)) {
++ if (op->data.dir == SPI_MEM_DATA_IN)
++ return qcom_spi_read_page(snandc, op);
++ if (op->data.dir == SPI_MEM_DATA_OUT)
++ return qcom_spi_write_page(snandc, op);
++ } else {
++ return qcom_spi_io_op(snandc, op);
++ }
++
++ return 0;
++}
++
++static const struct spi_controller_mem_ops qcom_spi_mem_ops = {
++ .supports_op = qcom_spi_supports_op,
++ .exec_op = qcom_spi_exec_op,
++};
++
++static const struct spi_controller_mem_caps qcom_spi_mem_caps = {
++ .ecc = true,
++};
++
++static int qcom_spi_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct spi_controller *ctlr;
++ struct qcom_nand_controller *snandc;
++ struct qpic_spi_nand *qspi;
++ struct qpic_ecc *ecc;
++ struct resource *res;
++ const void *dev_data;
++ int ret;
++
++ ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
++ if (!ecc)
++ return -ENOMEM;
++
++ qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
++ if (!qspi)
++ return -ENOMEM;
++
++ ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false);
++ if (!ctlr)
++ return -ENOMEM;
++
++ platform_set_drvdata(pdev, ctlr);
++
++ snandc = spi_controller_get_devdata(ctlr);
++ qspi->snandc = snandc;
++
++ snandc->dev = dev;
++ snandc->qspi = qspi;
++ snandc->qspi->ctlr = ctlr;
++ snandc->qspi->ecc = ecc;
++
++ dev_data = of_device_get_match_data(dev);
++ if (!dev_data) {
++ dev_err(&pdev->dev, "failed to get device data\n");
++ return -ENODEV;
++ }
++
++ snandc->props = dev_data;
++ snandc->dev = &pdev->dev;
++
++ snandc->core_clk = devm_clk_get(dev, "core");
++ if (IS_ERR(snandc->core_clk))
++ return PTR_ERR(snandc->core_clk);
++
++ snandc->aon_clk = devm_clk_get(dev, "aon");
++ if (IS_ERR(snandc->aon_clk))
++ return PTR_ERR(snandc->aon_clk);
++
++ snandc->qspi->iomacro_clk = devm_clk_get(dev, "iom");
++ if (IS_ERR(snandc->qspi->iomacro_clk))
++ return PTR_ERR(snandc->qspi->iomacro_clk);
++
++ snandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
++ if (IS_ERR(snandc->base))
++ return PTR_ERR(snandc->base);
++
++ snandc->base_phys = res->start;
++ snandc->base_dma = dma_map_resource(dev, res->start, resource_size(res),
++ DMA_BIDIRECTIONAL, 0);
++ if (dma_mapping_error(dev, snandc->base_dma))
++ return -ENXIO;
++
++ ret = clk_prepare_enable(snandc->core_clk);
++ if (ret)
++ goto err_dis_core_clk;
++
++ ret = clk_prepare_enable(snandc->aon_clk);
++ if (ret)
++ goto err_dis_aon_clk;
++
++ ret = clk_prepare_enable(snandc->qspi->iomacro_clk);
++ if (ret)
++ goto err_dis_iom_clk;
++
++ ret = qcom_nandc_alloc(snandc);
++ if (ret)
++ goto err_snand_alloc;
++
++ ret = qcom_spi_init(snandc);
++ if (ret)
++ goto err_spi_init;
++
++ /* setup ECC engine */
++ snandc->qspi->ecc_eng.dev = &pdev->dev;
++ snandc->qspi->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
++ snandc->qspi->ecc_eng.ops = &qcom_spi_ecc_engine_ops_pipelined;
++ snandc->qspi->ecc_eng.priv = snandc;
++
++ ret = nand_ecc_register_on_host_hw_engine(&snandc->qspi->ecc_eng);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to register ecc engine:%d\n", ret);
++ goto err_spi_init;
++ }
++
++ ctlr->num_chipselect = QPIC_QSPI_NUM_CS;
++ ctlr->mem_ops = &qcom_spi_mem_ops;
++ ctlr->mem_caps = &qcom_spi_mem_caps;
++ ctlr->dev.of_node = pdev->dev.of_node;
++ ctlr->mode_bits = SPI_TX_DUAL | SPI_RX_DUAL |
++ SPI_TX_QUAD | SPI_RX_QUAD;
++
++ ret = spi_register_controller(ctlr);
++ if (ret) {
++ dev_err(&pdev->dev, "spi_register_controller failed.\n");
++ goto err_spi_init;
++ }
++
++ return 0;
++
++err_spi_init:
++ qcom_nandc_unalloc(snandc);
++err_snand_alloc:
++ clk_disable_unprepare(snandc->qspi->iomacro_clk);
++err_dis_iom_clk:
++ clk_disable_unprepare(snandc->aon_clk);
++err_dis_aon_clk:
++ clk_disable_unprepare(snandc->core_clk);
++err_dis_core_clk:
++ dma_unmap_resource(dev, res->start, resource_size(res),
++ DMA_BIDIRECTIONAL, 0);
++ return ret;
++}
++
++static void qcom_spi_remove(struct platform_device *pdev)
++{
++ struct spi_controller *ctlr = platform_get_drvdata(pdev);
++ struct qcom_nand_controller *snandc = spi_controller_get_devdata(ctlr);
++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++ spi_unregister_controller(ctlr);
++
++ qcom_nandc_unalloc(snandc);
++
++ clk_disable_unprepare(snandc->aon_clk);
++ clk_disable_unprepare(snandc->core_clk);
++ clk_disable_unprepare(snandc->qspi->iomacro_clk);
++
++ dma_unmap_resource(&pdev->dev, snandc->base_dma, resource_size(res),
++ DMA_BIDIRECTIONAL, 0);
++}
++
++static const struct qcom_nandc_props ipq9574_snandc_props = {
++ .dev_cmd_reg_start = 0x7000,
++ .supports_bam = true,
++};
++
++static const struct of_device_id qcom_snandc_of_match[] = {
++ {
++ .compatible = "qcom,ipq9574-snand",
++ .data = &ipq9574_snandc_props,
++ },
++ {}
++}
++MODULE_DEVICE_TABLE(of, qcom_snandc_of_match);
++
++static struct platform_driver qcom_spi_driver = {
++ .driver = {
++ .name = "qcom_snand",
++ .of_match_table = qcom_snandc_of_match,
++ },
++ .probe = qcom_spi_probe,
++ .remove_new = qcom_spi_remove,
++};
++module_platform_driver(qcom_spi_driver);
++
++MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores");
++MODULE_LICENSE("GPL");
++
+--- a/include/linux/mtd/nand-qpic-common.h
++++ b/include/linux/mtd/nand-qpic-common.h
+@@ -325,6 +325,10 @@ struct nandc_regs {
+ __le32 read_location_last1;
+ __le32 read_location_last2;
+ __le32 read_location_last3;
++ __le32 spi_cfg;
++ __le32 num_addr_cycle;
++ __le32 busy_wait_cnt;
++ __le32 flash_feature;
+
+ __le32 erased_cw_detect_cfg_clr;
+ __le32 erased_cw_detect_cfg_set;
+@@ -339,6 +343,7 @@ struct nandc_regs {
+ *
+ * @core_clk: controller clock
+ * @aon_clk: another controller clock
++ * @iomacro_clk: io macro clock
+ *
+ * @regs: a contiguous chunk of memory for DMA register
+ * writes. contains the register values to be
+@@ -348,6 +353,7 @@ struct nandc_regs {
+ * initialized via DT match data
+ *
+ * @controller: base controller structure
++ * @qspi: qpic spi structure
+ * @host_list: list containing all the chips attached to the
+ * controller
+ *
+@@ -392,6 +398,7 @@ struct qcom_nand_controller {
+ const struct qcom_nandc_props *props;
+
+ struct nand_controller *controller;
++ struct qpic_spi_nand *qspi;
+ struct list_head host_list;
+
+ union {
--- /dev/null
+From cf1ba3cb245020459f2ca446b7a7b199839f5d83 Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Mar 2025 12:40:01 +0300
+Subject: [PATCH] spi: spi-qpic-snand: Fix ECC_CFG_ECC_DISABLE shift in
+ qcom_spi_read_last_cw()
+
+The ECC_CFG_ECC_DISABLE define is BIT(0). It's supposed to be used
+directly instead of used as a shifter.
+
+Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
+---
+ drivers/spi/spi-qpic-snand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -514,7 +514,7 @@ static int qcom_spi_read_last_cw(struct
+ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
+ 0 << CW_PER_PAGE;
+ cfg1 = ecc_cfg->cfg1_raw;
+- ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
++ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
+
+ snandc->regs->cmd = snandc->qspi->cmd;
+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
--- /dev/null
+From d450cdd9c4398add1f2aa7200f2c95f1e3b9f9fa Mon Sep 17 00:00:00 2001
+Date: Thu, 13 Mar 2025 19:31:21 +0100
+Subject: [PATCH] spi: spi-qpic-snand: avoid memleak in
+ qcom_spi_ecc_init_ctx_pipelined()
+
+When the allocation of the OOB buffer fails, the
+qcom_spi_ecc_init_ctx_pipelined() function returns without freeing
+the memory allocated for 'ecc_cfg' thus it can cause a memory leak.
+
+Call kfree() to free 'ecc_cfg' before returning from the function
+to avoid that.
+
+Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
+---
+ drivers/spi/spi-qpic-snand.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -263,8 +263,10 @@ static int qcom_spi_ecc_init_ctx_pipelin
+ return -ENOMEM;
+ snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
+ GFP_KERNEL);
+- if (!snandc->qspi->oob_buf)
++ if (!snandc->qspi->oob_buf) {
++ kfree(ecc_cfg);
+ return -ENOMEM;
++ }
+
+ memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
+
--- /dev/null
+From d32c4e58545f17caaa854415f854691e32d42075 Mon Sep 17 00:00:00 2001
+Date: Wed, 26 Mar 2025 15:22:19 +0100
+Subject: [PATCH] spi: SPI_QPIC_SNAND should be tristate and depend on MTD
+
+SPI_QPIC_SNAND is the only driver that selects MTD instead of depending
+on it, which could lead to circular dependencies. Moreover, as
+SPI_QPIC_SNAND is bool, this forces MTD (and various related symbols) to
+be built-in, as can be seen in an allmodconfig kernel.
+
+Except for a missing semicolon, there is no reason why SPI_QPIC_SNAND
+cannot be tristate; all MODULE_*() boilerplate is already present.
+Hence make SPI_QPIC_SNAND tristate, let it depend on MTD, and add the
+missing semicolon.
+
+Fixes: 7304d1909080ef0c ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
+Link: https://patch.msgid.link/b63db431cbf35223a4400e44c296293d32c4543c.1742998909.git.geert+renesas@glider.be
+---
+ drivers/spi/Kconfig | 4 ++--
+ drivers/spi/spi-qpic-snand.c | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -899,9 +899,9 @@ config SPI_QCOM_QSPI
+ QSPI(Quad SPI) driver for Qualcomm QSPI controller.
+
+ config SPI_QPIC_SNAND
+- bool "QPIC SNAND controller"
++ tristate "QPIC SNAND controller"
+ depends on ARCH_QCOM || COMPILE_TEST
+- select MTD
++ depends on MTD
+ help
+ QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller.
+ QPIC controller supports both parallel nand and serial nand.
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -1614,7 +1614,7 @@ static const struct of_device_id qcom_sn
+ .data = &ipq9574_snandc_props,
+ },
+ {}
+-}
++};
+ MODULE_DEVICE_TABLE(of, qcom_snandc_of_match);
+
+ static struct platform_driver qcom_spi_driver = {
--- /dev/null
+Date: Wed, 23 Apr 2025 21:31:57 +0200
+Subject: [PATCH] spi: spi-qpic-snand: propagate errors from
+ qcom_spi_block_erase()
+
+The qcom_spi_block_erase() function returns with error in case of
+failure. Change the qcom_spi_send_cmdaddr() function to propagate
+these errors to the callers instead of returning with success.
+
+Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
+---
+ drivers/spi/spi-qpic-snand.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+
+---
+base-commit: 9c32cda43eb78f78c73aee4aa344b777714e259b
+change-id: 20250422-qpic-snand-propagate-error-9c95811ab811
+
+Best regards,
+
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -1307,8 +1307,7 @@ static int qcom_spi_send_cmdaddr(struct
+ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16);
+ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
+ snandc->qspi->cmd = cpu_to_le32(cmd);
+- qcom_spi_block_erase(snandc);
+- return 0;
++ return qcom_spi_block_erase(snandc);
+ default:
+ break;
+ }
--- /dev/null
+Date: Mon, 28 Apr 2025 09:30:55 +0200
+Subject: [PATCH] spi: spi-qpic-snand: fix NAND_READ_LOCATION_2 register
+ handling
+
+The precomputed value for the NAND_READ_LOCATION_2 register should be
+stored in 'snandc->regs->read_location2'.
+
+Fix the qcom_spi_set_read_loc_first() function accordingly.
+
+Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
+---
+ drivers/spi/spi-qpic-snand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+
+---
+base-commit: 15cfe55ec58ace931a73e19e5367598734ceb074
+change-id: 20250428-qpic-snand-readloc2-fix-bccd07cf26d3
+
+Best regards,
+
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -142,7 +142,7 @@ static void qcom_spi_set_read_loc_first(
+ else if (reg == NAND_READ_LOCATION_1)
+ snandc->regs->read_location1 = locreg_val;
+ else if (reg == NAND_READ_LOCATION_2)
+- snandc->regs->read_location1 = locreg_val;
++ snandc->regs->read_location2 = locreg_val;
+ else if (reg == NAND_READ_LOCATION_3)
+ snandc->regs->read_location3 = locreg_val;
+ }
--- /dev/null
+From f48d80503504257682e493dc17408f2f0b47bcfa Mon Sep 17 00:00:00 2001
+Date: Thu, 20 Mar 2025 19:11:59 +0100
+Subject: [PATCH] spi: spi-qpic-snand: use kmalloc() for OOB buffer allocation
+
+The qcom_spi_ecc_init_ctx_pipelined() function allocates zeroed
+memory for the OOB buffer, then it fills the buffer with '0xff'
+bytes right after the allocation. In this case zeroing the memory
+during allocation is superfluous, so use kmalloc() instead of
+kzalloc() to avoid that.
+
+---
+ drivers/spi/spi-qpic-snand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -261,7 +261,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
+ ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
+ if (!ecc_cfg)
+ return -ENOMEM;
+- snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
++ snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize,
+ GFP_KERNEL);
+ if (!snandc->qspi->oob_buf) {
+ kfree(ecc_cfg);
--- /dev/null
+Date: Thu, 24 Apr 2025 20:10:59 +0200
+Subject: [PATCH] spi: spi-qpic-snand: remove unused 'wlen' member of
+ 'struct qpic_spi_nand'
+
+The 'wlen' member of the qpic_spi_nand structure is never used in the
+code so remove that.
+
+---
+ drivers/spi/spi-qpic-snand.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+
+---
+base-commit: 9c32cda43eb78f78c73aee4aa344b777714e259b
+change-id: 20250424-qpic-snand-remove-wlen-c0cef3801a7f
+
+Best regards,
+
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -116,7 +116,6 @@ struct qpic_spi_nand {
+ struct nand_ecc_engine ecc_eng;
+ u8 *data_buf;
+ u8 *oob_buf;
+- u32 wlen;
+ __le32 addr1;
+ __le32 addr2;
+ __le32 cmd;
+++ /dev/null
-From 03cb793b26834ddca170ba87057c8f883772dd45 Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2024 00:11:41 +0200
-Subject: [PATCH 1/5] block: add support for defining read-only partitions
-
-Add support for defining read-only partitions and complete support for
-it in the cmdline partition parser as the additional "ro" after a
-partition is scanned but never actually applied.
-
----
- block/blk.h | 1 +
- block/partitions/cmdline.c | 3 +++
- block/partitions/core.c | 3 +++
- 3 files changed, 7 insertions(+)
-
---- a/block/blk.h
-+++ b/block/blk.h
-@@ -556,6 +556,7 @@ void blk_free_ext_minor(unsigned int min
- #define ADDPART_FLAG_NONE 0
- #define ADDPART_FLAG_RAID 1
- #define ADDPART_FLAG_WHOLEDISK 2
-+#define ADDPART_FLAG_READONLY 4
- int bdev_add_partition(struct gendisk *disk, int partno, sector_t start,
- sector_t length);
- int bdev_del_partition(struct gendisk *disk, int partno);
---- a/block/partitions/cmdline.c
-+++ b/block/partitions/cmdline.c
-@@ -237,6 +237,9 @@ static int add_part(int slot, struct cmd
- put_partition(state, slot, subpart->from >> 9,
- subpart->size >> 9);
-
-+ if (subpart->flags & PF_RDONLY)
-+ state->parts[slot].flags |= ADDPART_FLAG_READONLY;
-+
- info = &state->parts[slot].info;
-
- strscpy(info->volname, subpart->name, sizeof(info->volname));
---- a/block/partitions/core.c
-+++ b/block/partitions/core.c
-@@ -373,6 +373,9 @@ static struct block_device *add_partitio
- goto out_del;
- }
-
-+ if (flags & ADDPART_FLAG_READONLY)
-+ bdev_set_flag(bdev, BD_READ_ONLY);
-+
- /* everything is up and running, commence */
- err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
- if (err)
+++ /dev/null
-From e5f587242b6072ffab4f4a084a459a59f3035873 Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2024 00:11:43 +0200
-Subject: [PATCH 3/5] block: introduce add_disk_fwnode()
-
-Introduce add_disk_fwnode() as a replacement of device_add_disk() that
-permits to pass and attach a fwnode to disk dev.
-
-This variant can be useful for eMMC that might have the partition table
-for the disk defined in DT. A parser can later make use of the attached
-fwnode to parse the related table and init the hardcoded partition for
-the disk.
-
-device_add_disk() is converted to a simple wrapper of add_disk_fwnode()
-with the fwnode entry set as NULL.
-
----
- block/genhd.c | 28 ++++++++++++++++++++++++----
- include/linux/blkdev.h | 3 +++
- 2 files changed, 27 insertions(+), 4 deletions(-)
-
---- a/block/genhd.c
-+++ b/block/genhd.c
-@@ -383,16 +383,18 @@ int disk_scan_partitions(struct gendisk
- }
-
- /**
-- * device_add_disk - add disk information to kernel list
-+ * add_disk_fwnode - add disk information to kernel list with fwnode
- * @parent: parent device for the disk
- * @disk: per-device partitioning information
- * @groups: Additional per-device sysfs groups
-+ * @fwnode: attached disk fwnode
- *
- * This function registers the partitioning information in @disk
-- * with the kernel.
-+ * with the kernel. Also attach a fwnode to the disk device.
- */
--int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
-- const struct attribute_group **groups)
-+int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk,
-+ const struct attribute_group **groups,
-+ struct fwnode_handle *fwnode)
-
- {
- struct device *ddev = disk_to_dev(disk);
-@@ -452,6 +454,8 @@ int __must_check device_add_disk(struct
- ddev->parent = parent;
- ddev->groups = groups;
- dev_set_name(ddev, "%s", disk->disk_name);
-+ if (fwnode)
-+ device_set_node(ddev, fwnode);
- if (!(disk->flags & GENHD_FL_HIDDEN))
- ddev->devt = MKDEV(disk->major, disk->first_minor);
- ret = device_add(ddev);
-@@ -553,6 +557,22 @@ out_exit_elevator:
- elevator_exit(disk->queue);
- return ret;
- }
-+EXPORT_SYMBOL_GPL(add_disk_fwnode);
-+
-+/**
-+ * device_add_disk - add disk information to kernel list
-+ * @parent: parent device for the disk
-+ * @disk: per-device partitioning information
-+ * @groups: Additional per-device sysfs groups
-+ *
-+ * This function registers the partitioning information in @disk
-+ * with the kernel.
-+ */
-+int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
-+ const struct attribute_group **groups)
-+{
-+ return add_disk_fwnode(parent, disk, groups, NULL);
-+}
- EXPORT_SYMBOL(device_add_disk);
-
- static void blk_report_disk_dead(struct gendisk *disk, bool surprise)
---- a/include/linux/blkdev.h
-+++ b/include/linux/blkdev.h
-@@ -734,6 +734,9 @@ static inline unsigned int blk_queue_dep
- #define for_each_bio(_bio) \
- for (; _bio; _bio = _bio->bi_next)
-
-+int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk,
-+ const struct attribute_group **groups,
-+ struct fwnode_handle *fwnode);
- int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
- const struct attribute_group **groups);
- static inline int __must_check add_disk(struct gendisk *disk)
+++ /dev/null
-From 45ff6c340ddfc2dade74d5b7a8962c778ab7042c Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2024 00:11:44 +0200
-Subject: [PATCH 4/5] mmc: block: attach partitions fwnode if found in mmc-card
-
-Attach partitions fwnode if found in mmc-card and register disk with it.
-
-This permits block partition to reference the node and register a
-partition table defined in DT for the special case for embedded device
-that doesn't have a partition table flashed but have an hardcoded
-partition table passed from the system.
-
-JEDEC BOOT partition boot0/boot1 are supported but in DT we refer with
-the JEDEC name of boot1 and boot2 to better adhere to documentation.
-
-Also JEDEC GP partition gp0/1/2/3 are supported but in DT we refer with
-the JEDEC name of gp1/2/3/4 to better adhere to documentration.
-
----
- drivers/mmc/core/block.c | 55 +++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 54 insertions(+), 1 deletion(-)
-
---- a/drivers/mmc/core/block.c
-+++ b/drivers/mmc/core/block.c
-@@ -2517,6 +2517,56 @@ static inline int mmc_blk_readonly(struc
- !(card->csd.cmdclass & CCC_BLOCK_WRITE);
- }
-
-+/*
-+ * Search for a declared partitions node for the disk in mmc-card related node.
-+ *
-+ * This is to permit support for partition table defined in DT in special case
-+ * where a partition table is not written in the disk and is expected to be
-+ * passed from the running system.
-+ *
-+ * For the user disk, "partitions" node is searched.
-+ * For the special HW disk, "partitions-" node with the appended name is used
-+ * following this conversion table (to adhere to JEDEC naming)
-+ * - boot0 -> partitions-boot1
-+ * - boot1 -> partitions-boot2
-+ * - gp0 -> partitions-gp1
-+ * - gp1 -> partitions-gp2
-+ * - gp2 -> partitions-gp3
-+ * - gp3 -> partitions-gp4
-+ */
-+static struct fwnode_handle *mmc_blk_get_partitions_node(struct device *mmc_dev,
-+ const char *subname)
-+{
-+ const char *node_name = "partitions";
-+
-+ if (subname) {
-+ mmc_dev = mmc_dev->parent;
-+
-+ /*
-+ * Check if we are allocating a BOOT disk boot0/1 disk.
-+ * In DT we use the JEDEC naming boot1/2.
-+ */
-+ if (!strcmp(subname, "boot0"))
-+ node_name = "partitions-boot1";
-+ if (!strcmp(subname, "boot1"))
-+ node_name = "partitions-boot2";
-+ /*
-+ * Check if we are allocating a GP disk gp0/1/2/3 disk.
-+ * In DT we use the JEDEC naming gp1/2/3/4.
-+ */
-+ if (!strcmp(subname, "gp0"))
-+ node_name = "partitions-gp1";
-+ if (!strcmp(subname, "gp1"))
-+ node_name = "partitions-gp2";
-+ if (!strcmp(subname, "gp2"))
-+ node_name = "partitions-gp3";
-+ if (!strcmp(subname, "gp3"))
-+ node_name = "partitions-gp4";
-+ }
-+
-+ return device_get_named_child_node(mmc_dev, node_name);
-+}
-+
- static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
- struct device *parent,
- sector_t size,
-@@ -2525,6 +2575,7 @@ static struct mmc_blk_data *mmc_blk_allo
- int area_type,
- unsigned int part_type)
- {
-+ struct fwnode_handle *disk_fwnode;
- struct mmc_blk_data *md;
- int devidx, ret;
- char cap_str[10];
-@@ -2626,7 +2677,9 @@ static struct mmc_blk_data *mmc_blk_allo
- /* used in ->open, must be set before add_disk: */
- if (area_type == MMC_BLK_DATA_AREA_MAIN)
- dev_set_drvdata(&card->dev, md);
-- ret = device_add_disk(md->parent, md->disk, mmc_disk_attr_groups);
-+ disk_fwnode = mmc_blk_get_partitions_node(parent, subname);
-+ ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups,
-+ disk_fwnode);
- if (ret)
- goto err_put_disk;
- return md;
+++ /dev/null
-From 884555b557e5e6d41c866e2cd8d7b32f50ec974b Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2024 00:11:45 +0200
-Subject: [PATCH 5/5] block: add support for partition table defined in OF
-
-Add support for partition table defined in Device Tree. Similar to how
-it's done with MTD, add support for defining a fixed partition table in
-device tree.
-
-A common scenario for this is fixed block (eMMC) embedded devices that
-have no MBR or GPT partition table to save storage space. Bootloader
-access the block device with absolute address of data.
-
-This is to complete the functionality with an equivalent implementation
-with providing partition table with bootargs, for case where the booargs
-can't be modified and tweaking the Device Tree is the only solution to
-have an usabe partition table.
-
-The implementation follow the fixed-partitions parser used on MTD
-devices where a "partitions" node is expected to be declared with
-"fixed-partitions" compatible in the OF node of the disk device
-(mmc-card for eMMC for example) and each child node declare a label
-and a reg with offset and size. If label is not declared, the node name
-is used as fallback. Eventually is also possible to declare the read-only
-property to flag the partition as read-only.
-
----
- block/partitions/Kconfig | 9 ++++
- block/partitions/Makefile | 1 +
- block/partitions/check.h | 1 +
- block/partitions/core.c | 3 ++
- block/partitions/of.c | 110 ++++++++++++++++++++++++++++++++++++++
- 5 files changed, 124 insertions(+)
- create mode 100644 block/partitions/of.c
-
---- a/block/partitions/Kconfig
-+++ b/block/partitions/Kconfig
-@@ -270,4 +270,13 @@ config CMDLINE_PARTITION
- Say Y here if you want to read the partition table from bootargs.
- The format for the command line is just like mtdparts.
-
-+config OF_PARTITION
-+ bool "Device Tree partition support" if PARTITION_ADVANCED
-+ depends on OF
-+ help
-+ Say Y here if you want to enable support for partition table
-+ defined in Device Tree. (mainly for eMMC)
-+ The format for the device tree node is just like MTD fixed-partition
-+ schema.
-+
- endmenu
---- a/block/partitions/Makefile
-+++ b/block/partitions/Makefile
-@@ -12,6 +12,7 @@ obj-$(CONFIG_CMDLINE_PARTITION) += cmdli
- obj-$(CONFIG_MAC_PARTITION) += mac.o
- obj-$(CONFIG_LDM_PARTITION) += ldm.o
- obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
-+obj-$(CONFIG_OF_PARTITION) += of.o
- obj-$(CONFIG_OSF_PARTITION) += osf.o
- obj-$(CONFIG_SGI_PARTITION) += sgi.o
- obj-$(CONFIG_SUN_PARTITION) += sun.o
---- a/block/partitions/check.h
-+++ b/block/partitions/check.h
-@@ -62,6 +62,7 @@ int karma_partition(struct parsed_partit
- int ldm_partition(struct parsed_partitions *state);
- int mac_partition(struct parsed_partitions *state);
- int msdos_partition(struct parsed_partitions *state);
-+int of_partition(struct parsed_partitions *state);
- int osf_partition(struct parsed_partitions *state);
- int sgi_partition(struct parsed_partitions *state);
- int sun_partition(struct parsed_partitions *state);
---- a/block/partitions/core.c
-+++ b/block/partitions/core.c
-@@ -43,6 +43,9 @@ static int (*const check_part[])(struct
- #ifdef CONFIG_CMDLINE_PARTITION
- cmdline_partition,
- #endif
-+#ifdef CONFIG_OF_PARTITION
-+ of_partition, /* cmdline have priority to OF */
-+#endif
- #ifdef CONFIG_EFI_PARTITION
- efi_partition, /* this must come before msdos */
- #endif
---- /dev/null
-+++ b/block/partitions/of.c
-@@ -0,0 +1,110 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+#include <linux/blkdev.h>
-+#include <linux/major.h>
-+#include <linux/of.h>
-+#include <linux/string.h>
-+#include "check.h"
-+
-+static int validate_of_partition(struct device_node *np, int slot)
-+{
-+ u64 offset, size;
-+ int len;
-+
-+ const __be32 *reg = of_get_property(np, "reg", &len);
-+ int a_cells = of_n_addr_cells(np);
-+ int s_cells = of_n_size_cells(np);
-+
-+ /* Make sure reg len match the expected addr and size cells */
-+ if (len / sizeof(*reg) != a_cells + s_cells)
-+ return -EINVAL;
-+
-+ /* Validate offset conversion from bytes to sectors */
-+ offset = of_read_number(reg, a_cells);
-+ if (offset % SECTOR_SIZE)
-+ return -EINVAL;
-+
-+ /* Validate size conversion from bytes to sectors */
-+ size = of_read_number(reg + a_cells, s_cells);
-+ if (!size || size % SECTOR_SIZE)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static void add_of_partition(struct parsed_partitions *state, int slot,
-+ struct device_node *np)
-+{
-+ struct partition_meta_info *info;
-+ char tmp[sizeof(info->volname) + 4];
-+ const char *partname;
-+ int len;
-+
-+ const __be32 *reg = of_get_property(np, "reg", &len);
-+ int a_cells = of_n_addr_cells(np);
-+ int s_cells = of_n_size_cells(np);
-+
-+ /* Convert bytes to sector size */
-+ u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE;
-+ u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE;
-+
-+ put_partition(state, slot, offset, size);
-+
-+ if (of_property_read_bool(np, "read-only"))
-+ state->parts[slot].flags |= ADDPART_FLAG_READONLY;
-+
-+ /*
-+ * Follow MTD label logic, search for label property,
-+ * fallback to node name if not found.
-+ */
-+ info = &state->parts[slot].info;
-+ partname = of_get_property(np, "label", &len);
-+ if (!partname)
-+ partname = of_get_property(np, "name", &len);
-+ strscpy(info->volname, partname, sizeof(info->volname));
-+
-+ snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
-+ strlcat(state->pp_buf, tmp, PAGE_SIZE);
-+}
-+
-+int of_partition(struct parsed_partitions *state)
-+{
-+ struct device *ddev = disk_to_dev(state->disk);
-+ struct device_node *np;
-+ int slot;
-+
-+ struct device_node *partitions_np = of_node_get(ddev->of_node);
-+
-+ if (!partitions_np ||
-+ !of_device_is_compatible(partitions_np, "fixed-partitions"))
-+ return 0;
-+
-+ slot = 1;
-+ /* Validate parition offset and size */
-+ for_each_child_of_node(partitions_np, np) {
-+ if (validate_of_partition(np, slot)) {
-+ of_node_put(np);
-+ of_node_put(partitions_np);
-+
-+ return -1;
-+ }
-+
-+ slot++;
-+ }
-+
-+ slot = 1;
-+ for_each_child_of_node(partitions_np, np) {
-+ if (slot >= state->limit) {
-+ of_node_put(np);
-+ break;
-+ }
-+
-+ add_of_partition(state, slot, np);
-+
-+ slot++;
-+ }
-+
-+ strlcat(state->pp_buf, "\n", PAGE_SIZE);
-+
-+ return 1;
-+}
+++ /dev/null
-From ae461cde5c559675fc4c0ba351c7c31ace705f56 Mon Sep 17 00:00:00 2001
-Date: Sun, 10 Nov 2024 22:50:47 +0200
-Subject: [PATCH] mtd: spinand: add support for FORESEE F35SQA001G
-
-Add support for FORESEE F35SQA001G SPI NAND.
-
-Similar to F35SQA002G, but differs in capacity.
-Datasheet:
- - https://cdn.ozdisan.com/ETicaret_Dosya/704795_871495.pdf
-
-Tested on Xiaomi AX3000T flashed with OpenWRT.
-
----
- drivers/mtd/nand/spi/foresee.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/mtd/nand/spi/foresee.c
-+++ b/drivers/mtd/nand/spi/foresee.c
-@@ -81,6 +81,16 @@ static const struct spinand_info foresee
- SPINAND_HAS_QE_BIT,
- SPINAND_ECCINFO(&f35sqa002g_ooblayout,
- f35sqa002g_ecc_get_status)),
-+ SPINAND_INFO("F35SQA001G",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71, 0x71),
-+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
-+ NAND_ECCREQ(1, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ SPINAND_HAS_QE_BIT,
-+ SPINAND_ECCINFO(&f35sqa002g_ooblayout,
-+ f35sqa002g_ecc_get_status)),
- };
-
- static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = {
+++ /dev/null
-From 8c52932da5e6756fa66f52f0720da283fba13aa6 Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Nov 2024 14:45:00 +0530
-Subject: [PATCH 1/4] mtd: rawnand: qcom: cleanup qcom_nandc driver
-
-Perform a global cleanup of the Qualcomm NAND
-controller driver with the following improvements:
-
-- Remove register value indirection API
-
-- Remove set_reg() API
-
-- Convert read_loc_first & read_loc_last macro to functions
-
-- Rename multiple variables
-
----
- drivers/mtd/nand/raw/qcom_nandc.c | 516 ++++++++++++++----------------
- 1 file changed, 234 insertions(+), 282 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -189,17 +189,6 @@
- #define ECC_BCH_4BIT BIT(2)
- #define ECC_BCH_8BIT BIT(3)
-
--#define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc) \
--nandc_set_reg(chip, reg, \
-- ((cw_offset) << READ_LOCATION_OFFSET) | \
-- ((read_size) << READ_LOCATION_SIZE) | \
-- ((is_last_read_loc) << READ_LOCATION_LAST))
--
--#define nandc_set_read_loc_last(chip, reg, cw_offset, read_size, is_last_read_loc) \
--nandc_set_reg(chip, reg, \
-- ((cw_offset) << READ_LOCATION_OFFSET) | \
-- ((read_size) << READ_LOCATION_SIZE) | \
-- ((is_last_read_loc) << READ_LOCATION_LAST))
- /*
- * Returns the actual register address for all NAND_DEV_ registers
- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
-@@ -257,8 +246,6 @@ nandc_set_reg(chip, reg, \
- * @tx_sgl_start - start index in data sgl for tx.
- * @rx_sgl_pos - current index in data sgl for rx.
- * @rx_sgl_start - start index in data sgl for rx.
-- * @wait_second_completion - wait for second DMA desc completion before making
-- * the NAND transfer completion.
- */
- struct bam_transaction {
- struct bam_cmd_element *bam_ce;
-@@ -275,7 +262,6 @@ struct bam_transaction {
- u32 tx_sgl_start;
- u32 rx_sgl_pos;
- u32 rx_sgl_start;
-- bool wait_second_completion;
- };
-
- /*
-@@ -471,9 +457,9 @@ struct qcom_op {
- unsigned int data_instr_idx;
- unsigned int rdy_timeout_ms;
- unsigned int rdy_delay_ns;
-- u32 addr1_reg;
-- u32 addr2_reg;
-- u32 cmd_reg;
-+ __le32 addr1_reg;
-+ __le32 addr2_reg;
-+ __le32 cmd_reg;
- u8 flag;
- };
-
-@@ -549,17 +535,17 @@ struct qcom_nand_host {
- * among different NAND controllers.
- * @ecc_modes - ecc mode for NAND
- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
-- * @is_bam - whether NAND controller is using BAM
-- * @is_qpic - whether NAND CTRL is part of qpic IP
-- * @qpic_v2 - flag to indicate QPIC IP version 2
-+ * @supports_bam - whether NAND controller is using Bus Access Manager (BAM)
-+ * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
-+ * @qpic_version2 - flag to indicate QPIC IP version 2
- * @use_codeword_fixup - whether NAND has different layout for boot partitions
- */
- struct qcom_nandc_props {
- u32 ecc_modes;
- u32 dev_cmd_reg_start;
-- bool is_bam;
-- bool is_qpic;
-- bool qpic_v2;
-+ bool supports_bam;
-+ bool nandc_part_of_qpic;
-+ bool qpic_version2;
- bool use_codeword_fixup;
- };
-
-@@ -613,19 +599,11 @@ static void clear_bam_transaction(struct
- {
- struct bam_transaction *bam_txn = nandc->bam_txn;
-
-- if (!nandc->props->is_bam)
-+ if (!nandc->props->supports_bam)
- return;
-
-- bam_txn->bam_ce_pos = 0;
-- bam_txn->bam_ce_start = 0;
-- bam_txn->cmd_sgl_pos = 0;
-- bam_txn->cmd_sgl_start = 0;
-- bam_txn->tx_sgl_pos = 0;
-- bam_txn->tx_sgl_start = 0;
-- bam_txn->rx_sgl_pos = 0;
-- bam_txn->rx_sgl_start = 0;
-+ memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
- bam_txn->last_data_desc = NULL;
-- bam_txn->wait_second_completion = false;
-
- sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
- QPIC_PER_CW_CMD_SGL);
-@@ -640,46 +618,35 @@ static void qpic_bam_dma_done(void *data
- {
- struct bam_transaction *bam_txn = data;
-
-- /*
-- * In case of data transfer with NAND, 2 callbacks will be generated.
-- * One for command channel and another one for data channel.
-- * If current transaction has data descriptors
-- * (i.e. wait_second_completion is true), then set this to false
-- * and wait for second DMA descriptor completion.
-- */
-- if (bam_txn->wait_second_completion)
-- bam_txn->wait_second_completion = false;
-- else
-- complete(&bam_txn->txn_done);
-+ complete(&bam_txn->txn_done);
- }
-
--static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
-+static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
- {
- return container_of(chip, struct qcom_nand_host, chip);
- }
-
--static inline struct qcom_nand_controller *
-+static struct qcom_nand_controller *
- get_qcom_nand_controller(struct nand_chip *chip)
- {
- return container_of(chip->controller, struct qcom_nand_controller,
- controller);
- }
-
--static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
-+static u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
- {
- return ioread32(nandc->base + offset);
- }
-
--static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
-- u32 val)
-+static void nandc_write(struct qcom_nand_controller *nandc, int offset,
-+ u32 val)
- {
- iowrite32(val, nandc->base + offset);
- }
-
--static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
-- bool is_cpu)
-+static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
- {
-- if (!nandc->props->is_bam)
-+ if (!nandc->props->supports_bam)
- return;
-
- if (is_cpu)
-@@ -694,93 +661,90 @@ static inline void nandc_read_buffer_syn
- DMA_FROM_DEVICE);
- }
-
--static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
--{
-- switch (offset) {
-- case NAND_FLASH_CMD:
-- return ®s->cmd;
-- case NAND_ADDR0:
-- return ®s->addr0;
-- case NAND_ADDR1:
-- return ®s->addr1;
-- case NAND_FLASH_CHIP_SELECT:
-- return ®s->chip_sel;
-- case NAND_EXEC_CMD:
-- return ®s->exec;
-- case NAND_FLASH_STATUS:
-- return ®s->clrflashstatus;
-- case NAND_DEV0_CFG0:
-- return ®s->cfg0;
-- case NAND_DEV0_CFG1:
-- return ®s->cfg1;
-- case NAND_DEV0_ECC_CFG:
-- return ®s->ecc_bch_cfg;
-- case NAND_READ_STATUS:
-- return ®s->clrreadstatus;
-- case NAND_DEV_CMD1:
-- return ®s->cmd1;
-- case NAND_DEV_CMD1_RESTORE:
-- return ®s->orig_cmd1;
-- case NAND_DEV_CMD_VLD:
-- return ®s->vld;
-- case NAND_DEV_CMD_VLD_RESTORE:
-- return ®s->orig_vld;
-- case NAND_EBI2_ECC_BUF_CFG:
-- return ®s->ecc_buf_cfg;
-- case NAND_READ_LOCATION_0:
-- return ®s->read_location0;
-- case NAND_READ_LOCATION_1:
-- return ®s->read_location1;
-- case NAND_READ_LOCATION_2:
-- return ®s->read_location2;
-- case NAND_READ_LOCATION_3:
-- return ®s->read_location3;
-- case NAND_READ_LOCATION_LAST_CW_0:
-- return ®s->read_location_last0;
-- case NAND_READ_LOCATION_LAST_CW_1:
-- return ®s->read_location_last1;
-- case NAND_READ_LOCATION_LAST_CW_2:
-- return ®s->read_location_last2;
-- case NAND_READ_LOCATION_LAST_CW_3:
-- return ®s->read_location_last3;
-- default:
-- return NULL;
-- }
--}
--
--static void nandc_set_reg(struct nand_chip *chip, int offset,
-- u32 val)
--{
-- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-- struct nandc_regs *regs = nandc->regs;
-- __le32 *reg;
--
-- reg = offset_to_nandc_reg(regs, offset);
--
-- if (reg)
-- *reg = cpu_to_le32(val);
--}
--
--/* Helper to check the code word, whether it is last cw or not */
-+/* Helper to check whether this is the last CW or not */
- static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
- {
- return cw == (ecc->steps - 1);
- }
-
-+/**
-+ * nandc_set_read_loc_first() - to set read location first register
-+ * @chip: NAND Private Flash Chip Data
-+ * @reg_base: location register base
-+ * @cw_offset: code word offset
-+ * @read_size: code word read length
-+ * @is_last_read_loc: is this the last read location
-+ *
-+ * This function will set location register value
-+ */
-+static void nandc_set_read_loc_first(struct nand_chip *chip,
-+ int reg_base, u32 cw_offset,
-+ u32 read_size, u32 is_last_read_loc)
-+{
-+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-+ __le32 locreg_val;
-+ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+ ((read_size) << READ_LOCATION_SIZE) |
-+ ((is_last_read_loc) << READ_LOCATION_LAST));
-+
-+ locreg_val = cpu_to_le32(val);
-+
-+ if (reg_base == NAND_READ_LOCATION_0)
-+ nandc->regs->read_location0 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_1)
-+ nandc->regs->read_location1 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_2)
-+ nandc->regs->read_location2 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_3)
-+ nandc->regs->read_location3 = locreg_val;
-+}
-+
-+/**
-+ * nandc_set_read_loc_last - to set read location last register
-+ * @chip: NAND Private Flash Chip Data
-+ * @reg_base: location register base
-+ * @cw_offset: code word offset
-+ * @read_size: code word read length
-+ * @is_last_read_loc: is this the last read location
-+ *
-+ * This function will set location last register value
-+ */
-+static void nandc_set_read_loc_last(struct nand_chip *chip,
-+ int reg_base, u32 cw_offset,
-+ u32 read_size, u32 is_last_read_loc)
-+{
-+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-+ __le32 locreg_val;
-+ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+ ((read_size) << READ_LOCATION_SIZE) |
-+ ((is_last_read_loc) << READ_LOCATION_LAST));
-+
-+ locreg_val = cpu_to_le32(val);
-+
-+ if (reg_base == NAND_READ_LOCATION_LAST_CW_0)
-+ nandc->regs->read_location_last0 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_LAST_CW_1)
-+ nandc->regs->read_location_last1 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_LAST_CW_2)
-+ nandc->regs->read_location_last2 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_LAST_CW_3)
-+ nandc->regs->read_location_last3 = locreg_val;
-+}
-+
- /* helper to configure location register values */
- static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg,
-- int cw_offset, int read_size, int is_last_read_loc)
-+ u32 cw_offset, u32 read_size, u32 is_last_read_loc)
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- int reg_base = NAND_READ_LOCATION_0;
-
-- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
-+ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw))
- reg_base = NAND_READ_LOCATION_LAST_CW_0;
-
- reg_base += reg * 4;
-
-- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
-+ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw))
- return nandc_set_read_loc_last(chip, reg_base, cw_offset,
- read_size, is_last_read_loc);
- else
-@@ -792,12 +756,13 @@ static void nandc_set_read_loc(struct na
- static void set_address(struct qcom_nand_host *host, u16 column, int page)
- {
- struct nand_chip *chip = &host->chip;
-+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
- if (chip->options & NAND_BUSWIDTH_16)
- column >>= 1;
-
-- nandc_set_reg(chip, NAND_ADDR0, page << 16 | column);
-- nandc_set_reg(chip, NAND_ADDR1, page >> 16 & 0xff);
-+ nandc->regs->addr0 = cpu_to_le32(page << 16 | column);
-+ nandc->regs->addr1 = cpu_to_le32(page >> 16 & 0xff);
- }
-
- /*
-@@ -811,41 +776,43 @@ static void set_address(struct qcom_nand
- static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, int cw)
- {
- struct nand_chip *chip = &host->chip;
-- u32 cmd, cfg0, cfg1, ecc_bch_cfg;
-+ __le32 cmd, cfg0, cfg1, ecc_bch_cfg;
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
- if (read) {
- if (host->use_ecc)
-- cmd = OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
-+ cmd = cpu_to_le32(OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE);
- else
-- cmd = OP_PAGE_READ | PAGE_ACC | LAST_PAGE;
-+ cmd = cpu_to_le32(OP_PAGE_READ | PAGE_ACC | LAST_PAGE);
- } else {
-- cmd = OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
-+ cmd = cpu_to_le32(OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE);
- }
-
- if (host->use_ecc) {
-- cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) |
-- (num_cw - 1) << CW_PER_PAGE;
-+ cfg0 = cpu_to_le32((host->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE);
-
-- cfg1 = host->cfg1;
-- ecc_bch_cfg = host->ecc_bch_cfg;
-+ cfg1 = cpu_to_le32(host->cfg1);
-+ ecc_bch_cfg = cpu_to_le32(host->ecc_bch_cfg);
- } else {
-- cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-- (num_cw - 1) << CW_PER_PAGE;
-+ cfg0 = cpu_to_le32((host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE);
-
-- cfg1 = host->cfg1_raw;
-- ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-+ cfg1 = cpu_to_le32(host->cfg1_raw);
-+ ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
- }
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, cmd);
-- nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0);
-- nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1);
-- nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
-- if (!nandc->props->qpic_v2)
-- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
-- nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
-- nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
-+ nandc->regs->cmd = cmd;
-+ nandc->regs->cfg0 = cfg0;
-+ nandc->regs->cfg1 = cfg1;
-+ nandc->regs->ecc_bch_cfg = ecc_bch_cfg;
-+
-+ if (!nandc->props->qpic_version2)
-+ nandc->regs->ecc_buf_cfg = cpu_to_le32(host->ecc_buf_cfg);
-+
-+ nandc->regs->clrflashstatus = cpu_to_le32(host->clrflashstatus);
-+ nandc->regs->clrreadstatus = cpu_to_le32(host->clrreadstatus);
-+ nandc->regs->exec = cpu_to_le32(1);
-
- if (read)
- nandc_set_read_loc(chip, cw, 0, 0, host->use_ecc ?
-@@ -1121,7 +1088,7 @@ static int read_reg_dma(struct qcom_nand
- if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
- first = dev_cmd_reg_addr(nandc, first);
-
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
- num_regs, flags);
-
-@@ -1136,25 +1103,16 @@ static int read_reg_dma(struct qcom_nand
- * write_reg_dma: prepares a descriptor to write a given number of
- * contiguous registers
- *
-+ * @vaddr: contiguous memory from where register value will
-+ * be written
- * @first: offset of the first register in the contiguous block
- * @num_regs: number of registers to write
- * @flags: flags to control DMA descriptor preparation
- */
--static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
-- int num_regs, unsigned int flags)
-+static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-+ int first, int num_regs, unsigned int flags)
- {
- bool flow_control = false;
-- struct nandc_regs *regs = nandc->regs;
-- void *vaddr;
--
-- vaddr = offset_to_nandc_reg(regs, first);
--
-- if (first == NAND_ERASED_CW_DETECT_CFG) {
-- if (flags & NAND_ERASED_CW_SET)
-- vaddr = ®s->erased_cw_detect_cfg_set;
-- else
-- vaddr = ®s->erased_cw_detect_cfg_clr;
-- }
-
- if (first == NAND_EXEC_CMD)
- flags |= NAND_BAM_NWD;
-@@ -1165,7 +1123,7 @@ static int write_reg_dma(struct qcom_nan
- if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
-
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
- num_regs, flags);
-
-@@ -1188,7 +1146,7 @@ static int write_reg_dma(struct qcom_nan
- static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
- const u8 *vaddr, int size, unsigned int flags)
- {
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-
- return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
-@@ -1206,7 +1164,7 @@ static int read_data_dma(struct qcom_nan
- static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
- const u8 *vaddr, int size, unsigned int flags)
- {
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-
- return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
-@@ -1220,13 +1178,14 @@ static void config_nand_page_read(struct
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, NAND_ADDR0, 2, 0);
-- write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
-- if (!nandc->props->qpic_v2)
-- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-- write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
-- write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
-- NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ if (!nandc->props->qpic_version2)
-+ write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
- }
-
- /*
-@@ -1239,16 +1198,16 @@ config_nand_cw_read(struct nand_chip *ch
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-- int reg = NAND_READ_LOCATION_0;
-+ __le32 *reg = &nandc->regs->read_location0;
-
-- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
-- reg = NAND_READ_LOCATION_LAST_CW_0;
-+ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw))
-+ reg = &nandc->regs->read_location_last0;
-
-- if (nandc->props->is_bam)
-- write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL);
-+ if (nandc->props->supports_bam)
-+ write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
- if (use_ecc) {
- read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
-@@ -1279,10 +1238,10 @@ static void config_nand_page_write(struc
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, NAND_ADDR0, 2, 0);
-- write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
-- if (!nandc->props->qpic_v2)
-- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
-+ write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ if (!nandc->props->qpic_version2)
-+ write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1,
- NAND_BAM_NEXT_SGL);
- }
-
-@@ -1294,13 +1253,13 @@ static void config_nand_cw_write(struct
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
-- write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
- }
-
- /* helpers to submit/free our list of dma descriptors */
-@@ -1311,7 +1270,7 @@ static int submit_descs(struct qcom_nand
- struct bam_transaction *bam_txn = nandc->bam_txn;
- int ret = 0;
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
- ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
- if (ret)
-@@ -1336,14 +1295,9 @@ static int submit_descs(struct qcom_nand
- list_for_each_entry(desc, &nandc->desc_list, node)
- cookie = dmaengine_submit(desc->dma_desc);
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
- bam_txn->last_cmd_desc->callback_param = bam_txn;
-- if (bam_txn->last_data_desc) {
-- bam_txn->last_data_desc->callback = qpic_bam_dma_done;
-- bam_txn->last_data_desc->callback_param = bam_txn;
-- bam_txn->wait_second_completion = true;
-- }
-
- dma_async_issue_pending(nandc->tx_chan);
- dma_async_issue_pending(nandc->rx_chan);
-@@ -1365,7 +1319,7 @@ err_unmap_free_desc:
- list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
- list_del(&desc->node);
-
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- dma_unmap_sg(nandc->dev, desc->bam_sgl,
- desc->sgl_cnt, desc->dir);
- else
-@@ -1382,7 +1336,7 @@ err_unmap_free_desc:
- static void clear_read_regs(struct qcom_nand_controller *nandc)
- {
- nandc->reg_read_pos = 0;
-- nandc_read_buffer_sync(nandc, false);
-+ nandc_dev_to_mem(nandc, false);
- }
-
- /*
-@@ -1446,7 +1400,7 @@ static int check_flash_errors(struct qco
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
- int i;
-
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < cw_cnt; i++) {
- u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
-@@ -1476,7 +1430,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *
- clear_read_regs(nandc);
- host->use_ecc = false;
-
-- if (nandc->props->qpic_v2)
-+ if (nandc->props->qpic_version2)
- raw_cw = ecc->steps - 1;
-
- clear_bam_transaction(nandc);
-@@ -1497,7 +1451,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *
- oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
- }
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- nandc_set_read_loc(chip, cw, 0, read_loc, data_size1, 0);
- read_loc += data_size1;
-
-@@ -1621,7 +1575,7 @@ static int parse_read_errors(struct qcom
- u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
-
- buf = (struct read_stats *)nandc->reg_read_buf;
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < ecc->steps; i++, buf++) {
- u32 flash, buffer, erased_cw;
-@@ -1734,7 +1688,7 @@ static int read_page_ecc(struct qcom_nan
- oob_size = host->ecc_bytes_hw + host->spare_bytes;
- }
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- if (data_buf && oob_buf) {
- nandc_set_read_loc(chip, i, 0, 0, data_size, 0);
- nandc_set_read_loc(chip, i, 1, data_size,
-@@ -2455,14 +2409,14 @@ static int qcom_nand_attach_chip(struct
-
- mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
- /* Free the initially allocated BAM transaction for reading the ONFI params */
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- free_bam_transaction(nandc);
-
- nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
- cwperpage);
-
- /* Now allocate the BAM transaction based on updated max_cwperpage */
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- nandc->bam_txn = alloc_bam_transaction(nandc);
- if (!nandc->bam_txn) {
- dev_err(nandc->dev,
-@@ -2522,7 +2476,7 @@ static int qcom_nand_attach_chip(struct
- | ecc_mode << ECC_MODE
- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
-
-- if (!nandc->props->qpic_v2)
-+ if (!nandc->props->qpic_version2)
- host->ecc_buf_cfg = 0x203 << NUM_STEPS;
-
- host->clrflashstatus = FS_READY_BSY_N;
-@@ -2556,7 +2510,7 @@ static int qcom_op_cmd_mapping(struct na
- cmd = OP_FETCH_ID;
- break;
- case NAND_CMD_PARAM:
-- if (nandc->props->qpic_v2)
-+ if (nandc->props->qpic_version2)
- cmd = OP_PAGE_READ_ONFI_READ;
- else
- cmd = OP_PAGE_READ;
-@@ -2609,7 +2563,7 @@ static int qcom_parse_instructions(struc
- if (ret < 0)
- return ret;
-
-- q_op->cmd_reg = ret;
-+ q_op->cmd_reg = cpu_to_le32(ret);
- q_op->rdy_delay_ns = instr->delay_ns;
- break;
-
-@@ -2619,10 +2573,10 @@ static int qcom_parse_instructions(struc
- addrs = &instr->ctx.addr.addrs[offset];
-
- for (i = 0; i < min_t(unsigned int, 4, naddrs); i++)
-- q_op->addr1_reg |= addrs[i] << (i * 8);
-+ q_op->addr1_reg |= cpu_to_le32(addrs[i] << (i * 8));
-
- if (naddrs > 4)
-- q_op->addr2_reg |= addrs[4];
-+ q_op->addr2_reg |= cpu_to_le32(addrs[4]);
-
- q_op->rdy_delay_ns = instr->delay_ns;
- break;
-@@ -2663,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nan
- unsigned long start = jiffies + msecs_to_jiffies(time_ms);
- u32 flash;
-
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
-
- do {
- flash = le32_to_cpu(nandc->reg_read_buf[0]);
-@@ -2706,11 +2660,11 @@ static int qcom_read_status_exec(struct
- clear_read_regs(nandc);
- clear_bam_transaction(nandc);
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
-+ nandc->regs->cmd = q_op.cmd_reg;
-+ nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
- ret = submit_descs(nandc);
-@@ -2719,7 +2673,7 @@ static int qcom_read_status_exec(struct
- goto err_out;
- }
-
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < num_cw; i++) {
- flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
-@@ -2763,16 +2717,14 @@ static int qcom_read_id_type_exec(struct
- clear_read_regs(nandc);
- clear_bam_transaction(nandc);
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
-- nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg);
-- nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg);
-- nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
-- nandc->props->is_bam ? 0 : DM_EN);
-+ nandc->regs->cmd = q_op.cmd_reg;
-+ nandc->regs->addr0 = q_op.addr1_reg;
-+ nandc->regs->addr1 = q_op.addr2_reg;
-+ nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN);
-+ nandc->regs->exec = cpu_to_le32(1);
-
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
--
-- write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
- read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-
-@@ -2786,7 +2738,7 @@ static int qcom_read_id_type_exec(struct
- op_id = q_op.data_instr_idx;
- len = nand_subop_get_data_len(subop, op_id);
-
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
- memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len);
-
- err_out:
-@@ -2807,15 +2759,14 @@ static int qcom_misc_cmd_type_exec(struc
-
- if (q_op.flag == OP_PROGRAM_PAGE) {
- goto wait_rdy;
-- } else if (q_op.cmd_reg == OP_BLOCK_ERASE) {
-- q_op.cmd_reg |= PAGE_ACC | LAST_PAGE;
-- nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg);
-- nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg);
-- nandc_set_reg(chip, NAND_DEV0_CFG0,
-- host->cfg0_raw & ~(7 << CW_PER_PAGE));
-- nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
-+ } else if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE)) {
-+ q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE);
-+ nandc->regs->addr0 = q_op.addr1_reg;
-+ nandc->regs->addr1 = q_op.addr2_reg;
-+ nandc->regs->cfg0 = cpu_to_le32(host->cfg0_raw & ~(7 << CW_PER_PAGE));
-+ nandc->regs->cfg1 = cpu_to_le32(host->cfg1_raw);
- instrs = 3;
-- } else if (q_op.cmd_reg != OP_RESET_DEVICE) {
-+ } else if (q_op.cmd_reg != cpu_to_le32(OP_RESET_DEVICE)) {
- return 0;
- }
-
-@@ -2826,14 +2777,14 @@ static int qcom_misc_cmd_type_exec(struc
- clear_read_regs(nandc);
- clear_bam_transaction(nandc);
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
-+ nandc->regs->cmd = q_op.cmd_reg;
-+ nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
-- if (q_op.cmd_reg == OP_BLOCK_ERASE)
-- write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
-+ if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE))
-+ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
- ret = submit_descs(nandc);
-@@ -2864,7 +2815,7 @@ static int qcom_param_page_type_exec(str
- if (ret)
- return ret;
-
-- q_op.cmd_reg |= PAGE_ACC | LAST_PAGE;
-+ q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE);
-
- nandc->buf_count = 0;
- nandc->buf_start = 0;
-@@ -2872,38 +2823,38 @@ static int qcom_param_page_type_exec(str
- clear_read_regs(nandc);
- clear_bam_transaction(nandc);
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
-+ nandc->regs->cmd = q_op.cmd_reg;
-+ nandc->regs->addr0 = 0;
-+ nandc->regs->addr1 = 0;
-+
-+ nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE |
-+ 512 << UD_SIZE_BYTES |
-+ 5 << NUM_ADDR_CYCLES |
-+ 0 << SPARE_SIZE_BYTES);
-+
-+ nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES |
-+ 0 << CS_ACTIVE_BSY |
-+ 17 << BAD_BLOCK_BYTE_NUM |
-+ 1 << BAD_BLOCK_IN_SPARE_AREA |
-+ 2 << WR_RD_BSY_GAP |
-+ 0 << WIDE_FLASH |
-+ 1 << DEV0_CFG1_ECC_DISABLE);
-
-- nandc_set_reg(chip, NAND_ADDR0, 0);
-- nandc_set_reg(chip, NAND_ADDR1, 0);
-- nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
-- | 512 << UD_SIZE_BYTES
-- | 5 << NUM_ADDR_CYCLES
-- | 0 << SPARE_SIZE_BYTES);
-- nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
-- | 0 << CS_ACTIVE_BSY
-- | 17 << BAD_BLOCK_BYTE_NUM
-- | 1 << BAD_BLOCK_IN_SPARE_AREA
-- | 2 << WR_RD_BSY_GAP
-- | 0 << WIDE_FLASH
-- | 1 << DEV0_CFG1_ECC_DISABLE);
-- if (!nandc->props->qpic_v2)
-- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
-+ if (!nandc->props->qpic_version2)
-+ nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
-
- /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
-- if (!nandc->props->qpic_v2) {
-- nandc_set_reg(chip, NAND_DEV_CMD_VLD,
-- (nandc->vld & ~READ_START_VLD));
-- nandc_set_reg(chip, NAND_DEV_CMD1,
-- (nandc->cmd1 & ~(0xFF << READ_ADDR))
-- | NAND_CMD_PARAM << READ_ADDR);
-+ if (!nandc->props->qpic_version2) {
-+ nandc->regs->vld = cpu_to_le32((nandc->vld & ~READ_START_VLD));
-+ nandc->regs->cmd1 = cpu_to_le32((nandc->cmd1 & ~(0xFF << READ_ADDR))
-+ | NAND_CMD_PARAM << READ_ADDR);
- }
-
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
--
-- if (!nandc->props->qpic_v2) {
-- nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
-- nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
-+ nandc->regs->exec = cpu_to_le32(1);
-+
-+ if (!nandc->props->qpic_version2) {
-+ nandc->regs->orig_cmd1 = cpu_to_le32(nandc->cmd1);
-+ nandc->regs->orig_vld = cpu_to_le32(nandc->vld);
- }
-
- instr = q_op.data_instr;
-@@ -2912,9 +2863,9 @@ static int qcom_param_page_type_exec(str
-
- nandc_set_read_loc(chip, 0, 0, 0, len, 1);
-
-- if (!nandc->props->qpic_v2) {
-- write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
-- write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
-+ if (!nandc->props->qpic_version2) {
-+ write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
- }
-
- nandc->buf_count = len;
-@@ -2926,9 +2877,10 @@ static int qcom_param_page_type_exec(str
- nandc->buf_count, 0);
-
- /* restore CMD1 and VLD regs */
-- if (!nandc->props->qpic_v2) {
-- write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
-- write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
-+ if (!nandc->props->qpic_version2) {
-+ write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
-+ NAND_BAM_NEXT_SGL);
- }
-
- ret = submit_descs(nandc);
-@@ -3017,7 +2969,7 @@ static const struct nand_controller_ops
-
- static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
- {
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
- dma_unmap_single(nandc->dev, nandc->reg_read_dma,
- MAX_REG_RD *
-@@ -3070,7 +3022,7 @@ static int qcom_nandc_alloc(struct qcom_
- if (!nandc->reg_read_buf)
- return -ENOMEM;
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- nandc->reg_read_dma =
- dma_map_single(nandc->dev, nandc->reg_read_buf,
- MAX_REG_RD *
-@@ -3151,15 +3103,15 @@ static int qcom_nandc_setup(struct qcom_
- u32 nand_ctrl;
-
- /* kill onenand */
-- if (!nandc->props->is_qpic)
-+ if (!nandc->props->nandc_part_of_qpic)
- nandc_write(nandc, SFLASHC_BURST_CFG, 0);
-
-- if (!nandc->props->qpic_v2)
-+ if (!nandc->props->qpic_version2)
- nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
- NAND_DEV_CMD_VLD_VAL);
-
- /* enable ADM or BAM DMA */
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- nand_ctrl = nandc_read(nandc, NAND_CTRL);
-
- /*
-@@ -3176,7 +3128,7 @@ static int qcom_nandc_setup(struct qcom_
- }
-
- /* save the original values of these registers */
-- if (!nandc->props->qpic_v2) {
-+ if (!nandc->props->qpic_version2) {
- nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
- nandc->vld = NAND_DEV_CMD_VLD_VAL;
- }
-@@ -3349,7 +3301,7 @@ static int qcom_nandc_parse_dt(struct pl
- struct device_node *np = nandc->dev->of_node;
- int ret;
-
-- if (!nandc->props->is_bam) {
-+ if (!nandc->props->supports_bam) {
- ret = of_property_read_u32(np, "qcom,cmd-crci",
- &nandc->cmd_crci);
- if (ret) {
-@@ -3474,30 +3426,30 @@ static void qcom_nandc_remove(struct pla
-
- static const struct qcom_nandc_props ipq806x_nandc_props = {
- .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
-- .is_bam = false,
-+ .supports_bam = false,
- .use_codeword_fixup = true,
- .dev_cmd_reg_start = 0x0,
- };
-
- static const struct qcom_nandc_props ipq4019_nandc_props = {
- .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
-- .is_bam = true,
-- .is_qpic = true,
-+ .supports_bam = true,
-+ .nandc_part_of_qpic = true,
- .dev_cmd_reg_start = 0x0,
- };
-
- static const struct qcom_nandc_props ipq8074_nandc_props = {
- .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
-- .is_bam = true,
-- .is_qpic = true,
-+ .supports_bam = true,
-+ .nandc_part_of_qpic = true,
- .dev_cmd_reg_start = 0x7000,
- };
-
- static const struct qcom_nandc_props sdx55_nandc_props = {
- .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
-- .is_bam = true,
-- .is_qpic = true,
-- .qpic_v2 = true,
-+ .supports_bam = true,
-+ .nandc_part_of_qpic = true,
-+ .qpic_version2 = true,
- .dev_cmd_reg_start = 0x7000,
- };
-
+++ /dev/null
-From 1d479f5b345e0c3650fec4dddeef9fc6fab30c8b Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Nov 2024 14:45:01 +0530
-Subject: [PATCH 2/4] mtd: rawnand: qcom: Add qcom prefix to common api
-
-Add qcom prefix to all the api which will be commonly
-used by spi nand driver and raw nand driver.
-
----
- drivers/mtd/nand/raw/qcom_nandc.c | 320 +++++++++++++++---------------
- 1 file changed, 160 insertions(+), 160 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -53,7 +53,7 @@
- #define NAND_READ_LOCATION_LAST_CW_2 0xf48
- #define NAND_READ_LOCATION_LAST_CW_3 0xf4c
-
--/* dummy register offsets, used by write_reg_dma */
-+/* dummy register offsets, used by qcom_write_reg_dma */
- #define NAND_DEV_CMD1_RESTORE 0xdead
- #define NAND_DEV_CMD_VLD_RESTORE 0xbeef
-
-@@ -211,7 +211,7 @@
-
- /*
- * Flags used in DMA descriptor preparation helper functions
-- * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
-+ * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
- */
- /* Don't set the EOT in current tx BAM sgl */
- #define NAND_BAM_NO_EOT BIT(0)
-@@ -550,7 +550,7 @@ struct qcom_nandc_props {
- };
-
- /* Frees the BAM transaction memory */
--static void free_bam_transaction(struct qcom_nand_controller *nandc)
-+static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
- {
- struct bam_transaction *bam_txn = nandc->bam_txn;
-
-@@ -559,7 +559,7 @@ static void free_bam_transaction(struct
-
- /* Allocates and Initializes the BAM transaction */
- static struct bam_transaction *
--alloc_bam_transaction(struct qcom_nand_controller *nandc)
-+qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
- {
- struct bam_transaction *bam_txn;
- size_t bam_txn_size;
-@@ -595,7 +595,7 @@ alloc_bam_transaction(struct qcom_nand_c
- }
-
- /* Clears the BAM transaction indexes */
--static void clear_bam_transaction(struct qcom_nand_controller *nandc)
-+static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
- {
- struct bam_transaction *bam_txn = nandc->bam_txn;
-
-@@ -614,7 +614,7 @@ static void clear_bam_transaction(struct
- }
-
- /* Callback for DMA descriptor completion */
--static void qpic_bam_dma_done(void *data)
-+static void qcom_qpic_bam_dma_done(void *data)
- {
- struct bam_transaction *bam_txn = data;
-
-@@ -644,7 +644,7 @@ static void nandc_write(struct qcom_nand
- iowrite32(val, nandc->base + offset);
- }
-
--static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
-+static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
- {
- if (!nandc->props->supports_bam)
- return;
-@@ -824,9 +824,9 @@ static void update_rw_regs(struct qcom_n
- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
- * which will be submitted to DMA engine.
- */
--static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-- struct dma_chan *chan,
-- unsigned long flags)
-+static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-+ struct dma_chan *chan,
-+ unsigned long flags)
- {
- struct desc_info *desc;
- struct scatterlist *sgl;
-@@ -903,9 +903,9 @@ static int prepare_bam_async_desc(struct
- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
- * after the current command element.
- */
--static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-- int reg_off, const void *vaddr,
-- int size, unsigned int flags)
-+static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr,
-+ int size, unsigned int flags)
- {
- int bam_ce_size;
- int i, ret;
-@@ -943,9 +943,9 @@ static int prep_bam_dma_desc_cmd(struct
- bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
-
- if (flags & NAND_BAM_NWD) {
-- ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
-- DMA_PREP_FENCE |
-- DMA_PREP_CMD);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+ DMA_PREP_FENCE |
-+ DMA_PREP_CMD);
- if (ret)
- return ret;
- }
-@@ -958,9 +958,8 @@ static int prep_bam_dma_desc_cmd(struct
- * Prepares the data descriptor for BAM DMA which will be used for NAND
- * data reads and writes.
- */
--static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-- const void *vaddr,
-- int size, unsigned int flags)
-+static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-+ const void *vaddr, int size, unsigned int flags)
- {
- int ret;
- struct bam_transaction *bam_txn = nandc->bam_txn;
-@@ -979,8 +978,8 @@ static int prep_bam_dma_desc_data(struct
- * is not set, form the DMA descriptor
- */
- if (!(flags & NAND_BAM_NO_EOT)) {
-- ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
-- DMA_PREP_INTERRUPT);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+ DMA_PREP_INTERRUPT);
- if (ret)
- return ret;
- }
-@@ -989,9 +988,9 @@ static int prep_bam_dma_desc_data(struct
- return 0;
- }
-
--static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-- int reg_off, const void *vaddr, int size,
-- bool flow_control)
-+static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr, int size,
-+ bool flow_control)
- {
- struct desc_info *desc;
- struct dma_async_tx_descriptor *dma_desc;
-@@ -1069,15 +1068,15 @@ err:
- }
-
- /*
-- * read_reg_dma: prepares a descriptor to read a given number of
-+ * qcom_read_reg_dma: prepares a descriptor to read a given number of
- * contiguous registers to the reg_read_buf pointer
- *
- * @first: offset of the first register in the contiguous block
- * @num_regs: number of registers to read
- * @flags: flags to control DMA descriptor preparation
- */
--static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
-- int num_regs, unsigned int flags)
-+static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
-+ int num_regs, unsigned int flags)
- {
- bool flow_control = false;
- void *vaddr;
-@@ -1089,18 +1088,18 @@ static int read_reg_dma(struct qcom_nand
- first = dev_cmd_reg_addr(nandc, first);
-
- if (nandc->props->supports_bam)
-- return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
-+ return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
- num_regs, flags);
-
- if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
- flow_control = true;
-
-- return prep_adm_dma_desc(nandc, true, first, vaddr,
-+ return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
- num_regs * sizeof(u32), flow_control);
- }
-
- /*
-- * write_reg_dma: prepares a descriptor to write a given number of
-+ * qcom_write_reg_dma: prepares a descriptor to write a given number of
- * contiguous registers
- *
- * @vaddr: contiguous memory from where register value will
-@@ -1109,8 +1108,8 @@ static int read_reg_dma(struct qcom_nand
- * @num_regs: number of registers to write
- * @flags: flags to control DMA descriptor preparation
- */
--static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-- int first, int num_regs, unsigned int flags)
-+static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-+ int first, int num_regs, unsigned int flags)
- {
- bool flow_control = false;
-
-@@ -1124,18 +1123,18 @@ static int write_reg_dma(struct qcom_nan
- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
-
- if (nandc->props->supports_bam)
-- return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
-+ return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
- num_regs, flags);
-
- if (first == NAND_FLASH_CMD)
- flow_control = true;
-
-- return prep_adm_dma_desc(nandc, false, first, vaddr,
-+ return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
- num_regs * sizeof(u32), flow_control);
- }
-
- /*
-- * read_data_dma: prepares a DMA descriptor to transfer data from the
-+ * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the
- * controller's internal buffer to the buffer 'vaddr'
- *
- * @reg_off: offset within the controller's data buffer
-@@ -1143,17 +1142,17 @@ static int write_reg_dma(struct qcom_nan
- * @size: DMA transaction size in bytes
- * @flags: flags to control DMA descriptor preparation
- */
--static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-- const u8 *vaddr, int size, unsigned int flags)
-+static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+ const u8 *vaddr, int size, unsigned int flags)
- {
- if (nandc->props->supports_bam)
-- return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-+ return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-
-- return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
-+ return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
- }
-
- /*
-- * write_data_dma: prepares a DMA descriptor to transfer data from
-+ * qcom_write_data_dma: prepares a DMA descriptor to transfer data from
- * 'vaddr' to the controller's internal buffer
- *
- * @reg_off: offset within the controller's data buffer
-@@ -1161,13 +1160,13 @@ static int read_data_dma(struct qcom_nan
- * @size: DMA transaction size in bytes
- * @flags: flags to control DMA descriptor preparation
- */
--static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-- const u8 *vaddr, int size, unsigned int flags)
-+static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+ const u8 *vaddr, int size, unsigned int flags)
- {
- if (nandc->props->supports_bam)
-- return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-+ return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-
-- return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
-+ return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
- }
-
- /*
-@@ -1178,14 +1177,14 @@ static void config_nand_page_read(struct
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
- if (!nandc->props->qpic_version2)
-- write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr,
-- NAND_ERASED_CW_DETECT_CFG, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set,
-- NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
- }
-
- /*
-@@ -1204,17 +1203,17 @@ config_nand_cw_read(struct nand_chip *ch
- reg = &nandc->regs->read_location_last0;
-
- if (nandc->props->supports_bam)
-- write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
- if (use_ecc) {
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
-- read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-- NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
-+ qcom_read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-+ NAND_BAM_NEXT_SGL);
- } else {
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
- }
- }
-
-@@ -1238,11 +1237,11 @@ static void config_nand_page_write(struc
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
- if (!nandc->props->qpic_version2)
-- write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1,
-- NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1,
-+ NAND_BAM_NEXT_SGL);
- }
-
- /*
-@@ -1253,17 +1252,18 @@ static void config_nand_cw_write(struct
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1,
-+ NAND_BAM_NEXT_SGL);
- }
-
- /* helpers to submit/free our list of dma descriptors */
--static int submit_descs(struct qcom_nand_controller *nandc)
-+static int qcom_submit_descs(struct qcom_nand_controller *nandc)
- {
- struct desc_info *desc, *n;
- dma_cookie_t cookie = 0;
-@@ -1272,21 +1272,21 @@ static int submit_descs(struct qcom_nand
-
- if (nandc->props->supports_bam) {
- if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
-- ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
- if (ret)
- goto err_unmap_free_desc;
- }
-
- if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
-- ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
-- DMA_PREP_INTERRUPT);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+ DMA_PREP_INTERRUPT);
- if (ret)
- goto err_unmap_free_desc;
- }
-
- if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-- ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
-- DMA_PREP_CMD);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+ DMA_PREP_CMD);
- if (ret)
- goto err_unmap_free_desc;
- }
-@@ -1296,7 +1296,7 @@ static int submit_descs(struct qcom_nand
- cookie = dmaengine_submit(desc->dma_desc);
-
- if (nandc->props->supports_bam) {
-- bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
-+ bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
- bam_txn->last_cmd_desc->callback_param = bam_txn;
-
- dma_async_issue_pending(nandc->tx_chan);
-@@ -1314,7 +1314,7 @@ static int submit_descs(struct qcom_nand
- err_unmap_free_desc:
- /*
- * Unmap the dma sg_list and free the desc allocated by both
-- * prepare_bam_async_desc() and prep_adm_dma_desc() functions.
-+ * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
- */
- list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
- list_del(&desc->node);
-@@ -1333,10 +1333,10 @@ err_unmap_free_desc:
- }
-
- /* reset the register read buffer for next NAND operation */
--static void clear_read_regs(struct qcom_nand_controller *nandc)
-+static void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
- {
- nandc->reg_read_pos = 0;
-- nandc_dev_to_mem(nandc, false);
-+ qcom_nandc_dev_to_mem(nandc, false);
- }
-
- /*
-@@ -1400,7 +1400,7 @@ static int check_flash_errors(struct qco
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
- int i;
-
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < cw_cnt; i++) {
- u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
-@@ -1427,13 +1427,13 @@ qcom_nandc_read_cw_raw(struct mtd_info *
- nand_read_page_op(chip, page, 0, NULL, 0);
- nandc->buf_count = 0;
- nandc->buf_start = 0;
-- clear_read_regs(nandc);
-+ qcom_clear_read_regs(nandc);
- host->use_ecc = false;
-
- if (nandc->props->qpic_version2)
- raw_cw = ecc->steps - 1;
-
-- clear_bam_transaction(nandc);
-+ qcom_clear_bam_transaction(nandc);
- set_address(host, host->cw_size * cw, page);
- update_rw_regs(host, 1, true, raw_cw);
- config_nand_page_read(chip);
-@@ -1466,18 +1466,18 @@ qcom_nandc_read_cw_raw(struct mtd_info *
-
- config_nand_cw_read(chip, false, raw_cw);
-
-- read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
-+ qcom_read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
- reg_off += data_size1;
-
-- read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
-+ qcom_read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
- reg_off += oob_size1;
-
-- read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
-+ qcom_read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
- reg_off += data_size2;
-
-- read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
-+ qcom_read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to read raw cw %d\n", cw);
- return ret;
-@@ -1575,7 +1575,7 @@ static int parse_read_errors(struct qcom
- u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
-
- buf = (struct read_stats *)nandc->reg_read_buf;
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < ecc->steps; i++, buf++) {
- u32 flash, buffer, erased_cw;
-@@ -1704,8 +1704,8 @@ static int read_page_ecc(struct qcom_nan
- config_nand_cw_read(chip, true, i);
-
- if (data_buf)
-- read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
-- data_size, 0);
-+ qcom_read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
-+ data_size, 0);
-
- /*
- * when ecc is enabled, the controller doesn't read the real
-@@ -1720,8 +1720,8 @@ static int read_page_ecc(struct qcom_nan
- for (j = 0; j < host->bbm_size; j++)
- *oob_buf++ = 0xff;
-
-- read_data_dma(nandc, FLASH_BUF_ACC + data_size,
-- oob_buf, oob_size, 0);
-+ qcom_read_data_dma(nandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
- }
-
- if (data_buf)
-@@ -1730,7 +1730,7 @@ static int read_page_ecc(struct qcom_nan
- oob_buf += oob_size;
- }
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to read page/oob\n");
- return ret;
-@@ -1751,7 +1751,7 @@ static int copy_last_cw(struct qcom_nand
- int size;
- int ret;
-
-- clear_read_regs(nandc);
-+ qcom_clear_read_regs(nandc);
-
- size = host->use_ecc ? host->cw_data : host->cw_size;
-
-@@ -1763,9 +1763,9 @@ static int copy_last_cw(struct qcom_nand
-
- config_nand_single_cw_page_read(chip, host->use_ecc, ecc->steps - 1);
-
-- read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
-+ qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret)
- dev_err(nandc->dev, "failed to copy last codeword\n");
-
-@@ -1851,14 +1851,14 @@ static int qcom_nandc_read_page(struct n
- nandc->buf_count = 0;
- nandc->buf_start = 0;
- host->use_ecc = true;
-- clear_read_regs(nandc);
-+ qcom_clear_read_regs(nandc);
- set_address(host, 0, page);
- update_rw_regs(host, ecc->steps, true, 0);
-
- data_buf = buf;
- oob_buf = oob_required ? chip->oob_poi : NULL;
-
-- clear_bam_transaction(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- return read_page_ecc(host, data_buf, oob_buf, page);
- }
-@@ -1899,8 +1899,8 @@ static int qcom_nandc_read_oob(struct na
- if (host->nr_boot_partitions)
- qcom_nandc_codeword_fixup(host, page);
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- host->use_ecc = true;
- set_address(host, 0, page);
-@@ -1927,8 +1927,8 @@ static int qcom_nandc_write_page(struct
- set_address(host, 0, page);
- nandc->buf_count = 0;
- nandc->buf_start = 0;
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- data_buf = (u8 *)buf;
- oob_buf = chip->oob_poi;
-@@ -1949,8 +1949,8 @@ static int qcom_nandc_write_page(struct
- oob_size = ecc->bytes;
- }
-
-- write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
-- i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
-+ qcom_write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
-+ i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
-
- /*
- * when ECC is enabled, we don't really need to write anything
-@@ -1962,8 +1962,8 @@ static int qcom_nandc_write_page(struct
- if (qcom_nandc_is_last_cw(ecc, i)) {
- oob_buf += host->bbm_size;
-
-- write_data_dma(nandc, FLASH_BUF_ACC + data_size,
-- oob_buf, oob_size, 0);
-+ qcom_write_data_dma(nandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
- }
-
- config_nand_cw_write(chip);
-@@ -1972,7 +1972,7 @@ static int qcom_nandc_write_page(struct
- oob_buf += oob_size;
- }
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to write page\n");
- return ret;
-@@ -1997,8 +1997,8 @@ static int qcom_nandc_write_page_raw(str
- qcom_nandc_codeword_fixup(host, page);
-
- nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- data_buf = (u8 *)buf;
- oob_buf = chip->oob_poi;
-@@ -2024,28 +2024,28 @@ static int qcom_nandc_write_page_raw(str
- oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
- }
-
-- write_data_dma(nandc, reg_off, data_buf, data_size1,
-- NAND_BAM_NO_EOT);
-+ qcom_write_data_dma(nandc, reg_off, data_buf, data_size1,
-+ NAND_BAM_NO_EOT);
- reg_off += data_size1;
- data_buf += data_size1;
-
-- write_data_dma(nandc, reg_off, oob_buf, oob_size1,
-- NAND_BAM_NO_EOT);
-+ qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size1,
-+ NAND_BAM_NO_EOT);
- reg_off += oob_size1;
- oob_buf += oob_size1;
-
-- write_data_dma(nandc, reg_off, data_buf, data_size2,
-- NAND_BAM_NO_EOT);
-+ qcom_write_data_dma(nandc, reg_off, data_buf, data_size2,
-+ NAND_BAM_NO_EOT);
- reg_off += data_size2;
- data_buf += data_size2;
-
-- write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
-+ qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
- oob_buf += oob_size2;
-
- config_nand_cw_write(chip);
- }
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to write raw page\n");
- return ret;
-@@ -2075,7 +2075,7 @@ static int qcom_nandc_write_oob(struct n
- qcom_nandc_codeword_fixup(host, page);
-
- host->use_ecc = true;
-- clear_bam_transaction(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- /* calculate the data and oob size for the last codeword/step */
- data_size = ecc->size - ((ecc->steps - 1) << 2);
-@@ -2090,11 +2090,11 @@ static int qcom_nandc_write_oob(struct n
- update_rw_regs(host, 1, false, 0);
-
- config_nand_page_write(chip);
-- write_data_dma(nandc, FLASH_BUF_ACC,
-- nandc->data_buffer, data_size + oob_size, 0);
-+ qcom_write_data_dma(nandc, FLASH_BUF_ACC,
-+ nandc->data_buffer, data_size + oob_size, 0);
- config_nand_cw_write(chip);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to write oob\n");
- return ret;
-@@ -2121,7 +2121,7 @@ static int qcom_nandc_block_bad(struct n
- */
- host->use_ecc = false;
-
-- clear_bam_transaction(nandc);
-+ qcom_clear_bam_transaction(nandc);
- ret = copy_last_cw(host, page);
- if (ret)
- goto err;
-@@ -2148,8 +2148,8 @@ static int qcom_nandc_block_markbad(stru
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- int page, ret;
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- /*
- * to mark the BBM as bad, we flash the entire last codeword with 0s.
-@@ -2166,11 +2166,11 @@ static int qcom_nandc_block_markbad(stru
- update_rw_regs(host, 1, false, ecc->steps - 1);
-
- config_nand_page_write(chip);
-- write_data_dma(nandc, FLASH_BUF_ACC,
-- nandc->data_buffer, host->cw_size, 0);
-+ qcom_write_data_dma(nandc, FLASH_BUF_ACC,
-+ nandc->data_buffer, host->cw_size, 0);
- config_nand_cw_write(chip);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to update BBM\n");
- return ret;
-@@ -2410,14 +2410,14 @@ static int qcom_nand_attach_chip(struct
- mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
- /* Free the initially allocated BAM transaction for reading the ONFI params */
- if (nandc->props->supports_bam)
-- free_bam_transaction(nandc);
-+ qcom_free_bam_transaction(nandc);
-
- nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
- cwperpage);
-
- /* Now allocate the BAM transaction based on updated max_cwperpage */
- if (nandc->props->supports_bam) {
-- nandc->bam_txn = alloc_bam_transaction(nandc);
-+ nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
- if (!nandc->bam_txn) {
- dev_err(nandc->dev,
- "failed to allocate bam transaction\n");
-@@ -2617,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nan
- unsigned long start = jiffies + msecs_to_jiffies(time_ms);
- u32 flash;
-
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
-
- do {
- flash = le32_to_cpu(nandc->reg_read_buf[0]);
-@@ -2657,23 +2657,23 @@ static int qcom_read_status_exec(struct
- nandc->buf_start = 0;
- host->use_ecc = false;
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- nandc->regs->cmd = q_op.cmd_reg;
- nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure in submitting status descriptor\n");
- goto err_out;
- }
-
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < num_cw; i++) {
- flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
-@@ -2714,8 +2714,8 @@ static int qcom_read_id_type_exec(struct
- nandc->buf_start = 0;
- host->use_ecc = false;
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- nandc->regs->cmd = q_op.cmd_reg;
- nandc->regs->addr0 = q_op.addr1_reg;
-@@ -2723,12 +2723,12 @@ static int qcom_read_id_type_exec(struct
- nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN);
- nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-- read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure in submitting read id descriptor\n");
- goto err_out;
-@@ -2738,7 +2738,7 @@ static int qcom_read_id_type_exec(struct
- op_id = q_op.data_instr_idx;
- len = nand_subop_get_data_len(subop, op_id);
-
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
- memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len);
-
- err_out:
-@@ -2774,20 +2774,20 @@ static int qcom_misc_cmd_type_exec(struc
- nandc->buf_start = 0;
- host->use_ecc = false;
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- nandc->regs->cmd = q_op.cmd_reg;
- nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
- if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE))
-- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure in submitting misc descriptor\n");
- goto err_out;
-@@ -2820,8 +2820,8 @@ static int qcom_param_page_type_exec(str
- nandc->buf_count = 0;
- nandc->buf_start = 0;
- host->use_ecc = false;
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- nandc->regs->cmd = q_op.cmd_reg;
- nandc->regs->addr0 = 0;
-@@ -2864,8 +2864,8 @@ static int qcom_param_page_type_exec(str
- nandc_set_read_loc(chip, 0, 0, 0, len, 1);
-
- if (!nandc->props->qpic_version2) {
-- write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
- }
-
- nandc->buf_count = len;
-@@ -2873,17 +2873,17 @@ static int qcom_param_page_type_exec(str
-
- config_nand_single_cw_page_read(chip, false, 0);
-
-- read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
-- nandc->buf_count, 0);
-+ qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
-+ nandc->buf_count, 0);
-
- /* restore CMD1 and VLD regs */
- if (!nandc->props->qpic_version2) {
-- write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
-- NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
-+ NAND_BAM_NEXT_SGL);
- }
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure in submitting param page descriptor\n");
- goto err_out;
-@@ -3067,7 +3067,7 @@ static int qcom_nandc_alloc(struct qcom_
- * maximum codeword size
- */
- nandc->max_cwperpage = 1;
-- nandc->bam_txn = alloc_bam_transaction(nandc);
-+ nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
- if (!nandc->bam_txn) {
- dev_err(nandc->dev,
- "failed to allocate bam transaction\n");
+++ /dev/null
-From fdf3ee5c6e5278dab4f60b998b47ed2d510bf80f Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Nov 2024 14:45:02 +0530
-Subject: [PATCH 3/4] mtd: nand: Add qpic_common API file
-
-Add qpic_common.c file which hold all the common
-qpic APIs which will be used by both qpic raw nand
-driver and qpic spi nand driver.
-
----
- drivers/mtd/nand/Makefile | 2 +-
- drivers/mtd/nand/qpic_common.c | 759 ++++++++++++++++++
- drivers/mtd/nand/raw/qcom_nandc.c | 1092 +-------------------------
- include/linux/mtd/nand-qpic-common.h | 468 +++++++++++
- 4 files changed, 1240 insertions(+), 1081 deletions(-)
- create mode 100644 drivers/mtd/nand/qpic_common.c
- create mode 100644 include/linux/mtd/nand-qpic-common.h
-
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -3,7 +3,7 @@
- nandcore-objs := core.o bbt.o
- obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
- obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
--
-+obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o
- obj-y += onenand/
- obj-y += raw/
- obj-y += spi/
---- /dev/null
-+++ b/drivers/mtd/nand/qpic_common.c
-@@ -0,0 +1,759 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved
-+ */
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/dmaengine.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma/qcom_adm.h>
-+#include <linux/dma/qcom_bam_dma.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/nand-qpic-common.h>
-+
-+/**
-+ * qcom_free_bam_transaction() - Frees the BAM transaction memory
-+ * @nandc: qpic nand controller
-+ *
-+ * This function frees the bam transaction memory
-+ */
-+void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
-+{
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+ kfree(bam_txn);
-+}
-+EXPORT_SYMBOL(qcom_free_bam_transaction);
-+
-+/**
-+ * qcom_alloc_bam_transaction() - allocate BAM transaction
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will allocate and initialize the BAM transaction structure
-+ */
-+struct bam_transaction *
-+qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
-+{
-+ struct bam_transaction *bam_txn;
-+ size_t bam_txn_size;
-+ unsigned int num_cw = nandc->max_cwperpage;
-+ void *bam_txn_buf;
-+
-+ bam_txn_size =
-+ sizeof(*bam_txn) + num_cw *
-+ ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
-+ (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
-+ (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
-+
-+ bam_txn_buf = kzalloc(bam_txn_size, GFP_KERNEL);
-+ if (!bam_txn_buf)
-+ return NULL;
-+
-+ bam_txn = bam_txn_buf;
-+ bam_txn_buf += sizeof(*bam_txn);
-+
-+ bam_txn->bam_ce = bam_txn_buf;
-+ bam_txn_buf +=
-+ sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
-+
-+ bam_txn->cmd_sgl = bam_txn_buf;
-+ bam_txn_buf +=
-+ sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
-+
-+ bam_txn->data_sgl = bam_txn_buf;
-+
-+ init_completion(&bam_txn->txn_done);
-+
-+ return bam_txn;
-+}
-+EXPORT_SYMBOL(qcom_alloc_bam_transaction);
-+
-+/**
-+ * qcom_clear_bam_transaction() - Clears the BAM transaction
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will clear the BAM transaction indexes.
-+ */
-+void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
-+{
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+ if (!nandc->props->supports_bam)
-+ return;
-+
-+ memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
-+ bam_txn->last_data_desc = NULL;
-+
-+ sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
-+ QPIC_PER_CW_CMD_SGL);
-+ sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
-+ QPIC_PER_CW_DATA_SGL);
-+
-+ reinit_completion(&bam_txn->txn_done);
-+}
-+EXPORT_SYMBOL(qcom_clear_bam_transaction);
-+
-+/**
-+ * qcom_qpic_bam_dma_done() - Callback for DMA descriptor completion
-+ * @data: data pointer
-+ *
-+ * This function is a callback for DMA descriptor completion
-+ */
-+void qcom_qpic_bam_dma_done(void *data)
-+{
-+ struct bam_transaction *bam_txn = data;
-+
-+ complete(&bam_txn->txn_done);
-+}
-+EXPORT_SYMBOL(qcom_qpic_bam_dma_done);
-+
-+/**
-+ * qcom_nandc_dev_to_mem() - Check for dma sync for cpu or device
-+ * @nandc: qpic nand controller
-+ * @is_cpu: cpu or Device
-+ *
-+ * This function will check for dma sync for cpu or device
-+ */
-+inline void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
-+{
-+ if (!nandc->props->supports_bam)
-+ return;
-+
-+ if (is_cpu)
-+ dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
-+ MAX_REG_RD *
-+ sizeof(*nandc->reg_read_buf),
-+ DMA_FROM_DEVICE);
-+ else
-+ dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
-+ MAX_REG_RD *
-+ sizeof(*nandc->reg_read_buf),
-+ DMA_FROM_DEVICE);
-+}
-+EXPORT_SYMBOL(qcom_nandc_dev_to_mem);
-+
-+/**
-+ * qcom_prepare_bam_async_desc() - Prepare DMA descriptor
-+ * @nandc: qpic nand controller
-+ * @chan: dma channel
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function maps the scatter gather list for DMA transfer and forms the
-+ * DMA descriptor for BAM.This descriptor will be added in the NAND DMA
-+ * descriptor queue which will be submitted to DMA engine.
-+ */
-+int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-+ struct dma_chan *chan, unsigned long flags)
-+{
-+ struct desc_info *desc;
-+ struct scatterlist *sgl;
-+ unsigned int sgl_cnt;
-+ int ret;
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+ enum dma_transfer_direction dir_eng;
-+ struct dma_async_tx_descriptor *dma_desc;
-+
-+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-+ if (!desc)
-+ return -ENOMEM;
-+
-+ if (chan == nandc->cmd_chan) {
-+ sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
-+ sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
-+ bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
-+ dir_eng = DMA_MEM_TO_DEV;
-+ desc->dir = DMA_TO_DEVICE;
-+ } else if (chan == nandc->tx_chan) {
-+ sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
-+ sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
-+ bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
-+ dir_eng = DMA_MEM_TO_DEV;
-+ desc->dir = DMA_TO_DEVICE;
-+ } else {
-+ sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
-+ sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
-+ bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
-+ dir_eng = DMA_DEV_TO_MEM;
-+ desc->dir = DMA_FROM_DEVICE;
-+ }
-+
-+ sg_mark_end(sgl + sgl_cnt - 1);
-+ ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-+ if (ret == 0) {
-+ dev_err(nandc->dev, "failure in mapping desc\n");
-+ kfree(desc);
-+ return -ENOMEM;
-+ }
-+
-+ desc->sgl_cnt = sgl_cnt;
-+ desc->bam_sgl = sgl;
-+
-+ dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
-+ flags);
-+
-+ if (!dma_desc) {
-+ dev_err(nandc->dev, "failure in prep desc\n");
-+ dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-+ kfree(desc);
-+ return -EINVAL;
-+ }
-+
-+ desc->dma_desc = dma_desc;
-+
-+ /* update last data/command descriptor */
-+ if (chan == nandc->cmd_chan)
-+ bam_txn->last_cmd_desc = dma_desc;
-+ else
-+ bam_txn->last_data_desc = dma_desc;
-+
-+ list_add_tail(&desc->node, &nandc->desc_list);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(qcom_prepare_bam_async_desc);
-+
-+/**
-+ * qcom_prep_bam_dma_desc_cmd() - Prepares the command descriptor for BAM DMA
-+ * @nandc: qpic nand controller
-+ * @read: read or write type
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares the command descriptor for BAM DMA
-+ * which will be used for NAND register reads and writes.
-+ */
-+int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr,
-+ int size, unsigned int flags)
-+{
-+ int bam_ce_size;
-+ int i, ret;
-+ struct bam_cmd_element *bam_ce_buffer;
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
-+
-+ /* fill the command desc */
-+ for (i = 0; i < size; i++) {
-+ if (read)
-+ bam_prep_ce(&bam_ce_buffer[i],
-+ nandc_reg_phys(nandc, reg_off + 4 * i),
-+ BAM_READ_COMMAND,
-+ reg_buf_dma_addr(nandc,
-+ (__le32 *)vaddr + i));
-+ else
-+ bam_prep_ce_le32(&bam_ce_buffer[i],
-+ nandc_reg_phys(nandc, reg_off + 4 * i),
-+ BAM_WRITE_COMMAND,
-+ *((__le32 *)vaddr + i));
-+ }
-+
-+ bam_txn->bam_ce_pos += size;
-+
-+ /* use the separate sgl after this command */
-+ if (flags & NAND_BAM_NEXT_SGL) {
-+ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
-+ bam_ce_size = (bam_txn->bam_ce_pos -
-+ bam_txn->bam_ce_start) *
-+ sizeof(struct bam_cmd_element);
-+ sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
-+ bam_ce_buffer, bam_ce_size);
-+ bam_txn->cmd_sgl_pos++;
-+ bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
-+
-+ if (flags & NAND_BAM_NWD) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+ DMA_PREP_FENCE | DMA_PREP_CMD);
-+ if (ret)
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(qcom_prep_bam_dma_desc_cmd);
-+
-+/**
-+ * qcom_prep_bam_dma_desc_data() - Prepares the data descriptor for BAM DMA
-+ * @nandc: qpic nand controller
-+ * @read: read or write type
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares the data descriptor for BAM DMA which
-+ * will be used for NAND data reads and writes.
-+ */
-+int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-+ const void *vaddr, int size, unsigned int flags)
-+{
-+ int ret;
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+ if (read) {
-+ sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
-+ vaddr, size);
-+ bam_txn->rx_sgl_pos++;
-+ } else {
-+ sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
-+ vaddr, size);
-+ bam_txn->tx_sgl_pos++;
-+
-+ /*
-+ * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
-+ * is not set, form the DMA descriptor
-+ */
-+ if (!(flags & NAND_BAM_NO_EOT)) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+ DMA_PREP_INTERRUPT);
-+ if (ret)
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(qcom_prep_bam_dma_desc_data);
-+
-+/**
-+ * qcom_prep_adm_dma_desc() - Prepare descriptor for adma
-+ * @nandc: qpic nand controller
-+ * @read: read or write type
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: adm dma transaction size in bytes
-+ * @flow_control: flow controller
-+ *
-+ * This function will prepare descriptor for adma
-+ */
-+int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr, int size,
-+ bool flow_control)
-+{
-+ struct qcom_adm_peripheral_config periph_conf = {};
-+ struct dma_async_tx_descriptor *dma_desc;
-+ struct dma_slave_config slave_conf = {0};
-+ enum dma_transfer_direction dir_eng;
-+ struct desc_info *desc;
-+ struct scatterlist *sgl;
-+ int ret;
-+
-+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-+ if (!desc)
-+ return -ENOMEM;
-+
-+ sgl = &desc->adm_sgl;
-+
-+ sg_init_one(sgl, vaddr, size);
-+
-+ if (read) {
-+ dir_eng = DMA_DEV_TO_MEM;
-+ desc->dir = DMA_FROM_DEVICE;
-+ } else {
-+ dir_eng = DMA_MEM_TO_DEV;
-+ desc->dir = DMA_TO_DEVICE;
-+ }
-+
-+ ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
-+ if (!ret) {
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+
-+ slave_conf.device_fc = flow_control;
-+ if (read) {
-+ slave_conf.src_maxburst = 16;
-+ slave_conf.src_addr = nandc->base_dma + reg_off;
-+ if (nandc->data_crci) {
-+ periph_conf.crci = nandc->data_crci;
-+ slave_conf.peripheral_config = &periph_conf;
-+ slave_conf.peripheral_size = sizeof(periph_conf);
-+ }
-+ } else {
-+ slave_conf.dst_maxburst = 16;
-+ slave_conf.dst_addr = nandc->base_dma + reg_off;
-+ if (nandc->cmd_crci) {
-+ periph_conf.crci = nandc->cmd_crci;
-+ slave_conf.peripheral_config = &periph_conf;
-+ slave_conf.peripheral_size = sizeof(periph_conf);
-+ }
-+ }
-+
-+ ret = dmaengine_slave_config(nandc->chan, &slave_conf);
-+ if (ret) {
-+ dev_err(nandc->dev, "failed to configure dma channel\n");
-+ goto err;
-+ }
-+
-+ dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
-+ if (!dma_desc) {
-+ dev_err(nandc->dev, "failed to prepare desc\n");
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ desc->dma_desc = dma_desc;
-+
-+ list_add_tail(&desc->node, &nandc->desc_list);
-+
-+ return 0;
-+err:
-+ kfree(desc);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL(qcom_prep_adm_dma_desc);
-+
-+/**
-+ * qcom_read_reg_dma() - read a given number of registers to the reg_read_buf pointer
-+ * @nandc: qpic nand controller
-+ * @first: offset of the first register in the contiguous block
-+ * @num_regs: number of registers to read
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a descriptor to read a given number of
-+ * contiguous registers to the reg_read_buf pointer.
-+ */
-+int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
-+ int num_regs, unsigned int flags)
-+{
-+ bool flow_control = false;
-+ void *vaddr;
-+
-+ vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
-+ nandc->reg_read_pos += num_regs;
-+
-+ if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
-+ first = dev_cmd_reg_addr(nandc, first);
-+
-+ if (nandc->props->supports_bam)
-+ return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
-+ num_regs, flags);
-+
-+ if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
-+ flow_control = true;
-+
-+ return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
-+ num_regs * sizeof(u32), flow_control);
-+}
-+EXPORT_SYMBOL(qcom_read_reg_dma);
-+
-+/**
-+ * qcom_write_reg_dma() - write a given number of registers
-+ * @nandc: qpic nand controller
-+ * @vaddr: contiguous memory from where register value will
-+ * be written
-+ * @first: offset of the first register in the contiguous block
-+ * @num_regs: number of registers to write
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a descriptor to write a given number of
-+ * contiguous registers
-+ */
-+int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-+ int first, int num_regs, unsigned int flags)
-+{
-+ bool flow_control = false;
-+
-+ if (first == NAND_EXEC_CMD)
-+ flags |= NAND_BAM_NWD;
-+
-+ if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
-+ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
-+
-+ if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
-+ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
-+
-+ if (nandc->props->supports_bam)
-+ return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
-+ num_regs, flags);
-+
-+ if (first == NAND_FLASH_CMD)
-+ flow_control = true;
-+
-+ return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
-+ num_regs * sizeof(u32), flow_control);
-+}
-+EXPORT_SYMBOL(qcom_write_reg_dma);
-+
-+/**
-+ * qcom_read_data_dma() - transfer data
-+ * @nandc: qpic nand controller
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a DMA descriptor to transfer data from the
-+ * controller's internal buffer to the buffer 'vaddr'
-+ */
-+int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+ const u8 *vaddr, int size, unsigned int flags)
-+{
-+ if (nandc->props->supports_bam)
-+ return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-+
-+ return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
-+}
-+EXPORT_SYMBOL(qcom_read_data_dma);
-+
-+/**
-+ * qcom_write_data_dma() - transfer data
-+ * @nandc: qpic nand controller
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to read from
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a DMA descriptor to transfer data from
-+ * 'vaddr' to the controller's internal buffer
-+ */
-+int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+ const u8 *vaddr, int size, unsigned int flags)
-+{
-+ if (nandc->props->supports_bam)
-+ return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-+
-+ return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
-+}
-+EXPORT_SYMBOL(qcom_write_data_dma);
-+
-+/**
-+ * qcom_submit_descs() - submit dma descriptor
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will submit all the prepared dma descriptor
-+ * cmd or data descriptor
-+ */
-+int qcom_submit_descs(struct qcom_nand_controller *nandc)
-+{
-+ struct desc_info *desc, *n;
-+ dma_cookie_t cookie = 0;
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+ int ret = 0;
-+
-+ if (nandc->props->supports_bam) {
-+ if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
-+ if (ret)
-+ goto err_unmap_free_desc;
-+ }
-+
-+ if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+ DMA_PREP_INTERRUPT);
-+ if (ret)
-+ goto err_unmap_free_desc;
-+ }
-+
-+ if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+ DMA_PREP_CMD);
-+ if (ret)
-+ goto err_unmap_free_desc;
-+ }
-+ }
-+
-+ list_for_each_entry(desc, &nandc->desc_list, node)
-+ cookie = dmaengine_submit(desc->dma_desc);
-+
-+ if (nandc->props->supports_bam) {
-+ bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
-+ bam_txn->last_cmd_desc->callback_param = bam_txn;
-+
-+ dma_async_issue_pending(nandc->tx_chan);
-+ dma_async_issue_pending(nandc->rx_chan);
-+ dma_async_issue_pending(nandc->cmd_chan);
-+
-+ if (!wait_for_completion_timeout(&bam_txn->txn_done,
-+ QPIC_NAND_COMPLETION_TIMEOUT))
-+ ret = -ETIMEDOUT;
-+ } else {
-+ if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
-+ ret = -ETIMEDOUT;
-+ }
-+
-+err_unmap_free_desc:
-+ /*
-+ * Unmap the dma sg_list and free the desc allocated by both
-+ * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
-+ */
-+ list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
-+ list_del(&desc->node);
-+
-+ if (nandc->props->supports_bam)
-+ dma_unmap_sg(nandc->dev, desc->bam_sgl,
-+ desc->sgl_cnt, desc->dir);
-+ else
-+ dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
-+ desc->dir);
-+
-+ kfree(desc);
-+ }
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL(qcom_submit_descs);
-+
-+/**
-+ * qcom_clear_read_regs() - reset the read register buffer
-+ * @nandc: qpic nand controller
-+ *
-+ * This function reset the register read buffer for next NAND operation
-+ */
-+void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
-+{
-+ nandc->reg_read_pos = 0;
-+ qcom_nandc_dev_to_mem(nandc, false);
-+}
-+EXPORT_SYMBOL(qcom_clear_read_regs);
-+
-+/**
-+ * qcom_nandc_unalloc() - unallocate qpic nand controller
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will unallocate memory alloacted for qpic nand controller
-+ */
-+void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
-+{
-+ if (nandc->props->supports_bam) {
-+ if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
-+ dma_unmap_single(nandc->dev, nandc->reg_read_dma,
-+ MAX_REG_RD *
-+ sizeof(*nandc->reg_read_buf),
-+ DMA_FROM_DEVICE);
-+
-+ if (nandc->tx_chan)
-+ dma_release_channel(nandc->tx_chan);
-+
-+ if (nandc->rx_chan)
-+ dma_release_channel(nandc->rx_chan);
-+
-+ if (nandc->cmd_chan)
-+ dma_release_channel(nandc->cmd_chan);
-+ } else {
-+ if (nandc->chan)
-+ dma_release_channel(nandc->chan);
-+ }
-+}
-+EXPORT_SYMBOL(qcom_nandc_unalloc);
-+
-+/**
-+ * qcom_nandc_alloc() - Allocate qpic nand controller
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will allocate memory for qpic nand controller
-+ */
-+int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
-+{
-+ int ret;
-+
-+ ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
-+ if (ret) {
-+ dev_err(nandc->dev, "failed to set DMA mask\n");
-+ return ret;
-+ }
-+
-+ /*
-+ * we use the internal buffer for reading ONFI params, reading small
-+ * data like ID and status, and preforming read-copy-write operations
-+ * when writing to a codeword partially. 532 is the maximum possible
-+ * size of a codeword for our nand controller
-+ */
-+ nandc->buf_size = 532;
-+
-+ nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
-+ if (!nandc->data_buffer)
-+ return -ENOMEM;
-+
-+ nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
-+ if (!nandc->regs)
-+ return -ENOMEM;
-+
-+ nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
-+ sizeof(*nandc->reg_read_buf),
-+ GFP_KERNEL);
-+ if (!nandc->reg_read_buf)
-+ return -ENOMEM;
-+
-+ if (nandc->props->supports_bam) {
-+ nandc->reg_read_dma =
-+ dma_map_single(nandc->dev, nandc->reg_read_buf,
-+ MAX_REG_RD *
-+ sizeof(*nandc->reg_read_buf),
-+ DMA_FROM_DEVICE);
-+ if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
-+ dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
-+ return -EIO;
-+ }
-+
-+ nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
-+ if (IS_ERR(nandc->tx_chan)) {
-+ ret = PTR_ERR(nandc->tx_chan);
-+ nandc->tx_chan = NULL;
-+ dev_err_probe(nandc->dev, ret,
-+ "tx DMA channel request failed\n");
-+ goto unalloc;
-+ }
-+
-+ nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
-+ if (IS_ERR(nandc->rx_chan)) {
-+ ret = PTR_ERR(nandc->rx_chan);
-+ nandc->rx_chan = NULL;
-+ dev_err_probe(nandc->dev, ret,
-+ "rx DMA channel request failed\n");
-+ goto unalloc;
-+ }
-+
-+ nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
-+ if (IS_ERR(nandc->cmd_chan)) {
-+ ret = PTR_ERR(nandc->cmd_chan);
-+ nandc->cmd_chan = NULL;
-+ dev_err_probe(nandc->dev, ret,
-+ "cmd DMA channel request failed\n");
-+ goto unalloc;
-+ }
-+
-+ /*
-+ * Initially allocate BAM transaction to read ONFI param page.
-+ * After detecting all the devices, this BAM transaction will
-+ * be freed and the next BAM transaction will be allocated with
-+ * maximum codeword size
-+ */
-+ nandc->max_cwperpage = 1;
-+ nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
-+ if (!nandc->bam_txn) {
-+ dev_err(nandc->dev,
-+ "failed to allocate bam transaction\n");
-+ ret = -ENOMEM;
-+ goto unalloc;
-+ }
-+ } else {
-+ nandc->chan = dma_request_chan(nandc->dev, "rxtx");
-+ if (IS_ERR(nandc->chan)) {
-+ ret = PTR_ERR(nandc->chan);
-+ nandc->chan = NULL;
-+ dev_err_probe(nandc->dev, ret,
-+ "rxtx DMA channel request failed\n");
-+ return ret;
-+ }
-+ }
-+
-+ INIT_LIST_HEAD(&nandc->desc_list);
-+ INIT_LIST_HEAD(&nandc->host_list);
-+
-+ return 0;
-+unalloc:
-+ qcom_nandc_unalloc(nandc);
-+ return ret;
-+}
-+EXPORT_SYMBOL(qcom_nandc_alloc);
-+
-+MODULE_DESCRIPTION("QPIC controller common api");
-+MODULE_LICENSE("GPL");
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -15,417 +15,7 @@
- #include <linux/of.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
--
--/* NANDc reg offsets */
--#define NAND_FLASH_CMD 0x00
--#define NAND_ADDR0 0x04
--#define NAND_ADDR1 0x08
--#define NAND_FLASH_CHIP_SELECT 0x0c
--#define NAND_EXEC_CMD 0x10
--#define NAND_FLASH_STATUS 0x14
--#define NAND_BUFFER_STATUS 0x18
--#define NAND_DEV0_CFG0 0x20
--#define NAND_DEV0_CFG1 0x24
--#define NAND_DEV0_ECC_CFG 0x28
--#define NAND_AUTO_STATUS_EN 0x2c
--#define NAND_DEV1_CFG0 0x30
--#define NAND_DEV1_CFG1 0x34
--#define NAND_READ_ID 0x40
--#define NAND_READ_STATUS 0x44
--#define NAND_DEV_CMD0 0xa0
--#define NAND_DEV_CMD1 0xa4
--#define NAND_DEV_CMD2 0xa8
--#define NAND_DEV_CMD_VLD 0xac
--#define SFLASHC_BURST_CFG 0xe0
--#define NAND_ERASED_CW_DETECT_CFG 0xe8
--#define NAND_ERASED_CW_DETECT_STATUS 0xec
--#define NAND_EBI2_ECC_BUF_CFG 0xf0
--#define FLASH_BUF_ACC 0x100
--
--#define NAND_CTRL 0xf00
--#define NAND_VERSION 0xf08
--#define NAND_READ_LOCATION_0 0xf20
--#define NAND_READ_LOCATION_1 0xf24
--#define NAND_READ_LOCATION_2 0xf28
--#define NAND_READ_LOCATION_3 0xf2c
--#define NAND_READ_LOCATION_LAST_CW_0 0xf40
--#define NAND_READ_LOCATION_LAST_CW_1 0xf44
--#define NAND_READ_LOCATION_LAST_CW_2 0xf48
--#define NAND_READ_LOCATION_LAST_CW_3 0xf4c
--
--/* dummy register offsets, used by qcom_write_reg_dma */
--#define NAND_DEV_CMD1_RESTORE 0xdead
--#define NAND_DEV_CMD_VLD_RESTORE 0xbeef
--
--/* NAND_FLASH_CMD bits */
--#define PAGE_ACC BIT(4)
--#define LAST_PAGE BIT(5)
--
--/* NAND_FLASH_CHIP_SELECT bits */
--#define NAND_DEV_SEL 0
--#define DM_EN BIT(2)
--
--/* NAND_FLASH_STATUS bits */
--#define FS_OP_ERR BIT(4)
--#define FS_READY_BSY_N BIT(5)
--#define FS_MPU_ERR BIT(8)
--#define FS_DEVICE_STS_ERR BIT(16)
--#define FS_DEVICE_WP BIT(23)
--
--/* NAND_BUFFER_STATUS bits */
--#define BS_UNCORRECTABLE_BIT BIT(8)
--#define BS_CORRECTABLE_ERR_MSK 0x1f
--
--/* NAND_DEVn_CFG0 bits */
--#define DISABLE_STATUS_AFTER_WRITE 4
--#define CW_PER_PAGE 6
--#define UD_SIZE_BYTES 9
--#define UD_SIZE_BYTES_MASK GENMASK(18, 9)
--#define ECC_PARITY_SIZE_BYTES_RS 19
--#define SPARE_SIZE_BYTES 23
--#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
--#define NUM_ADDR_CYCLES 27
--#define STATUS_BFR_READ 30
--#define SET_RD_MODE_AFTER_STATUS 31
--
--/* NAND_DEVn_CFG0 bits */
--#define DEV0_CFG1_ECC_DISABLE 0
--#define WIDE_FLASH 1
--#define NAND_RECOVERY_CYCLES 2
--#define CS_ACTIVE_BSY 5
--#define BAD_BLOCK_BYTE_NUM 6
--#define BAD_BLOCK_IN_SPARE_AREA 16
--#define WR_RD_BSY_GAP 17
--#define ENABLE_BCH_ECC 27
--
--/* NAND_DEV0_ECC_CFG bits */
--#define ECC_CFG_ECC_DISABLE 0
--#define ECC_SW_RESET 1
--#define ECC_MODE 4
--#define ECC_PARITY_SIZE_BYTES_BCH 8
--#define ECC_NUM_DATA_BYTES 16
--#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
--#define ECC_FORCE_CLK_OPEN 30
--
--/* NAND_DEV_CMD1 bits */
--#define READ_ADDR 0
--
--/* NAND_DEV_CMD_VLD bits */
--#define READ_START_VLD BIT(0)
--#define READ_STOP_VLD BIT(1)
--#define WRITE_START_VLD BIT(2)
--#define ERASE_START_VLD BIT(3)
--#define SEQ_READ_START_VLD BIT(4)
--
--/* NAND_EBI2_ECC_BUF_CFG bits */
--#define NUM_STEPS 0
--
--/* NAND_ERASED_CW_DETECT_CFG bits */
--#define ERASED_CW_ECC_MASK 1
--#define AUTO_DETECT_RES 0
--#define MASK_ECC BIT(ERASED_CW_ECC_MASK)
--#define RESET_ERASED_DET BIT(AUTO_DETECT_RES)
--#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES)
--#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC)
--#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC)
--
--/* NAND_ERASED_CW_DETECT_STATUS bits */
--#define PAGE_ALL_ERASED BIT(7)
--#define CODEWORD_ALL_ERASED BIT(6)
--#define PAGE_ERASED BIT(5)
--#define CODEWORD_ERASED BIT(4)
--#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED)
--#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
--
--/* NAND_READ_LOCATION_n bits */
--#define READ_LOCATION_OFFSET 0
--#define READ_LOCATION_SIZE 16
--#define READ_LOCATION_LAST 31
--
--/* Version Mask */
--#define NAND_VERSION_MAJOR_MASK 0xf0000000
--#define NAND_VERSION_MAJOR_SHIFT 28
--#define NAND_VERSION_MINOR_MASK 0x0fff0000
--#define NAND_VERSION_MINOR_SHIFT 16
--
--/* NAND OP_CMDs */
--#define OP_PAGE_READ 0x2
--#define OP_PAGE_READ_WITH_ECC 0x3
--#define OP_PAGE_READ_WITH_ECC_SPARE 0x4
--#define OP_PAGE_READ_ONFI_READ 0x5
--#define OP_PROGRAM_PAGE 0x6
--#define OP_PAGE_PROGRAM_WITH_ECC 0x7
--#define OP_PROGRAM_PAGE_SPARE 0x9
--#define OP_BLOCK_ERASE 0xa
--#define OP_CHECK_STATUS 0xc
--#define OP_FETCH_ID 0xb
--#define OP_RESET_DEVICE 0xd
--
--/* Default Value for NAND_DEV_CMD_VLD */
--#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
-- ERASE_START_VLD | SEQ_READ_START_VLD)
--
--/* NAND_CTRL bits */
--#define BAM_MODE_EN BIT(0)
--
--/*
-- * the NAND controller performs reads/writes with ECC in 516 byte chunks.
-- * the driver calls the chunks 'step' or 'codeword' interchangeably
-- */
--#define NANDC_STEP_SIZE 512
--
--/*
-- * the largest page size we support is 8K, this will have 16 steps/codewords
-- * of 512 bytes each
-- */
--#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE)
--
--/* we read at most 3 registers per codeword scan */
--#define MAX_REG_RD (3 * MAX_NUM_STEPS)
--
--/* ECC modes supported by the controller */
--#define ECC_NONE BIT(0)
--#define ECC_RS_4BIT BIT(1)
--#define ECC_BCH_4BIT BIT(2)
--#define ECC_BCH_8BIT BIT(3)
--
--/*
-- * Returns the actual register address for all NAND_DEV_ registers
-- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
-- */
--#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
--
--/* Returns the NAND register physical address */
--#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
--
--/* Returns the dma address for reg read buffer */
--#define reg_buf_dma_addr(chip, vaddr) \
-- ((chip)->reg_read_dma + \
-- ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
--
--#define QPIC_PER_CW_CMD_ELEMENTS 32
--#define QPIC_PER_CW_CMD_SGL 32
--#define QPIC_PER_CW_DATA_SGL 8
--
--#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
--
--/*
-- * Flags used in DMA descriptor preparation helper functions
-- * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
-- */
--/* Don't set the EOT in current tx BAM sgl */
--#define NAND_BAM_NO_EOT BIT(0)
--/* Set the NWD flag in current BAM sgl */
--#define NAND_BAM_NWD BIT(1)
--/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
--#define NAND_BAM_NEXT_SGL BIT(2)
--/*
-- * Erased codeword status is being used two times in single transfer so this
-- * flag will determine the current value of erased codeword status register
-- */
--#define NAND_ERASED_CW_SET BIT(4)
--
--#define MAX_ADDRESS_CYCLE 5
--
--/*
-- * This data type corresponds to the BAM transaction which will be used for all
-- * NAND transfers.
-- * @bam_ce - the array of BAM command elements
-- * @cmd_sgl - sgl for NAND BAM command pipe
-- * @data_sgl - sgl for NAND BAM consumer/producer pipe
-- * @last_data_desc - last DMA desc in data channel (tx/rx).
-- * @last_cmd_desc - last DMA desc in command channel.
-- * @txn_done - completion for NAND transfer.
-- * @bam_ce_pos - the index in bam_ce which is available for next sgl
-- * @bam_ce_start - the index in bam_ce which marks the start position ce
-- * for current sgl. It will be used for size calculation
-- * for current sgl
-- * @cmd_sgl_pos - current index in command sgl.
-- * @cmd_sgl_start - start index in command sgl.
-- * @tx_sgl_pos - current index in data sgl for tx.
-- * @tx_sgl_start - start index in data sgl for tx.
-- * @rx_sgl_pos - current index in data sgl for rx.
-- * @rx_sgl_start - start index in data sgl for rx.
-- */
--struct bam_transaction {
-- struct bam_cmd_element *bam_ce;
-- struct scatterlist *cmd_sgl;
-- struct scatterlist *data_sgl;
-- struct dma_async_tx_descriptor *last_data_desc;
-- struct dma_async_tx_descriptor *last_cmd_desc;
-- struct completion txn_done;
-- u32 bam_ce_pos;
-- u32 bam_ce_start;
-- u32 cmd_sgl_pos;
-- u32 cmd_sgl_start;
-- u32 tx_sgl_pos;
-- u32 tx_sgl_start;
-- u32 rx_sgl_pos;
-- u32 rx_sgl_start;
--};
--
--/*
-- * This data type corresponds to the nand dma descriptor
-- * @dma_desc - low level DMA engine descriptor
-- * @list - list for desc_info
-- *
-- * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
-- * ADM
-- * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
-- * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
-- * @dir - DMA transfer direction
-- */
--struct desc_info {
-- struct dma_async_tx_descriptor *dma_desc;
-- struct list_head node;
--
-- union {
-- struct scatterlist adm_sgl;
-- struct {
-- struct scatterlist *bam_sgl;
-- int sgl_cnt;
-- };
-- };
-- enum dma_data_direction dir;
--};
--
--/*
-- * holds the current register values that we want to write. acts as a contiguous
-- * chunk of memory which we use to write the controller registers through DMA.
-- */
--struct nandc_regs {
-- __le32 cmd;
-- __le32 addr0;
-- __le32 addr1;
-- __le32 chip_sel;
-- __le32 exec;
--
-- __le32 cfg0;
-- __le32 cfg1;
-- __le32 ecc_bch_cfg;
--
-- __le32 clrflashstatus;
-- __le32 clrreadstatus;
--
-- __le32 cmd1;
-- __le32 vld;
--
-- __le32 orig_cmd1;
-- __le32 orig_vld;
--
-- __le32 ecc_buf_cfg;
-- __le32 read_location0;
-- __le32 read_location1;
-- __le32 read_location2;
-- __le32 read_location3;
-- __le32 read_location_last0;
-- __le32 read_location_last1;
-- __le32 read_location_last2;
-- __le32 read_location_last3;
--
-- __le32 erased_cw_detect_cfg_clr;
-- __le32 erased_cw_detect_cfg_set;
--};
--
--/*
-- * NAND controller data struct
-- *
-- * @dev: parent device
-- *
-- * @base: MMIO base
-- *
-- * @core_clk: controller clock
-- * @aon_clk: another controller clock
-- *
-- * @regs: a contiguous chunk of memory for DMA register
-- * writes. contains the register values to be
-- * written to controller
-- *
-- * @props: properties of current NAND controller,
-- * initialized via DT match data
-- *
-- * @controller: base controller structure
-- * @host_list: list containing all the chips attached to the
-- * controller
-- *
-- * @chan: dma channel
-- * @cmd_crci: ADM DMA CRCI for command flow control
-- * @data_crci: ADM DMA CRCI for data flow control
-- *
-- * @desc_list: DMA descriptor list (list of desc_infos)
-- *
-- * @data_buffer: our local DMA buffer for page read/writes,
-- * used when we can't use the buffer provided
-- * by upper layers directly
-- * @reg_read_buf: local buffer for reading back registers via DMA
-- *
-- * @base_phys: physical base address of controller registers
-- * @base_dma: dma base address of controller registers
-- * @reg_read_dma: contains dma address for register read buffer
-- *
-- * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
-- * functions
-- * @max_cwperpage: maximum QPIC codewords required. calculated
-- * from all connected NAND devices pagesize
-- *
-- * @reg_read_pos: marker for data read in reg_read_buf
-- *
-- * @cmd1/vld: some fixed controller register values
-- *
-- * @exec_opwrite: flag to select correct number of code word
-- * while reading status
-- */
--struct qcom_nand_controller {
-- struct device *dev;
--
-- void __iomem *base;
--
-- struct clk *core_clk;
-- struct clk *aon_clk;
--
-- struct nandc_regs *regs;
-- struct bam_transaction *bam_txn;
--
-- const struct qcom_nandc_props *props;
--
-- struct nand_controller controller;
-- struct list_head host_list;
--
-- union {
-- /* will be used only by QPIC for BAM DMA */
-- struct {
-- struct dma_chan *tx_chan;
-- struct dma_chan *rx_chan;
-- struct dma_chan *cmd_chan;
-- };
--
-- /* will be used only by EBI2 for ADM DMA */
-- struct {
-- struct dma_chan *chan;
-- unsigned int cmd_crci;
-- unsigned int data_crci;
-- };
-- };
--
-- struct list_head desc_list;
--
-- u8 *data_buffer;
-- __le32 *reg_read_buf;
--
-- phys_addr_t base_phys;
-- dma_addr_t base_dma;
-- dma_addr_t reg_read_dma;
--
-- int buf_size;
-- int buf_count;
-- int buf_start;
-- unsigned int max_cwperpage;
--
-- int reg_read_pos;
--
-- u32 cmd1, vld;
-- bool exec_opwrite;
--};
-+#include <linux/mtd/nand-qpic-common.h>
-
- /*
- * NAND special boot partitions
-@@ -530,97 +120,6 @@ struct qcom_nand_host {
- bool bch_enabled;
- };
-
--/*
-- * This data type corresponds to the NAND controller properties which varies
-- * among different NAND controllers.
-- * @ecc_modes - ecc mode for NAND
-- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
-- * @supports_bam - whether NAND controller is using Bus Access Manager (BAM)
-- * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
-- * @qpic_version2 - flag to indicate QPIC IP version 2
-- * @use_codeword_fixup - whether NAND has different layout for boot partitions
-- */
--struct qcom_nandc_props {
-- u32 ecc_modes;
-- u32 dev_cmd_reg_start;
-- bool supports_bam;
-- bool nandc_part_of_qpic;
-- bool qpic_version2;
-- bool use_codeword_fixup;
--};
--
--/* Frees the BAM transaction memory */
--static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
--{
-- struct bam_transaction *bam_txn = nandc->bam_txn;
--
-- devm_kfree(nandc->dev, bam_txn);
--}
--
--/* Allocates and Initializes the BAM transaction */
--static struct bam_transaction *
--qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
--{
-- struct bam_transaction *bam_txn;
-- size_t bam_txn_size;
-- unsigned int num_cw = nandc->max_cwperpage;
-- void *bam_txn_buf;
--
-- bam_txn_size =
-- sizeof(*bam_txn) + num_cw *
-- ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
-- (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
-- (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
--
-- bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
-- if (!bam_txn_buf)
-- return NULL;
--
-- bam_txn = bam_txn_buf;
-- bam_txn_buf += sizeof(*bam_txn);
--
-- bam_txn->bam_ce = bam_txn_buf;
-- bam_txn_buf +=
-- sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
--
-- bam_txn->cmd_sgl = bam_txn_buf;
-- bam_txn_buf +=
-- sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
--
-- bam_txn->data_sgl = bam_txn_buf;
--
-- init_completion(&bam_txn->txn_done);
--
-- return bam_txn;
--}
--
--/* Clears the BAM transaction indexes */
--static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
--{
-- struct bam_transaction *bam_txn = nandc->bam_txn;
--
-- if (!nandc->props->supports_bam)
-- return;
--
-- memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
-- bam_txn->last_data_desc = NULL;
--
-- sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
-- QPIC_PER_CW_CMD_SGL);
-- sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
-- QPIC_PER_CW_DATA_SGL);
--
-- reinit_completion(&bam_txn->txn_done);
--}
--
--/* Callback for DMA descriptor completion */
--static void qcom_qpic_bam_dma_done(void *data)
--{
-- struct bam_transaction *bam_txn = data;
--
-- complete(&bam_txn->txn_done);
--}
--
- static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
- {
- return container_of(chip, struct qcom_nand_host, chip);
-@@ -629,8 +128,8 @@ static struct qcom_nand_host *to_qcom_na
- static struct qcom_nand_controller *
- get_qcom_nand_controller(struct nand_chip *chip)
- {
-- return container_of(chip->controller, struct qcom_nand_controller,
-- controller);
-+ return (struct qcom_nand_controller *)
-+ ((u8 *)chip->controller - sizeof(struct qcom_nand_controller));
- }
-
- static u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
-@@ -644,23 +143,6 @@ static void nandc_write(struct qcom_nand
- iowrite32(val, nandc->base + offset);
- }
-
--static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
--{
-- if (!nandc->props->supports_bam)
-- return;
--
-- if (is_cpu)
-- dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
-- MAX_REG_RD *
-- sizeof(*nandc->reg_read_buf),
-- DMA_FROM_DEVICE);
-- else
-- dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
-- MAX_REG_RD *
-- sizeof(*nandc->reg_read_buf),
-- DMA_FROM_DEVICE);
--}
--
- /* Helper to check whether this is the last CW or not */
- static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
- {
-@@ -820,356 +302,6 @@ static void update_rw_regs(struct qcom_n
- }
-
- /*
-- * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
-- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
-- * which will be submitted to DMA engine.
-- */
--static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-- struct dma_chan *chan,
-- unsigned long flags)
--{
-- struct desc_info *desc;
-- struct scatterlist *sgl;
-- unsigned int sgl_cnt;
-- int ret;
-- struct bam_transaction *bam_txn = nandc->bam_txn;
-- enum dma_transfer_direction dir_eng;
-- struct dma_async_tx_descriptor *dma_desc;
--
-- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-- if (!desc)
-- return -ENOMEM;
--
-- if (chan == nandc->cmd_chan) {
-- sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
-- sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
-- bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
-- dir_eng = DMA_MEM_TO_DEV;
-- desc->dir = DMA_TO_DEVICE;
-- } else if (chan == nandc->tx_chan) {
-- sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
-- sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
-- bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
-- dir_eng = DMA_MEM_TO_DEV;
-- desc->dir = DMA_TO_DEVICE;
-- } else {
-- sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
-- sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
-- bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
-- dir_eng = DMA_DEV_TO_MEM;
-- desc->dir = DMA_FROM_DEVICE;
-- }
--
-- sg_mark_end(sgl + sgl_cnt - 1);
-- ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-- if (ret == 0) {
-- dev_err(nandc->dev, "failure in mapping desc\n");
-- kfree(desc);
-- return -ENOMEM;
-- }
--
-- desc->sgl_cnt = sgl_cnt;
-- desc->bam_sgl = sgl;
--
-- dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
-- flags);
--
-- if (!dma_desc) {
-- dev_err(nandc->dev, "failure in prep desc\n");
-- dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-- kfree(desc);
-- return -EINVAL;
-- }
--
-- desc->dma_desc = dma_desc;
--
-- /* update last data/command descriptor */
-- if (chan == nandc->cmd_chan)
-- bam_txn->last_cmd_desc = dma_desc;
-- else
-- bam_txn->last_data_desc = dma_desc;
--
-- list_add_tail(&desc->node, &nandc->desc_list);
--
-- return 0;
--}
--
--/*
-- * Prepares the command descriptor for BAM DMA which will be used for NAND
-- * register reads and writes. The command descriptor requires the command
-- * to be formed in command element type so this function uses the command
-- * element from bam transaction ce array and fills the same with required
-- * data. A single SGL can contain multiple command elements so
-- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
-- * after the current command element.
-- */
--static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-- int reg_off, const void *vaddr,
-- int size, unsigned int flags)
--{
-- int bam_ce_size;
-- int i, ret;
-- struct bam_cmd_element *bam_ce_buffer;
-- struct bam_transaction *bam_txn = nandc->bam_txn;
--
-- bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
--
-- /* fill the command desc */
-- for (i = 0; i < size; i++) {
-- if (read)
-- bam_prep_ce(&bam_ce_buffer[i],
-- nandc_reg_phys(nandc, reg_off + 4 * i),
-- BAM_READ_COMMAND,
-- reg_buf_dma_addr(nandc,
-- (__le32 *)vaddr + i));
-- else
-- bam_prep_ce_le32(&bam_ce_buffer[i],
-- nandc_reg_phys(nandc, reg_off + 4 * i),
-- BAM_WRITE_COMMAND,
-- *((__le32 *)vaddr + i));
-- }
--
-- bam_txn->bam_ce_pos += size;
--
-- /* use the separate sgl after this command */
-- if (flags & NAND_BAM_NEXT_SGL) {
-- bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
-- bam_ce_size = (bam_txn->bam_ce_pos -
-- bam_txn->bam_ce_start) *
-- sizeof(struct bam_cmd_element);
-- sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
-- bam_ce_buffer, bam_ce_size);
-- bam_txn->cmd_sgl_pos++;
-- bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
--
-- if (flags & NAND_BAM_NWD) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-- DMA_PREP_FENCE |
-- DMA_PREP_CMD);
-- if (ret)
-- return ret;
-- }
-- }
--
-- return 0;
--}
--
--/*
-- * Prepares the data descriptor for BAM DMA which will be used for NAND
-- * data reads and writes.
-- */
--static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-- const void *vaddr, int size, unsigned int flags)
--{
-- int ret;
-- struct bam_transaction *bam_txn = nandc->bam_txn;
--
-- if (read) {
-- sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
-- vaddr, size);
-- bam_txn->rx_sgl_pos++;
-- } else {
-- sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
-- vaddr, size);
-- bam_txn->tx_sgl_pos++;
--
-- /*
-- * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
-- * is not set, form the DMA descriptor
-- */
-- if (!(flags & NAND_BAM_NO_EOT)) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-- DMA_PREP_INTERRUPT);
-- if (ret)
-- return ret;
-- }
-- }
--
-- return 0;
--}
--
--static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-- int reg_off, const void *vaddr, int size,
-- bool flow_control)
--{
-- struct desc_info *desc;
-- struct dma_async_tx_descriptor *dma_desc;
-- struct scatterlist *sgl;
-- struct dma_slave_config slave_conf;
-- struct qcom_adm_peripheral_config periph_conf = {};
-- enum dma_transfer_direction dir_eng;
-- int ret;
--
-- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-- if (!desc)
-- return -ENOMEM;
--
-- sgl = &desc->adm_sgl;
--
-- sg_init_one(sgl, vaddr, size);
--
-- if (read) {
-- dir_eng = DMA_DEV_TO_MEM;
-- desc->dir = DMA_FROM_DEVICE;
-- } else {
-- dir_eng = DMA_MEM_TO_DEV;
-- desc->dir = DMA_TO_DEVICE;
-- }
--
-- ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
-- if (ret == 0) {
-- ret = -ENOMEM;
-- goto err;
-- }
--
-- memset(&slave_conf, 0x00, sizeof(slave_conf));
--
-- slave_conf.device_fc = flow_control;
-- if (read) {
-- slave_conf.src_maxburst = 16;
-- slave_conf.src_addr = nandc->base_dma + reg_off;
-- if (nandc->data_crci) {
-- periph_conf.crci = nandc->data_crci;
-- slave_conf.peripheral_config = &periph_conf;
-- slave_conf.peripheral_size = sizeof(periph_conf);
-- }
-- } else {
-- slave_conf.dst_maxburst = 16;
-- slave_conf.dst_addr = nandc->base_dma + reg_off;
-- if (nandc->cmd_crci) {
-- periph_conf.crci = nandc->cmd_crci;
-- slave_conf.peripheral_config = &periph_conf;
-- slave_conf.peripheral_size = sizeof(periph_conf);
-- }
-- }
--
-- ret = dmaengine_slave_config(nandc->chan, &slave_conf);
-- if (ret) {
-- dev_err(nandc->dev, "failed to configure dma channel\n");
-- goto err;
-- }
--
-- dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
-- if (!dma_desc) {
-- dev_err(nandc->dev, "failed to prepare desc\n");
-- ret = -EINVAL;
-- goto err;
-- }
--
-- desc->dma_desc = dma_desc;
--
-- list_add_tail(&desc->node, &nandc->desc_list);
--
-- return 0;
--err:
-- kfree(desc);
--
-- return ret;
--}
--
--/*
-- * qcom_read_reg_dma: prepares a descriptor to read a given number of
-- * contiguous registers to the reg_read_buf pointer
-- *
-- * @first: offset of the first register in the contiguous block
-- * @num_regs: number of registers to read
-- * @flags: flags to control DMA descriptor preparation
-- */
--static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
-- int num_regs, unsigned int flags)
--{
-- bool flow_control = false;
-- void *vaddr;
--
-- vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
-- nandc->reg_read_pos += num_regs;
--
-- if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
-- first = dev_cmd_reg_addr(nandc, first);
--
-- if (nandc->props->supports_bam)
-- return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
-- num_regs, flags);
--
-- if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
-- flow_control = true;
--
-- return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
-- num_regs * sizeof(u32), flow_control);
--}
--
--/*
-- * qcom_write_reg_dma: prepares a descriptor to write a given number of
-- * contiguous registers
-- *
-- * @vaddr: contiguous memory from where register value will
-- * be written
-- * @first: offset of the first register in the contiguous block
-- * @num_regs: number of registers to write
-- * @flags: flags to control DMA descriptor preparation
-- */
--static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-- int first, int num_regs, unsigned int flags)
--{
-- bool flow_control = false;
--
-- if (first == NAND_EXEC_CMD)
-- flags |= NAND_BAM_NWD;
--
-- if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
-- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
--
-- if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
-- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
--
-- if (nandc->props->supports_bam)
-- return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
-- num_regs, flags);
--
-- if (first == NAND_FLASH_CMD)
-- flow_control = true;
--
-- return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
-- num_regs * sizeof(u32), flow_control);
--}
--
--/*
-- * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the
-- * controller's internal buffer to the buffer 'vaddr'
-- *
-- * @reg_off: offset within the controller's data buffer
-- * @vaddr: virtual address of the buffer we want to write to
-- * @size: DMA transaction size in bytes
-- * @flags: flags to control DMA descriptor preparation
-- */
--static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-- const u8 *vaddr, int size, unsigned int flags)
--{
-- if (nandc->props->supports_bam)
-- return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
--
-- return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
--}
--
--/*
-- * qcom_write_data_dma: prepares a DMA descriptor to transfer data from
-- * 'vaddr' to the controller's internal buffer
-- *
-- * @reg_off: offset within the controller's data buffer
-- * @vaddr: virtual address of the buffer we want to read from
-- * @size: DMA transaction size in bytes
-- * @flags: flags to control DMA descriptor preparation
-- */
--static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-- const u8 *vaddr, int size, unsigned int flags)
--{
-- if (nandc->props->supports_bam)
-- return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
--
-- return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
--}
--
--/*
- * Helper to prepare DMA descriptors for configuring registers
- * before reading a NAND page.
- */
-@@ -1262,83 +394,6 @@ static void config_nand_cw_write(struct
- NAND_BAM_NEXT_SGL);
- }
-
--/* helpers to submit/free our list of dma descriptors */
--static int qcom_submit_descs(struct qcom_nand_controller *nandc)
--{
-- struct desc_info *desc, *n;
-- dma_cookie_t cookie = 0;
-- struct bam_transaction *bam_txn = nandc->bam_txn;
-- int ret = 0;
--
-- if (nandc->props->supports_bam) {
-- if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
-- if (ret)
-- goto err_unmap_free_desc;
-- }
--
-- if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-- DMA_PREP_INTERRUPT);
-- if (ret)
-- goto err_unmap_free_desc;
-- }
--
-- if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-- DMA_PREP_CMD);
-- if (ret)
-- goto err_unmap_free_desc;
-- }
-- }
--
-- list_for_each_entry(desc, &nandc->desc_list, node)
-- cookie = dmaengine_submit(desc->dma_desc);
--
-- if (nandc->props->supports_bam) {
-- bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
-- bam_txn->last_cmd_desc->callback_param = bam_txn;
--
-- dma_async_issue_pending(nandc->tx_chan);
-- dma_async_issue_pending(nandc->rx_chan);
-- dma_async_issue_pending(nandc->cmd_chan);
--
-- if (!wait_for_completion_timeout(&bam_txn->txn_done,
-- QPIC_NAND_COMPLETION_TIMEOUT))
-- ret = -ETIMEDOUT;
-- } else {
-- if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
-- ret = -ETIMEDOUT;
-- }
--
--err_unmap_free_desc:
-- /*
-- * Unmap the dma sg_list and free the desc allocated by both
-- * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
-- */
-- list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
-- list_del(&desc->node);
--
-- if (nandc->props->supports_bam)
-- dma_unmap_sg(nandc->dev, desc->bam_sgl,
-- desc->sgl_cnt, desc->dir);
-- else
-- dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
-- desc->dir);
--
-- kfree(desc);
-- }
--
-- return ret;
--}
--
--/* reset the register read buffer for next NAND operation */
--static void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
--{
-- nandc->reg_read_pos = 0;
-- qcom_nandc_dev_to_mem(nandc, false);
--}
--
- /*
- * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
- * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
-@@ -2967,141 +2022,14 @@ static const struct nand_controller_ops
- .exec_op = qcom_nand_exec_op,
- };
-
--static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
--{
-- if (nandc->props->supports_bam) {
-- if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
-- dma_unmap_single(nandc->dev, nandc->reg_read_dma,
-- MAX_REG_RD *
-- sizeof(*nandc->reg_read_buf),
-- DMA_FROM_DEVICE);
--
-- if (nandc->tx_chan)
-- dma_release_channel(nandc->tx_chan);
--
-- if (nandc->rx_chan)
-- dma_release_channel(nandc->rx_chan);
--
-- if (nandc->cmd_chan)
-- dma_release_channel(nandc->cmd_chan);
-- } else {
-- if (nandc->chan)
-- dma_release_channel(nandc->chan);
-- }
--}
--
--static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
--{
-- int ret;
--
-- ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
-- if (ret) {
-- dev_err(nandc->dev, "failed to set DMA mask\n");
-- return ret;
-- }
--
-- /*
-- * we use the internal buffer for reading ONFI params, reading small
-- * data like ID and status, and preforming read-copy-write operations
-- * when writing to a codeword partially. 532 is the maximum possible
-- * size of a codeword for our nand controller
-- */
-- nandc->buf_size = 532;
--
-- nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
-- if (!nandc->data_buffer)
-- return -ENOMEM;
--
-- nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
-- if (!nandc->regs)
-- return -ENOMEM;
--
-- nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
-- sizeof(*nandc->reg_read_buf),
-- GFP_KERNEL);
-- if (!nandc->reg_read_buf)
-- return -ENOMEM;
--
-- if (nandc->props->supports_bam) {
-- nandc->reg_read_dma =
-- dma_map_single(nandc->dev, nandc->reg_read_buf,
-- MAX_REG_RD *
-- sizeof(*nandc->reg_read_buf),
-- DMA_FROM_DEVICE);
-- if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
-- dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
-- return -EIO;
-- }
--
-- nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
-- if (IS_ERR(nandc->tx_chan)) {
-- ret = PTR_ERR(nandc->tx_chan);
-- nandc->tx_chan = NULL;
-- dev_err_probe(nandc->dev, ret,
-- "tx DMA channel request failed\n");
-- goto unalloc;
-- }
--
-- nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
-- if (IS_ERR(nandc->rx_chan)) {
-- ret = PTR_ERR(nandc->rx_chan);
-- nandc->rx_chan = NULL;
-- dev_err_probe(nandc->dev, ret,
-- "rx DMA channel request failed\n");
-- goto unalloc;
-- }
--
-- nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
-- if (IS_ERR(nandc->cmd_chan)) {
-- ret = PTR_ERR(nandc->cmd_chan);
-- nandc->cmd_chan = NULL;
-- dev_err_probe(nandc->dev, ret,
-- "cmd DMA channel request failed\n");
-- goto unalloc;
-- }
--
-- /*
-- * Initially allocate BAM transaction to read ONFI param page.
-- * After detecting all the devices, this BAM transaction will
-- * be freed and the next BAM transaction will be allocated with
-- * maximum codeword size
-- */
-- nandc->max_cwperpage = 1;
-- nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
-- if (!nandc->bam_txn) {
-- dev_err(nandc->dev,
-- "failed to allocate bam transaction\n");
-- ret = -ENOMEM;
-- goto unalloc;
-- }
-- } else {
-- nandc->chan = dma_request_chan(nandc->dev, "rxtx");
-- if (IS_ERR(nandc->chan)) {
-- ret = PTR_ERR(nandc->chan);
-- nandc->chan = NULL;
-- dev_err_probe(nandc->dev, ret,
-- "rxtx DMA channel request failed\n");
-- return ret;
-- }
-- }
--
-- INIT_LIST_HEAD(&nandc->desc_list);
-- INIT_LIST_HEAD(&nandc->host_list);
--
-- nand_controller_init(&nandc->controller);
-- nandc->controller.ops = &qcom_nandc_ops;
--
-- return 0;
--unalloc:
-- qcom_nandc_unalloc(nandc);
-- return ret;
--}
--
- /* one time setup of a few nand controller registers */
- static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
- {
- u32 nand_ctrl;
-
-+ nand_controller_init(nandc->controller);
-+ nandc->controller->ops = &qcom_nandc_ops;
-+
- /* kill onenand */
- if (!nandc->props->nandc_part_of_qpic)
- nandc_write(nandc, SFLASHC_BURST_CFG, 0);
-@@ -3240,7 +2168,7 @@ static int qcom_nand_host_init_and_regis
- chip->legacy.block_bad = qcom_nandc_block_bad;
- chip->legacy.block_markbad = qcom_nandc_block_markbad;
-
-- chip->controller = &nandc->controller;
-+ chip->controller = nandc->controller;
- chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA |
- NAND_SKIP_BBTSCAN;
-
-@@ -3323,17 +2251,21 @@ static int qcom_nandc_parse_dt(struct pl
- static int qcom_nandc_probe(struct platform_device *pdev)
- {
- struct qcom_nand_controller *nandc;
-+ struct nand_controller *controller;
- const void *dev_data;
- struct device *dev = &pdev->dev;
- struct resource *res;
- int ret;
-
-- nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
-+ nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc) + sizeof(*controller),
-+ GFP_KERNEL);
- if (!nandc)
- return -ENOMEM;
-+ controller = (struct nand_controller *)&nandc[1];
-
- platform_set_drvdata(pdev, nandc);
- nandc->dev = dev;
-+ nandc->controller = controller;
-
- dev_data = of_device_get_match_data(dev);
- if (!dev_data) {
---- /dev/null
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -0,0 +1,468 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * QCOM QPIC common APIs header file
-+ *
-+ * Copyright (c) 2023 Qualcomm Inc.
-+ *
-+ */
-+#ifndef __MTD_NAND_QPIC_COMMON_H__
-+#define __MTD_NAND_QPIC_COMMON_H__
-+
-+/* NANDc reg offsets */
-+#define NAND_FLASH_CMD 0x00
-+#define NAND_ADDR0 0x04
-+#define NAND_ADDR1 0x08
-+#define NAND_FLASH_CHIP_SELECT 0x0c
-+#define NAND_EXEC_CMD 0x10
-+#define NAND_FLASH_STATUS 0x14
-+#define NAND_BUFFER_STATUS 0x18
-+#define NAND_DEV0_CFG0 0x20
-+#define NAND_DEV0_CFG1 0x24
-+#define NAND_DEV0_ECC_CFG 0x28
-+#define NAND_AUTO_STATUS_EN 0x2c
-+#define NAND_DEV1_CFG0 0x30
-+#define NAND_DEV1_CFG1 0x34
-+#define NAND_READ_ID 0x40
-+#define NAND_READ_STATUS 0x44
-+#define NAND_DEV_CMD0 0xa0
-+#define NAND_DEV_CMD1 0xa4
-+#define NAND_DEV_CMD2 0xa8
-+#define NAND_DEV_CMD_VLD 0xac
-+#define SFLASHC_BURST_CFG 0xe0
-+#define NAND_ERASED_CW_DETECT_CFG 0xe8
-+#define NAND_ERASED_CW_DETECT_STATUS 0xec
-+#define NAND_EBI2_ECC_BUF_CFG 0xf0
-+#define FLASH_BUF_ACC 0x100
-+
-+#define NAND_CTRL 0xf00
-+#define NAND_VERSION 0xf08
-+#define NAND_READ_LOCATION_0 0xf20
-+#define NAND_READ_LOCATION_1 0xf24
-+#define NAND_READ_LOCATION_2 0xf28
-+#define NAND_READ_LOCATION_3 0xf2c
-+#define NAND_READ_LOCATION_LAST_CW_0 0xf40
-+#define NAND_READ_LOCATION_LAST_CW_1 0xf44
-+#define NAND_READ_LOCATION_LAST_CW_2 0xf48
-+#define NAND_READ_LOCATION_LAST_CW_3 0xf4c
-+
-+/* dummy register offsets, used by qcom_write_reg_dma */
-+#define NAND_DEV_CMD1_RESTORE 0xdead
-+#define NAND_DEV_CMD_VLD_RESTORE 0xbeef
-+
-+/* NAND_FLASH_CMD bits */
-+#define PAGE_ACC BIT(4)
-+#define LAST_PAGE BIT(5)
-+
-+/* NAND_FLASH_CHIP_SELECT bits */
-+#define NAND_DEV_SEL 0
-+#define DM_EN BIT(2)
-+
-+/* NAND_FLASH_STATUS bits */
-+#define FS_OP_ERR BIT(4)
-+#define FS_READY_BSY_N BIT(5)
-+#define FS_MPU_ERR BIT(8)
-+#define FS_DEVICE_STS_ERR BIT(16)
-+#define FS_DEVICE_WP BIT(23)
-+
-+/* NAND_BUFFER_STATUS bits */
-+#define BS_UNCORRECTABLE_BIT BIT(8)
-+#define BS_CORRECTABLE_ERR_MSK 0x1f
-+
-+/* NAND_DEVn_CFG0 bits */
-+#define DISABLE_STATUS_AFTER_WRITE 4
-+#define CW_PER_PAGE 6
-+#define UD_SIZE_BYTES 9
-+#define UD_SIZE_BYTES_MASK GENMASK(18, 9)
-+#define ECC_PARITY_SIZE_BYTES_RS 19
-+#define SPARE_SIZE_BYTES 23
-+#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
-+#define NUM_ADDR_CYCLES 27
-+#define STATUS_BFR_READ 30
-+#define SET_RD_MODE_AFTER_STATUS 31
-+
-+/* NAND_DEVn_CFG0 bits */
-+#define DEV0_CFG1_ECC_DISABLE 0
-+#define WIDE_FLASH 1
-+#define NAND_RECOVERY_CYCLES 2
-+#define CS_ACTIVE_BSY 5
-+#define BAD_BLOCK_BYTE_NUM 6
-+#define BAD_BLOCK_IN_SPARE_AREA 16
-+#define WR_RD_BSY_GAP 17
-+#define ENABLE_BCH_ECC 27
-+
-+/* NAND_DEV0_ECC_CFG bits */
-+#define ECC_CFG_ECC_DISABLE 0
-+#define ECC_SW_RESET 1
-+#define ECC_MODE 4
-+#define ECC_PARITY_SIZE_BYTES_BCH 8
-+#define ECC_NUM_DATA_BYTES 16
-+#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
-+#define ECC_FORCE_CLK_OPEN 30
-+
-+/* NAND_DEV_CMD1 bits */
-+#define READ_ADDR 0
-+
-+/* NAND_DEV_CMD_VLD bits */
-+#define READ_START_VLD BIT(0)
-+#define READ_STOP_VLD BIT(1)
-+#define WRITE_START_VLD BIT(2)
-+#define ERASE_START_VLD BIT(3)
-+#define SEQ_READ_START_VLD BIT(4)
-+
-+/* NAND_EBI2_ECC_BUF_CFG bits */
-+#define NUM_STEPS 0
-+
-+/* NAND_ERASED_CW_DETECT_CFG bits */
-+#define ERASED_CW_ECC_MASK 1
-+#define AUTO_DETECT_RES 0
-+#define MASK_ECC BIT(ERASED_CW_ECC_MASK)
-+#define RESET_ERASED_DET BIT(AUTO_DETECT_RES)
-+#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES)
-+#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC)
-+#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC)
-+
-+/* NAND_ERASED_CW_DETECT_STATUS bits */
-+#define PAGE_ALL_ERASED BIT(7)
-+#define CODEWORD_ALL_ERASED BIT(6)
-+#define PAGE_ERASED BIT(5)
-+#define CODEWORD_ERASED BIT(4)
-+#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED)
-+#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
-+
-+/* NAND_READ_LOCATION_n bits */
-+#define READ_LOCATION_OFFSET 0
-+#define READ_LOCATION_SIZE 16
-+#define READ_LOCATION_LAST 31
-+
-+/* Version Mask */
-+#define NAND_VERSION_MAJOR_MASK 0xf0000000
-+#define NAND_VERSION_MAJOR_SHIFT 28
-+#define NAND_VERSION_MINOR_MASK 0x0fff0000
-+#define NAND_VERSION_MINOR_SHIFT 16
-+
-+/* NAND OP_CMDs */
-+#define OP_PAGE_READ 0x2
-+#define OP_PAGE_READ_WITH_ECC 0x3
-+#define OP_PAGE_READ_WITH_ECC_SPARE 0x4
-+#define OP_PAGE_READ_ONFI_READ 0x5
-+#define OP_PROGRAM_PAGE 0x6
-+#define OP_PAGE_PROGRAM_WITH_ECC 0x7
-+#define OP_PROGRAM_PAGE_SPARE 0x9
-+#define OP_BLOCK_ERASE 0xa
-+#define OP_CHECK_STATUS 0xc
-+#define OP_FETCH_ID 0xb
-+#define OP_RESET_DEVICE 0xd
-+
-+/* Default Value for NAND_DEV_CMD_VLD */
-+#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
-+ ERASE_START_VLD | SEQ_READ_START_VLD)
-+
-+/* NAND_CTRL bits */
-+#define BAM_MODE_EN BIT(0)
-+
-+/*
-+ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
-+ * the driver calls the chunks 'step' or 'codeword' interchangeably
-+ */
-+#define NANDC_STEP_SIZE 512
-+
-+/*
-+ * the largest page size we support is 8K, this will have 16 steps/codewords
-+ * of 512 bytes each
-+ */
-+#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE)
-+
-+/* we read at most 3 registers per codeword scan */
-+#define MAX_REG_RD (3 * MAX_NUM_STEPS)
-+
-+/* ECC modes supported by the controller */
-+#define ECC_NONE BIT(0)
-+#define ECC_RS_4BIT BIT(1)
-+#define ECC_BCH_4BIT BIT(2)
-+#define ECC_BCH_8BIT BIT(3)
-+
-+/*
-+ * Returns the actual register address for all NAND_DEV_ registers
-+ * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
-+ */
-+#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
-+
-+/* Returns the NAND register physical address */
-+#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
-+
-+/* Returns the dma address for reg read buffer */
-+#define reg_buf_dma_addr(chip, vaddr) \
-+ ((chip)->reg_read_dma + \
-+ ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
-+
-+#define QPIC_PER_CW_CMD_ELEMENTS 32
-+#define QPIC_PER_CW_CMD_SGL 32
-+#define QPIC_PER_CW_DATA_SGL 8
-+
-+#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
-+
-+/*
-+ * Flags used in DMA descriptor preparation helper functions
-+ * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
-+ */
-+/* Don't set the EOT in current tx BAM sgl */
-+#define NAND_BAM_NO_EOT BIT(0)
-+/* Set the NWD flag in current BAM sgl */
-+#define NAND_BAM_NWD BIT(1)
-+/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
-+#define NAND_BAM_NEXT_SGL BIT(2)
-+/*
-+ * Erased codeword status is being used two times in single transfer so this
-+ * flag will determine the current value of erased codeword status register
-+ */
-+#define NAND_ERASED_CW_SET BIT(4)
-+
-+#define MAX_ADDRESS_CYCLE 5
-+
-+/*
-+ * This data type corresponds to the BAM transaction which will be used for all
-+ * NAND transfers.
-+ * @bam_ce - the array of BAM command elements
-+ * @cmd_sgl - sgl for NAND BAM command pipe
-+ * @data_sgl - sgl for NAND BAM consumer/producer pipe
-+ * @last_data_desc - last DMA desc in data channel (tx/rx).
-+ * @last_cmd_desc - last DMA desc in command channel.
-+ * @txn_done - completion for NAND transfer.
-+ * @bam_ce_pos - the index in bam_ce which is available for next sgl
-+ * @bam_ce_start - the index in bam_ce which marks the start position ce
-+ * for current sgl. It will be used for size calculation
-+ * for current sgl
-+ * @cmd_sgl_pos - current index in command sgl.
-+ * @cmd_sgl_start - start index in command sgl.
-+ * @tx_sgl_pos - current index in data sgl for tx.
-+ * @tx_sgl_start - start index in data sgl for tx.
-+ * @rx_sgl_pos - current index in data sgl for rx.
-+ * @rx_sgl_start - start index in data sgl for rx.
-+ */
-+struct bam_transaction {
-+ struct bam_cmd_element *bam_ce;
-+ struct scatterlist *cmd_sgl;
-+ struct scatterlist *data_sgl;
-+ struct dma_async_tx_descriptor *last_data_desc;
-+ struct dma_async_tx_descriptor *last_cmd_desc;
-+ struct completion txn_done;
-+ u32 bam_ce_pos;
-+ u32 bam_ce_start;
-+ u32 cmd_sgl_pos;
-+ u32 cmd_sgl_start;
-+ u32 tx_sgl_pos;
-+ u32 tx_sgl_start;
-+ u32 rx_sgl_pos;
-+ u32 rx_sgl_start;
-+};
-+
-+/*
-+ * This data type corresponds to the nand dma descriptor
-+ * @dma_desc - low level DMA engine descriptor
-+ * @list - list for desc_info
-+ *
-+ * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
-+ * ADM
-+ * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
-+ * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
-+ * @dir - DMA transfer direction
-+ */
-+struct desc_info {
-+ struct dma_async_tx_descriptor *dma_desc;
-+ struct list_head node;
-+
-+ union {
-+ struct scatterlist adm_sgl;
-+ struct {
-+ struct scatterlist *bam_sgl;
-+ int sgl_cnt;
-+ };
-+ };
-+ enum dma_data_direction dir;
-+};
-+
-+/*
-+ * holds the current register values that we want to write. acts as a contiguous
-+ * chunk of memory which we use to write the controller registers through DMA.
-+ */
-+struct nandc_regs {
-+ __le32 cmd;
-+ __le32 addr0;
-+ __le32 addr1;
-+ __le32 chip_sel;
-+ __le32 exec;
-+
-+ __le32 cfg0;
-+ __le32 cfg1;
-+ __le32 ecc_bch_cfg;
-+
-+ __le32 clrflashstatus;
-+ __le32 clrreadstatus;
-+
-+ __le32 cmd1;
-+ __le32 vld;
-+
-+ __le32 orig_cmd1;
-+ __le32 orig_vld;
-+
-+ __le32 ecc_buf_cfg;
-+ __le32 read_location0;
-+ __le32 read_location1;
-+ __le32 read_location2;
-+ __le32 read_location3;
-+ __le32 read_location_last0;
-+ __le32 read_location_last1;
-+ __le32 read_location_last2;
-+ __le32 read_location_last3;
-+
-+ __le32 erased_cw_detect_cfg_clr;
-+ __le32 erased_cw_detect_cfg_set;
-+};
-+
-+/*
-+ * NAND controller data struct
-+ *
-+ * @dev: parent device
-+ *
-+ * @base: MMIO base
-+ *
-+ * @core_clk: controller clock
-+ * @aon_clk: another controller clock
-+ *
-+ * @regs: a contiguous chunk of memory for DMA register
-+ * writes. contains the register values to be
-+ * written to controller
-+ *
-+ * @props: properties of current NAND controller,
-+ * initialized via DT match data
-+ *
-+ * @controller: base controller structure
-+ * @host_list: list containing all the chips attached to the
-+ * controller
-+ *
-+ * @chan: dma channel
-+ * @cmd_crci: ADM DMA CRCI for command flow control
-+ * @data_crci: ADM DMA CRCI for data flow control
-+ *
-+ * @desc_list: DMA descriptor list (list of desc_infos)
-+ *
-+ * @data_buffer: our local DMA buffer for page read/writes,
-+ * used when we can't use the buffer provided
-+ * by upper layers directly
-+ * @reg_read_buf: local buffer for reading back registers via DMA
-+ *
-+ * @base_phys: physical base address of controller registers
-+ * @base_dma: dma base address of controller registers
-+ * @reg_read_dma: contains dma address for register read buffer
-+ *
-+ * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
-+ * functions
-+ * @max_cwperpage: maximum QPIC codewords required. calculated
-+ * from all connected NAND devices pagesize
-+ *
-+ * @reg_read_pos: marker for data read in reg_read_buf
-+ *
-+ * @cmd1/vld: some fixed controller register values
-+ *
-+ * @exec_opwrite: flag to select correct number of code word
-+ * while reading status
-+ */
-+struct qcom_nand_controller {
-+ struct device *dev;
-+
-+ void __iomem *base;
-+
-+ struct clk *core_clk;
-+ struct clk *aon_clk;
-+
-+ struct nandc_regs *regs;
-+ struct bam_transaction *bam_txn;
-+
-+ const struct qcom_nandc_props *props;
-+
-+ struct nand_controller *controller;
-+ struct list_head host_list;
-+
-+ union {
-+ /* will be used only by QPIC for BAM DMA */
-+ struct {
-+ struct dma_chan *tx_chan;
-+ struct dma_chan *rx_chan;
-+ struct dma_chan *cmd_chan;
-+ };
-+
-+ /* will be used only by EBI2 for ADM DMA */
-+ struct {
-+ struct dma_chan *chan;
-+ unsigned int cmd_crci;
-+ unsigned int data_crci;
-+ };
-+ };
-+
-+ struct list_head desc_list;
-+
-+ u8 *data_buffer;
-+ __le32 *reg_read_buf;
-+
-+ phys_addr_t base_phys;
-+ dma_addr_t base_dma;
-+ dma_addr_t reg_read_dma;
-+
-+ int buf_size;
-+ int buf_count;
-+ int buf_start;
-+ unsigned int max_cwperpage;
-+
-+ int reg_read_pos;
-+
-+ u32 cmd1, vld;
-+ bool exec_opwrite;
-+};
-+
-+/*
-+ * This data type corresponds to the NAND controller properties which varies
-+ * among different NAND controllers.
-+ * @ecc_modes - ecc mode for NAND
-+ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
-+ * @supports_bam - whether NAND controller is using BAM
-+ * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
-+ * @qpic_version2 - flag to indicate QPIC IP version 2
-+ * @use_codeword_fixup - whether NAND has different layout for boot partitions
-+ */
-+struct qcom_nandc_props {
-+ u32 ecc_modes;
-+ u32 dev_cmd_reg_start;
-+ bool supports_bam;
-+ bool nandc_part_of_qpic;
-+ bool qpic_version2;
-+ bool use_codeword_fixup;
-+};
-+
-+void qcom_free_bam_transaction(struct qcom_nand_controller *nandc);
-+struct bam_transaction *qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc);
-+void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc);
-+void qcom_qpic_bam_dma_done(void *data);
-+void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu);
-+int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-+ struct dma_chan *chan, unsigned long flags);
-+int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr, int size, unsigned int flags);
-+int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-+ const void *vaddr, int size, unsigned int flags);
-+int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, int reg_off,
-+ const void *vaddr, int size, bool flow_control);
-+int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, int num_regs,
-+ unsigned int flags);
-+int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, int first,
-+ int num_regs, unsigned int flags);
-+int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr,
-+ int size, unsigned int flags);
-+int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr,
-+ int size, unsigned int flags);
-+int qcom_submit_descs(struct qcom_nand_controller *nandc);
-+void qcom_clear_read_regs(struct qcom_nand_controller *nandc);
-+void qcom_nandc_unalloc(struct qcom_nand_controller *nandc);
-+int qcom_nandc_alloc(struct qcom_nand_controller *nandc);
-+#endif
-+
+++ /dev/null
-From 0c08080fd71cd5dd59643104b39d3c89d793ab3c Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Nov 2024 14:45:03 +0530
-Subject: [PATCH 4/4] mtd: rawnand: qcom: use FIELD_PREP and GENMASK
-
-Use the bitfield macro FIELD_PREP, and GENMASK to
-do the shift and mask in one go. This makes the code
-more readable.
-
----
- drivers/mtd/nand/raw/qcom_nandc.c | 97 ++++++++++++++--------------
- include/linux/mtd/nand-qpic-common.h | 31 +++++----
- 2 files changed, 67 insertions(+), 61 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -281,7 +281,7 @@ static void update_rw_regs(struct qcom_n
- (num_cw - 1) << CW_PER_PAGE);
-
- cfg1 = cpu_to_le32(host->cfg1_raw);
-- ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
-+ ecc_bch_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
- }
-
- nandc->regs->cmd = cmd;
-@@ -1494,42 +1494,41 @@ static int qcom_nand_attach_chip(struct
- host->cw_size = host->cw_data + ecc->bytes;
- bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
-
-- host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
-- | host->cw_data << UD_SIZE_BYTES
-- | 0 << DISABLE_STATUS_AFTER_WRITE
-- | 5 << NUM_ADDR_CYCLES
-- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
-- | 0 << STATUS_BFR_READ
-- | 1 << SET_RD_MODE_AFTER_STATUS
-- | host->spare_bytes << SPARE_SIZE_BYTES;
--
-- host->cfg1 = 7 << NAND_RECOVERY_CYCLES
-- | 0 << CS_ACTIVE_BSY
-- | bad_block_byte << BAD_BLOCK_BYTE_NUM
-- | 0 << BAD_BLOCK_IN_SPARE_AREA
-- | 2 << WR_RD_BSY_GAP
-- | wide_bus << WIDE_FLASH
-- | host->bch_enabled << ENABLE_BCH_ECC;
--
-- host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
-- | host->cw_size << UD_SIZE_BYTES
-- | 5 << NUM_ADDR_CYCLES
-- | 0 << SPARE_SIZE_BYTES;
--
-- host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
-- | 0 << CS_ACTIVE_BSY
-- | 17 << BAD_BLOCK_BYTE_NUM
-- | 1 << BAD_BLOCK_IN_SPARE_AREA
-- | 2 << WR_RD_BSY_GAP
-- | wide_bus << WIDE_FLASH
-- | 1 << DEV0_CFG1_ECC_DISABLE;
--
-- host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
-- | 0 << ECC_SW_RESET
-- | host->cw_data << ECC_NUM_DATA_BYTES
-- | 1 << ECC_FORCE_CLK_OPEN
-- | ecc_mode << ECC_MODE
-- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
-+ host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_data) |
-+ FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 0) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, host->ecc_bytes_hw) |
-+ FIELD_PREP(STATUS_BFR_READ, 0) |
-+ FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, host->spare_bytes);
-+
-+ host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-+ FIELD_PREP(WIDE_FLASH, wide_bus) |
-+ FIELD_PREP(ENABLE_BCH_ECC, host->bch_enabled);
-+
-+ host->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_size) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-+
-+ host->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-+ FIELD_PREP(WIDE_FLASH, wide_bus) |
-+ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-+
-+ host->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !host->bch_enabled) |
-+ FIELD_PREP(ECC_SW_RESET, 0) |
-+ FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, host->cw_data) |
-+ FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
-+ FIELD_PREP(ECC_MODE_MASK, ecc_mode) |
-+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, host->ecc_bytes_hw);
-
- if (!nandc->props->qpic_version2)
- host->ecc_buf_cfg = 0x203 << NUM_STEPS;
-@@ -1882,21 +1881,21 @@ static int qcom_param_page_type_exec(str
- nandc->regs->addr0 = 0;
- nandc->regs->addr1 = 0;
-
-- nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE |
-- 512 << UD_SIZE_BYTES |
-- 5 << NUM_ADDR_CYCLES |
-- 0 << SPARE_SIZE_BYTES);
--
-- nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES |
-- 0 << CS_ACTIVE_BSY |
-- 17 << BAD_BLOCK_BYTE_NUM |
-- 1 << BAD_BLOCK_IN_SPARE_AREA |
-- 2 << WR_RD_BSY_GAP |
-- 0 << WIDE_FLASH |
-- 1 << DEV0_CFG1_ECC_DISABLE);
-+ host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-+
-+ host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-+ FIELD_PREP(WIDE_FLASH, 0) |
-+ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-
- if (!nandc->props->qpic_version2)
-- nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
-+ nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
-
- /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
- if (!nandc->props->qpic_version2) {
---- a/include/linux/mtd/nand-qpic-common.h
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -70,35 +70,42 @@
- #define BS_CORRECTABLE_ERR_MSK 0x1f
-
- /* NAND_DEVn_CFG0 bits */
--#define DISABLE_STATUS_AFTER_WRITE 4
-+#define DISABLE_STATUS_AFTER_WRITE BIT(4)
- #define CW_PER_PAGE 6
-+#define CW_PER_PAGE_MASK GENMASK(8, 6)
- #define UD_SIZE_BYTES 9
- #define UD_SIZE_BYTES_MASK GENMASK(18, 9)
--#define ECC_PARITY_SIZE_BYTES_RS 19
-+#define ECC_PARITY_SIZE_BYTES_RS GENMASK(22, 19)
- #define SPARE_SIZE_BYTES 23
- #define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
- #define NUM_ADDR_CYCLES 27
--#define STATUS_BFR_READ 30
--#define SET_RD_MODE_AFTER_STATUS 31
-+#define NUM_ADDR_CYCLES_MASK GENMASK(29, 27)
-+#define STATUS_BFR_READ BIT(30)
-+#define SET_RD_MODE_AFTER_STATUS BIT(31)
-
- /* NAND_DEVn_CFG0 bits */
--#define DEV0_CFG1_ECC_DISABLE 0
--#define WIDE_FLASH 1
-+#define DEV0_CFG1_ECC_DISABLE BIT(0)
-+#define WIDE_FLASH BIT(1)
- #define NAND_RECOVERY_CYCLES 2
--#define CS_ACTIVE_BSY 5
-+#define NAND_RECOVERY_CYCLES_MASK GENMASK(4, 2)
-+#define CS_ACTIVE_BSY BIT(5)
- #define BAD_BLOCK_BYTE_NUM 6
--#define BAD_BLOCK_IN_SPARE_AREA 16
-+#define BAD_BLOCK_BYTE_NUM_MASK GENMASK(15, 6)
-+#define BAD_BLOCK_IN_SPARE_AREA BIT(16)
- #define WR_RD_BSY_GAP 17
--#define ENABLE_BCH_ECC 27
-+#define WR_RD_BSY_GAP_MASK GENMASK(22, 17)
-+#define ENABLE_BCH_ECC BIT(27)
-
- /* NAND_DEV0_ECC_CFG bits */
--#define ECC_CFG_ECC_DISABLE 0
--#define ECC_SW_RESET 1
-+#define ECC_CFG_ECC_DISABLE BIT(0)
-+#define ECC_SW_RESET BIT(1)
- #define ECC_MODE 4
-+#define ECC_MODE_MASK GENMASK(5, 4)
- #define ECC_PARITY_SIZE_BYTES_BCH 8
-+#define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8)
- #define ECC_NUM_DATA_BYTES 16
- #define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
--#define ECC_FORCE_CLK_OPEN 30
-+#define ECC_FORCE_CLK_OPEN BIT(30)
-
- /* NAND_DEV_CMD1 bits */
- #define READ_ADDR 0
+++ /dev/null
-From 9d4ffbcfde283f2a87ea45128ddf7e6651facdd9 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Feb 2025 20:42:38 +0100
-Subject: [PATCH] mtd: rawnand: qcom: fix broken config in
- qcom_param_page_type_exec
-
-Fix broken config in qcom_param_page_type_exec caused by copy-paste error
-from commit 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
-
-In qcom_param_page_type_exec the value needs to be set to
-nandc->regs->cfg0 instead of host->cfg0. This wrong configuration caused
-the Qcom NANDC driver to malfunction on any device that makes use of it
-(IPQ806x, IPQ40xx, IPQ807x, IPQ60xx) with the following error:
-
-[ 0.885369] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xaa
-[ 0.885909] nand: Micron NAND 256MiB 1,8V 8-bit
-[ 0.892499] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
-[ 0.896823] nand: ECC (step, strength) = (512, 8) does not fit in OOB
-[ 0.896836] qcom-nandc 79b0000.nand-controller: No valid ECC settings possible
-[ 0.910996] bam-dma-engine 7984000.dma-controller: Cannot free busy channel
-[ 0.918070] qcom-nandc: probe of 79b0000.nand-controller failed with error -28
-
-Restore original configuration fix the problem and makes the driver work
-again.
-
-Fixes: 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
----
- drivers/mtd/nand/raw/qcom_nandc.c | 24 ++++++++++++------------
- 1 file changed, 12 insertions(+), 12 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -1881,18 +1881,18 @@ static int qcom_param_page_type_exec(str
- nandc->regs->addr0 = 0;
- nandc->regs->addr1 = 0;
-
-- host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
-- FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
-- FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-- FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-+ nandc->regs->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-
-- host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-- FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-- FIELD_PREP(CS_ACTIVE_BSY, 0) |
-- FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-- FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-- FIELD_PREP(WIDE_FLASH, 0) |
-- FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-+ nandc->regs->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-+ FIELD_PREP(WIDE_FLASH, 0) |
-+ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-
- if (!nandc->props->qpic_version2)
- nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
+++ /dev/null
-From b9371866799d67a80be0ea9e01bd41987db22f26 Mon Sep 17 00:00:00 2001
-Date: Mon, 6 Jan 2025 18:45:58 +0530
-Subject: [PATCH] mtd: rawnand: qcom: Fix build issue on x86 architecture
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Fix a buffer overflow issue in qcom_clear_bam_transaction by using
-struct_group to group related fields and avoid FORTIFY_SOURCE warnings.
-
-On x86 architecture, the following error occurs due to warnings being
-treated as errors:
-
-In function ‘fortify_memset_chk’,
- inlined from ‘qcom_clear_bam_transaction’ at
-drivers/mtd/nand/qpic_common.c:88:2:
-./include/linux/fortify-string.h:480:25: error: call to ‘__write_overflow_field’
-declared with attribute warning: detected write beyond size of field
-(1st parameter); maybe use struct_group()? [-Werror=attribute-warning]
- 480 | __write_overflow_field(p_size_field, size);
- | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- LD [M] drivers/mtd/nand/nandcore.o
- CC [M] drivers/w1/masters/mxc_w1.o
-cc1: all warnings being treated as errors
-
-This patch addresses the issue by grouping the related fields in
-struct bam_transaction using struct_group and updating the memset call
-accordingly.
-
-Fixes: 8c52932da5e6 ("mtd: rawnand: qcom: cleanup qcom_nandc driver")
----
- drivers/mtd/nand/qpic_common.c | 2 +-
- include/linux/mtd/nand-qpic-common.h | 19 +++++++++++--------
- 2 files changed, 12 insertions(+), 9 deletions(-)
-
---- a/drivers/mtd/nand/qpic_common.c
-+++ b/drivers/mtd/nand/qpic_common.c
-@@ -85,7 +85,7 @@ void qcom_clear_bam_transaction(struct q
- if (!nandc->props->supports_bam)
- return;
-
-- memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
-+ memset(&bam_txn->bam_positions, 0, sizeof(bam_txn->bam_positions));
- bam_txn->last_data_desc = NULL;
-
- sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
---- a/include/linux/mtd/nand-qpic-common.h
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -254,14 +254,17 @@ struct bam_transaction {
- struct dma_async_tx_descriptor *last_data_desc;
- struct dma_async_tx_descriptor *last_cmd_desc;
- struct completion txn_done;
-- u32 bam_ce_pos;
-- u32 bam_ce_start;
-- u32 cmd_sgl_pos;
-- u32 cmd_sgl_start;
-- u32 tx_sgl_pos;
-- u32 tx_sgl_start;
-- u32 rx_sgl_pos;
-- u32 rx_sgl_start;
-+ struct_group(bam_positions,
-+ u32 bam_ce_pos;
-+ u32 bam_ce_start;
-+ u32 cmd_sgl_pos;
-+ u32 cmd_sgl_start;
-+ u32 tx_sgl_pos;
-+ u32 tx_sgl_start;
-+ u32 rx_sgl_pos;
-+ u32 rx_sgl_start;
-+
-+ );
- };
-
- /*
+++ /dev/null
-From 7304d1909080ef0c9da703500a97f46c98393fcd Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Feb 2025 16:44:14 +0530
-Subject: [PATCH] spi: spi-qpic: add driver for QCOM SPI NAND flash Interface
-
-This driver implements support for the SPI-NAND mode of QCOM NAND Flash
-Interface as a SPI-MEM controller with pipelined ECC capability.
-
----
- drivers/mtd/nand/Makefile | 4 +
- drivers/spi/Kconfig | 9 +
- drivers/spi/Makefile | 1 +
- drivers/spi/spi-qpic-snand.c | 1631 ++++++++++++++++++++++++++
- include/linux/mtd/nand-qpic-common.h | 7 +
- 5 files changed, 1652 insertions(+)
- create mode 100644 drivers/spi/spi-qpic-snand.c
-
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -3,7 +3,11 @@
- nandcore-objs := core.o bbt.o
- obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
- obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
-+ifeq ($(CONFIG_SPI_QPIC_SNAND),y)
-+obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o
-+else
- obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o
-+endif
- obj-y += onenand/
- obj-y += raw/
- obj-y += spi/
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -898,6 +898,15 @@ config SPI_QCOM_QSPI
- help
- QSPI(Quad SPI) driver for Qualcomm QSPI controller.
-
-+config SPI_QPIC_SNAND
-+ bool "QPIC SNAND controller"
-+ depends on ARCH_QCOM || COMPILE_TEST
-+ select MTD
-+ help
-+ QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller.
-+ QPIC controller supports both parallel nand and serial nand.
-+ This config will enable serial nand driver for QPIC controller.
-+
- config SPI_QUP
- tristate "Qualcomm SPI controller with QUP interface"
- depends on ARCH_QCOM || COMPILE_TEST
---- a/drivers/spi/Makefile
-+++ b/drivers/spi/Makefile
-@@ -114,6 +114,7 @@ obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-
- obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
- obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o
- obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o
-+obj-$(CONFIG_SPI_QPIC_SNAND) += spi-qpic-snand.o
- obj-$(CONFIG_SPI_QUP) += spi-qup.o
- obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
- obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o
---- /dev/null
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -0,0 +1,1631 @@
-+/*
-+ * SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
-+ *
-+ * Authors:
-+ */
-+#include <linux/bitops.h>
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/dmaengine.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma/qcom_adm.h>
-+#include <linux/dma/qcom_bam_dma.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/nand-qpic-common.h>
-+#include <linux/mtd/spinand.h>
-+#include <linux/bitfield.h>
-+
-+#define NAND_FLASH_SPI_CFG 0xc0
-+#define NAND_NUM_ADDR_CYCLES 0xc4
-+#define NAND_BUSY_CHECK_WAIT_CNT 0xc8
-+#define NAND_FLASH_FEATURES 0xf64
-+
-+/* QSPI NAND config reg bits */
-+#define LOAD_CLK_CNTR_INIT_EN BIT(28)
-+#define CLK_CNTR_INIT_VAL_VEC 0x924
-+#define CLK_CNTR_INIT_VAL_VEC_MASK GENMASK(27, 16)
-+#define FEA_STATUS_DEV_ADDR 0xc0
-+#define FEA_STATUS_DEV_ADDR_MASK GENMASK(15, 8)
-+#define SPI_CFG BIT(0)
-+#define SPI_NUM_ADDR 0xDA4DB
-+#define SPI_WAIT_CNT 0x10
-+#define QPIC_QSPI_NUM_CS 1
-+#define SPI_TRANSFER_MODE_x1 BIT(29)
-+#define SPI_TRANSFER_MODE_x4 (3 << 29)
-+#define SPI_WP BIT(28)
-+#define SPI_HOLD BIT(27)
-+#define QPIC_SET_FEATURE BIT(31)
-+
-+#define SPINAND_RESET 0xff
-+#define SPINAND_READID 0x9f
-+#define SPINAND_GET_FEATURE 0x0f
-+#define SPINAND_SET_FEATURE 0x1f
-+#define SPINAND_READ 0x13
-+#define SPINAND_ERASE 0xd8
-+#define SPINAND_WRITE_EN 0x06
-+#define SPINAND_PROGRAM_EXECUTE 0x10
-+#define SPINAND_PROGRAM_LOAD 0x84
-+
-+#define ACC_FEATURE 0xe
-+#define BAD_BLOCK_MARKER_SIZE 0x2
-+#define OOB_BUF_SIZE 128
-+#define ecceng_to_qspi(eng) container_of(eng, struct qpic_spi_nand, ecc_eng)
-+
-+struct qpic_snand_op {
-+ u32 cmd_reg;
-+ u32 addr1_reg;
-+ u32 addr2_reg;
-+};
-+
-+struct snandc_read_status {
-+ __le32 snandc_flash;
-+ __le32 snandc_buffer;
-+ __le32 snandc_erased_cw;
-+};
-+
-+/*
-+ * ECC state struct
-+ * @corrected: ECC corrected
-+ * @bitflips: Max bit flip
-+ * @failed: ECC failed
-+ */
-+struct qcom_ecc_stats {
-+ u32 corrected;
-+ u32 bitflips;
-+ u32 failed;
-+};
-+
-+struct qpic_ecc {
-+ struct device *dev;
-+ int ecc_bytes_hw;
-+ int spare_bytes;
-+ int bbm_size;
-+ int ecc_mode;
-+ int bytes;
-+ int steps;
-+ int step_size;
-+ int strength;
-+ int cw_size;
-+ int cw_data;
-+ u32 cfg0;
-+ u32 cfg1;
-+ u32 cfg0_raw;
-+ u32 cfg1_raw;
-+ u32 ecc_buf_cfg;
-+ u32 ecc_bch_cfg;
-+ u32 clrflashstatus;
-+ u32 clrreadstatus;
-+ bool bch_enabled;
-+};
-+
-+struct qpic_spi_nand {
-+ struct qcom_nand_controller *snandc;
-+ struct spi_controller *ctlr;
-+ struct mtd_info *mtd;
-+ struct clk *iomacro_clk;
-+ struct qpic_ecc *ecc;
-+ struct qcom_ecc_stats ecc_stats;
-+ struct nand_ecc_engine ecc_eng;
-+ u8 *data_buf;
-+ u8 *oob_buf;
-+ u32 wlen;
-+ __le32 addr1;
-+ __le32 addr2;
-+ __le32 cmd;
-+ u32 num_cw;
-+ bool oob_rw;
-+ bool page_rw;
-+ bool raw_rw;
-+};
-+
-+static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc,
-+ int reg, int cw_offset, int read_size,
-+ int is_last_read_loc)
-+{
-+ __le32 locreg_val;
-+ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+ ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
-+ << READ_LOCATION_LAST));
-+
-+ locreg_val = cpu_to_le32(val);
-+
-+ if (reg == NAND_READ_LOCATION_0)
-+ snandc->regs->read_location0 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_1)
-+ snandc->regs->read_location1 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_2)
-+ snandc->regs->read_location1 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_3)
-+ snandc->regs->read_location3 = locreg_val;
-+}
-+
-+static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc,
-+ int reg, int cw_offset, int read_size,
-+ int is_last_read_loc)
-+{
-+ __le32 locreg_val;
-+ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+ ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
-+ << READ_LOCATION_LAST));
-+
-+ locreg_val = cpu_to_le32(val);
-+
-+ if (reg == NAND_READ_LOCATION_LAST_CW_0)
-+ snandc->regs->read_location_last0 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_LAST_CW_1)
-+ snandc->regs->read_location_last1 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_LAST_CW_2)
-+ snandc->regs->read_location_last2 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_LAST_CW_3)
-+ snandc->regs->read_location_last3 = locreg_val;
-+}
-+
-+static struct qcom_nand_controller *nand_to_qcom_snand(struct nand_device *nand)
-+{
-+ struct nand_ecc_engine *eng = nand->ecc.engine;
-+ struct qpic_spi_nand *qspi = ecceng_to_qspi(eng);
-+
-+ return qspi->snandc;
-+}
-+
-+static int qcom_spi_init(struct qcom_nand_controller *snandc)
-+{
-+ u32 snand_cfg_val = 0x0;
-+ int ret;
-+
-+ snand_cfg_val = FIELD_PREP(CLK_CNTR_INIT_VAL_VEC_MASK, CLK_CNTR_INIT_VAL_VEC) |
-+ FIELD_PREP(LOAD_CLK_CNTR_INIT_EN, 0) |
-+ FIELD_PREP(FEA_STATUS_DEV_ADDR_MASK, FEA_STATUS_DEV_ADDR) |
-+ FIELD_PREP(SPI_CFG, 0);
-+
-+ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
-+ snandc->regs->num_addr_cycle = cpu_to_le32(SPI_NUM_ADDR);
-+ snandc->regs->busy_wait_cnt = cpu_to_le32(SPI_WAIT_CNT);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
-+
-+ snand_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN;
-+ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->num_addr_cycle, NAND_NUM_ADDR_CYCLES, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->busy_wait_cnt, NAND_BUSY_CHECK_WAIT_CNT, 1,
-+ NAND_BAM_NEXT_SGL);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure in submitting spi init descriptor\n");
-+ return ret;
-+ }
-+
-+ return ret;
-+}
-+
-+static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *oobregion)
-+{
-+ struct nand_device *nand = mtd_to_nanddev(mtd);
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct qpic_ecc *qecc = snandc->qspi->ecc;
-+
-+ if (section > 1)
-+ return -ERANGE;
-+
-+ oobregion->length = qecc->ecc_bytes_hw + qecc->spare_bytes;
-+ oobregion->offset = mtd->oobsize - oobregion->length;
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *oobregion)
-+{
-+ struct nand_device *nand = mtd_to_nanddev(mtd);
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct qpic_ecc *qecc = snandc->qspi->ecc;
-+
-+ if (section)
-+ return -ERANGE;
-+
-+ oobregion->length = qecc->steps * 4;
-+ oobregion->offset = ((qecc->steps - 1) * qecc->bytes) + qecc->bbm_size;
-+
-+ return 0;
-+}
-+
-+static const struct mtd_ooblayout_ops qcom_spi_ooblayout = {
-+ .ecc = qcom_spi_ooblayout_ecc,
-+ .free = qcom_spi_ooblayout_free,
-+};
-+
-+static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
-+{
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
-+ struct mtd_info *mtd = nanddev_to_mtd(nand);
-+ int cwperpage, bad_block_byte;
-+ struct qpic_ecc *ecc_cfg;
-+
-+ cwperpage = mtd->writesize / NANDC_STEP_SIZE;
-+ snandc->qspi->num_cw = cwperpage;
-+
-+ ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
-+ if (!ecc_cfg)
-+ return -ENOMEM;
-+ snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
-+ GFP_KERNEL);
-+ if (!snandc->qspi->oob_buf)
-+ return -ENOMEM;
-+
-+ memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
-+
-+ nand->ecc.ctx.priv = ecc_cfg;
-+ snandc->qspi->mtd = mtd;
-+
-+ ecc_cfg->ecc_bytes_hw = 7;
-+ ecc_cfg->spare_bytes = 4;
-+ ecc_cfg->bbm_size = 1;
-+ ecc_cfg->bch_enabled = true;
-+ ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
-+
-+ ecc_cfg->steps = 4;
-+ ecc_cfg->strength = 4;
-+ ecc_cfg->step_size = 512;
-+ ecc_cfg->cw_data = 516;
-+ ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
-+ bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;
-+
-+ mtd_set_ooblayout(mtd, &qcom_spi_ooblayout);
-+
-+ ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) |
-+ FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
-+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, ecc_cfg->ecc_bytes_hw) |
-+ FIELD_PREP(STATUS_BFR_READ, 0) |
-+ FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, ecc_cfg->spare_bytes);
-+
-+ ecc_cfg->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
-+ FIELD_PREP(WIDE_FLASH, 0) |
-+ FIELD_PREP(ENABLE_BCH_ECC, ecc_cfg->bch_enabled);
-+
-+ ecc_cfg->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_size) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-+
-+ ecc_cfg->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
-+ FIELD_PREP(WIDE_FLASH, 0) |
-+ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-+
-+ ecc_cfg->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !ecc_cfg->bch_enabled) |
-+ FIELD_PREP(ECC_SW_RESET, 0) |
-+ FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
-+ FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
-+ FIELD_PREP(ECC_MODE_MASK, 0) |
-+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
-+
-+ ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
-+ ecc_cfg->clrflashstatus = FS_READY_BSY_N;
-+ ecc_cfg->clrreadstatus = 0xc0;
-+
-+ conf->step_size = ecc_cfg->step_size;
-+ conf->strength = ecc_cfg->strength;
-+
-+ snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET);
-+ snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET);
-+
-+ dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n",
-+ ecc_cfg->strength, ecc_cfg->step_size);
-+
-+ return 0;
-+}
-+
-+static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand)
-+{
-+ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
-+
-+ kfree(ecc_cfg);
-+}
-+
-+static int qcom_spi_ecc_prepare_io_req_pipelined(struct nand_device *nand,
-+ struct nand_page_io_req *req)
-+{
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
-+
-+ snandc->qspi->ecc = ecc_cfg;
-+ snandc->qspi->raw_rw = false;
-+ snandc->qspi->oob_rw = false;
-+ snandc->qspi->page_rw = false;
-+
-+ if (req->datalen)
-+ snandc->qspi->page_rw = true;
-+
-+ if (req->ooblen)
-+ snandc->qspi->oob_rw = true;
-+
-+ if (req->mode == MTD_OPS_RAW)
-+ snandc->qspi->raw_rw = true;
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_ecc_finish_io_req_pipelined(struct nand_device *nand,
-+ struct nand_page_io_req *req)
-+{
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct mtd_info *mtd = nanddev_to_mtd(nand);
-+
-+ if (req->mode == MTD_OPS_RAW || req->type != NAND_PAGE_READ)
-+ return 0;
-+
-+ if (snandc->qspi->ecc_stats.failed)
-+ mtd->ecc_stats.failed += snandc->qspi->ecc_stats.failed;
-+ else
-+ mtd->ecc_stats.corrected += snandc->qspi->ecc_stats.corrected;
-+
-+ if (snandc->qspi->ecc_stats.failed)
-+ return -EBADMSG;
-+ else
-+ return snandc->qspi->ecc_stats.bitflips;
-+}
-+
-+static struct nand_ecc_engine_ops qcom_spi_ecc_engine_ops_pipelined = {
-+ .init_ctx = qcom_spi_ecc_init_ctx_pipelined,
-+ .cleanup_ctx = qcom_spi_ecc_cleanup_ctx_pipelined,
-+ .prepare_io_req = qcom_spi_ecc_prepare_io_req_pipelined,
-+ .finish_io_req = qcom_spi_ecc_finish_io_req_pipelined,
-+};
-+
-+/* helper to configure location register values */
-+static void qcom_spi_set_read_loc(struct qcom_nand_controller *snandc, int cw, int reg,
-+ int cw_offset, int read_size, int is_last_read_loc)
-+{
-+ int reg_base = NAND_READ_LOCATION_0;
-+ int num_cw = snandc->qspi->num_cw;
-+
-+ if (cw == (num_cw - 1))
-+ reg_base = NAND_READ_LOCATION_LAST_CW_0;
-+
-+ reg_base += reg * 4;
-+
-+ if (cw == (num_cw - 1))
-+ return qcom_spi_set_read_loc_last(snandc, reg_base, cw_offset,
-+ read_size, is_last_read_loc);
-+ else
-+ return qcom_spi_set_read_loc_first(snandc, reg_base, cw_offset,
-+ read_size, is_last_read_loc);
-+}
-+
-+static void
-+qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int cw)
-+{
-+ __le32 *reg = &snandc->regs->read_location0;
-+ int num_cw = snandc->qspi->num_cw;
-+
-+ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
-+ if (cw == (num_cw - 1)) {
-+ reg = &snandc->regs->read_location_last0;
-+ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4,
-+ NAND_BAM_NEXT_SGL);
-+ }
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0);
-+ qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-+ NAND_BAM_NEXT_SGL);
-+}
-+
-+static int qcom_spi_block_erase(struct qcom_nand_controller *snandc)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ int ret;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE));
-+ snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to erase block\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *snandc,
-+ bool use_ecc, int cw)
-+{
-+ __le32 *reg = &snandc->regs->read_location0;
-+ int num_cw = snandc->qspi->num_cw;
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1,
-+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+ if (cw == (num_cw - 1)) {
-+ reg = &snandc->regs->read_location_last0;
-+ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, NAND_BAM_NEXT_SGL);
-+ }
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0);
-+}
-+
-+static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ struct mtd_info *mtd = snandc->qspi->mtd;
-+ int size, ret = 0;
-+ int col, bbpos;
-+ u32 cfg0, cfg1, ecc_bch_cfg;
-+ u32 num_cw = snandc->qspi->num_cw;
-+
-+ qcom_clear_bam_transaction(snandc);
-+ qcom_clear_read_regs(snandc);
-+
-+ size = ecc_cfg->cw_size;
-+ col = ecc_cfg->cw_size * (num_cw - 1);
-+
-+ memset(snandc->data_buffer, 0xff, size);
-+ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+
-+ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+ 0 << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1_raw;
-+ ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-+
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1);
-+
-+ qcom_spi_config_single_cw_page_read(snandc, false, num_cw - 1);
-+
-+ qcom_read_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, size, 0);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failed to read last cw\n");
-+ return ret;
-+ }
-+
-+ qcom_nandc_dev_to_mem(snandc, true);
-+ u32 flash = le32_to_cpu(snandc->reg_read_buf[0]);
-+
-+ if (flash & (FS_OP_ERR | FS_MPU_ERR))
-+ return -EIO;
-+
-+ bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
-+
-+ if (snandc->data_buffer[bbpos] == 0xff)
-+ snandc->data_buffer[bbpos + 1] = 0xff;
-+ if (snandc->data_buffer[bbpos] != 0xff)
-+ snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos];
-+
-+ memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes);
-+
-+ return ret;
-+}
-+
-+static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf)
-+{
-+ struct snandc_read_status *buf;
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ int i, num_cw = snandc->qspi->num_cw;
-+ bool flash_op_err = false, erased;
-+ unsigned int max_bitflips = 0;
-+ unsigned int uncorrectable_cws = 0;
-+
-+ snandc->qspi->ecc_stats.failed = 0;
-+ snandc->qspi->ecc_stats.corrected = 0;
-+
-+ qcom_nandc_dev_to_mem(snandc, true);
-+ buf = (struct snandc_read_status *)snandc->reg_read_buf;
-+
-+ for (i = 0; i < num_cw; i++, buf++) {
-+ u32 flash, buffer, erased_cw;
-+ int data_len, oob_len;
-+
-+ if (i == (num_cw - 1)) {
-+ data_len = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+ oob_len = num_cw << 2;
-+ } else {
-+ data_len = ecc_cfg->cw_data;
-+ oob_len = 0;
-+ }
-+
-+ flash = le32_to_cpu(buf->snandc_flash);
-+ buffer = le32_to_cpu(buf->snandc_buffer);
-+ erased_cw = le32_to_cpu(buf->snandc_erased_cw);
-+
-+ if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
-+ if (ecc_cfg->bch_enabled)
-+ erased = (erased_cw & ERASED_CW) == ERASED_CW;
-+ else
-+ erased = false;
-+
-+ if (!erased)
-+ uncorrectable_cws |= BIT(i);
-+
-+ } else if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
-+ flash_op_err = true;
-+ } else {
-+ unsigned int stat;
-+
-+ stat = buffer & BS_CORRECTABLE_ERR_MSK;
-+ snandc->qspi->ecc_stats.corrected += stat;
-+ max_bitflips = max(max_bitflips, stat);
-+ }
-+
-+ if (data_buf)
-+ data_buf += data_len;
-+ if (oob_buf)
-+ oob_buf += oob_len + ecc_cfg->bytes;
-+ }
-+
-+ if (flash_op_err)
-+ return -EIO;
-+
-+ if (!uncorrectable_cws)
-+ snandc->qspi->ecc_stats.bitflips = max_bitflips;
-+ else
-+ snandc->qspi->ecc_stats.failed++;
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt)
-+{
-+ int i;
-+
-+ qcom_nandc_dev_to_mem(snandc, true);
-+
-+ for (i = 0; i < cw_cnt; i++) {
-+ u32 flash = le32_to_cpu(snandc->reg_read_buf[i]);
-+
-+ if (flash & (FS_OP_ERR | FS_MPU_ERR))
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf,
-+ u8 *oob_buf, int cw)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ struct mtd_info *mtd = snandc->qspi->mtd;
-+ int data_size1, data_size2, oob_size1, oob_size2;
-+ int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
-+ int raw_cw = cw;
-+ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
-+ int col;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+ raw_cw = num_cw - 1;
-+
-+ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+ 0 << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1_raw;
-+ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
-+
-+ col = ecc_cfg->cw_size * cw;
-+
-+ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1,
-+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
-+ oob_size1 = ecc_cfg->bbm_size;
-+
-+ if (cw == (num_cw - 1)) {
-+ data_size2 = NANDC_STEP_SIZE - data_size1 -
-+ ((num_cw - 1) * 4);
-+ oob_size2 = (num_cw * 4) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size2 = ecc_cfg->cw_data - data_size1;
-+ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+ }
-+
-+ qcom_spi_set_read_loc(snandc, cw, 0, read_loc, data_size1, 0);
-+ read_loc += data_size1;
-+
-+ qcom_spi_set_read_loc(snandc, cw, 1, read_loc, oob_size1, 0);
-+ read_loc += oob_size1;
-+
-+ qcom_spi_set_read_loc(snandc, cw, 2, read_loc, data_size2, 0);
-+ read_loc += data_size2;
-+
-+ qcom_spi_set_read_loc(snandc, cw, 3, read_loc, oob_size2, 1);
-+
-+ qcom_spi_config_cw_read(snandc, false, raw_cw);
-+
-+ qcom_read_data_dma(snandc, reg_off, data_buf, data_size1, 0);
-+ reg_off += data_size1;
-+
-+ qcom_read_data_dma(snandc, reg_off, oob_buf, oob_size1, 0);
-+ reg_off += oob_size1;
-+
-+ qcom_read_data_dma(snandc, reg_off, data_buf + data_size1, data_size2, 0);
-+ reg_off += data_size2;
-+
-+ qcom_read_data_dma(snandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to read raw cw %d\n", cw);
-+ return ret;
-+ }
-+
-+ return qcom_spi_check_raw_flash_errors(snandc, 1);
-+}
-+
-+static int qcom_spi_read_page_raw(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *data_buf = NULL, *oob_buf = NULL;
-+ int ret, cw;
-+ u32 num_cw = snandc->qspi->num_cw;
-+
-+ if (snandc->qspi->page_rw)
-+ data_buf = op->data.buf.in;
-+
-+ oob_buf = snandc->qspi->oob_buf;
-+ memset(oob_buf, 0xff, OOB_BUF_SIZE);
-+
-+ for (cw = 0; cw < num_cw; cw++) {
-+ ret = qcom_spi_read_cw_raw(snandc, data_buf, oob_buf, cw);
-+ if (ret)
-+ return ret;
-+
-+ if (data_buf)
-+ data_buf += ecc_cfg->cw_data;
-+ if (oob_buf)
-+ oob_buf += ecc_cfg->bytes;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
-+ int ret, i;
-+ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
-+
-+ data_buf = op->data.buf.in;
-+ data_buf_start = data_buf;
-+
-+ oob_buf = snandc->qspi->oob_buf;
-+ oob_buf_start = oob_buf;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+
-+ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1;
-+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
-+
-+ qcom_clear_bam_transaction(snandc);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1,
-+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+ for (i = 0; i < num_cw; i++) {
-+ int data_size, oob_size;
-+
-+ if (i == (num_cw - 1)) {
-+ data_size = 512 - ((num_cw - 1) << 2);
-+ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size = ecc_cfg->cw_data;
-+ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+ }
-+
-+ if (data_buf && oob_buf) {
-+ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 0);
-+ qcom_spi_set_read_loc(snandc, i, 1, data_size, oob_size, 1);
-+ } else if (data_buf) {
-+ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 1);
-+ } else {
-+ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
-+ }
-+
-+ qcom_spi_config_cw_read(snandc, true, i);
-+
-+ if (data_buf)
-+ qcom_read_data_dma(snandc, FLASH_BUF_ACC, data_buf,
-+ data_size, 0);
-+ if (oob_buf) {
-+ int j;
-+
-+ for (j = 0; j < ecc_cfg->bbm_size; j++)
-+ *oob_buf++ = 0xff;
-+
-+ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
-+ }
-+
-+ if (data_buf)
-+ data_buf += data_size;
-+ if (oob_buf)
-+ oob_buf += oob_size;
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to read page\n");
-+ return ret;
-+ }
-+
-+ return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
-+}
-+
-+static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
-+ int ret, i;
-+ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
-+
-+ oob_buf = op->data.buf.in;
-+ oob_buf_start = oob_buf;
-+
-+ data_buf_start = data_buf;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1;
-+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1,
-+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+ for (i = 0; i < num_cw; i++) {
-+ int data_size, oob_size;
-+
-+ if (i == (num_cw - 1)) {
-+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size = ecc_cfg->cw_data;
-+ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+ }
-+
-+ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
-+
-+ qcom_spi_config_cw_read(snandc, true, i);
-+
-+ if (oob_buf) {
-+ int j;
-+
-+ for (j = 0; j < ecc_cfg->bbm_size; j++)
-+ *oob_buf++ = 0xff;
-+
-+ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
-+ }
-+
-+ if (oob_buf)
-+ oob_buf += oob_size;
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to read oob\n");
-+ return ret;
-+ }
-+
-+ return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
-+}
-+
-+static int qcom_spi_read_page(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
-+ return qcom_spi_read_page_raw(snandc, op);
-+
-+ if (snandc->qspi->page_rw)
-+ return qcom_spi_read_page_ecc(snandc, op);
-+
-+ if (snandc->qspi->oob_rw && snandc->qspi->raw_rw)
-+ return qcom_spi_read_last_cw(snandc, op);
-+
-+ if (snandc->qspi->oob_rw)
-+ return qcom_spi_read_page_oob(snandc, op);
-+
-+ return 0;
-+}
-+
-+static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc)
-+{
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG,
-+ 1, NAND_BAM_NEXT_SGL);
-+}
-+
-+static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc)
-+{
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->clrreadstatus, NAND_READ_STATUS, 1,
-+ NAND_BAM_NEXT_SGL);
-+}
-+
-+static int qcom_spi_program_raw(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ struct mtd_info *mtd = snandc->qspi->mtd;
-+ u8 *data_buf = NULL, *oob_buf = NULL;
-+ int i, ret;
-+ int num_cw = snandc->qspi->num_cw;
-+ u32 cfg0, cfg1, ecc_bch_cfg;
-+
-+ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1_raw;
-+ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
-+
-+ data_buf = snandc->qspi->data_buf;
-+
-+ oob_buf = snandc->qspi->oob_buf;
-+ memset(oob_buf, 0xff, OOB_BUF_SIZE);
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_config_page_write(snandc);
-+
-+ for (i = 0; i < num_cw; i++) {
-+ int data_size1, data_size2, oob_size1, oob_size2;
-+ int reg_off = FLASH_BUF_ACC;
-+
-+ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
-+ oob_size1 = ecc_cfg->bbm_size;
-+
-+ if (i == (num_cw - 1)) {
-+ data_size2 = NANDC_STEP_SIZE - data_size1 -
-+ ((num_cw - 1) << 2);
-+ oob_size2 = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size2 = ecc_cfg->cw_data - data_size1;
-+ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+ }
-+
-+ qcom_write_data_dma(snandc, reg_off, data_buf, data_size1,
-+ NAND_BAM_NO_EOT);
-+ reg_off += data_size1;
-+ data_buf += data_size1;
-+
-+ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size1,
-+ NAND_BAM_NO_EOT);
-+ oob_buf += oob_size1;
-+ reg_off += oob_size1;
-+
-+ qcom_write_data_dma(snandc, reg_off, data_buf, data_size2,
-+ NAND_BAM_NO_EOT);
-+ reg_off += data_size2;
-+ data_buf += data_size2;
-+
-+ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size2, 0);
-+ oob_buf += oob_size2;
-+
-+ qcom_spi_config_cw_write(snandc);
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to write raw page\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *data_buf = NULL, *oob_buf = NULL;
-+ int i, ret;
-+ int num_cw = snandc->qspi->num_cw;
-+ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
-+
-+ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1;
-+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
-+
-+ if (snandc->qspi->data_buf)
-+ data_buf = snandc->qspi->data_buf;
-+
-+ oob_buf = snandc->qspi->oob_buf;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_config_page_write(snandc);
-+
-+ for (i = 0; i < num_cw; i++) {
-+ int data_size, oob_size;
-+
-+ if (i == (num_cw - 1)) {
-+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size = ecc_cfg->cw_data;
-+ oob_size = ecc_cfg->bytes;
-+ }
-+
-+ if (data_buf)
-+ qcom_write_data_dma(snandc, FLASH_BUF_ACC, data_buf, data_size,
-+ i == (num_cw - 1) ? NAND_BAM_NO_EOT : 0);
-+
-+ if (i == (num_cw - 1)) {
-+ if (oob_buf) {
-+ oob_buf += ecc_cfg->bbm_size;
-+ qcom_write_data_dma(snandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
-+ }
-+ }
-+
-+ qcom_spi_config_cw_write(snandc);
-+
-+ if (data_buf)
-+ data_buf += data_size;
-+ if (oob_buf)
-+ oob_buf += oob_size;
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to write page\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_program_oob(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *oob_buf = NULL;
-+ int ret, col, data_size, oob_size;
-+ int num_cw = snandc->qspi->num_cw;
-+ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
-+
-+ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1;
-+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
-+
-+ col = ecc_cfg->cw_size * (num_cw - 1);
-+
-+ oob_buf = snandc->qspi->data_buf;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ /* calculate the data and oob size for the last codeword/step */
-+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+ oob_size = snandc->qspi->mtd->oobavail;
-+
-+ memset(snandc->data_buffer, 0xff, ecc_cfg->cw_data);
-+ /* override new oob content to last codeword */
-+ mtd_ooblayout_get_databytes(snandc->qspi->mtd, snandc->data_buffer + data_size,
-+ oob_buf, 0, snandc->qspi->mtd->oobavail);
-+ qcom_spi_config_page_write(snandc);
-+ qcom_write_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, data_size + oob_size, 0);
-+ qcom_spi_config_cw_write(snandc);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to write oob\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_program_execute(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
-+ return qcom_spi_program_raw(snandc, op);
-+
-+ if (snandc->qspi->page_rw)
-+ return qcom_spi_program_ecc(snandc, op);
-+
-+ if (snandc->qspi->oob_rw)
-+ return qcom_spi_program_oob(snandc, op);
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd)
-+{
-+ switch (opcode) {
-+ case SPINAND_RESET:
-+ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE);
-+ break;
-+ case SPINAND_READID:
-+ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID);
-+ break;
-+ case SPINAND_GET_FEATURE:
-+ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE);
-+ break;
-+ case SPINAND_SET_FEATURE:
-+ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE |
-+ QPIC_SET_FEATURE);
-+ break;
-+ case SPINAND_READ:
-+ if (snandc->qspi->raw_rw) {
-+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
-+ SPI_WP | SPI_HOLD | OP_PAGE_READ);
-+ } else {
-+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
-+ SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC);
-+ }
-+
-+ break;
-+ case SPINAND_ERASE:
-+ *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP |
-+ SPI_HOLD | SPI_TRANSFER_MODE_x1;
-+ break;
-+ case SPINAND_WRITE_EN:
-+ *cmd = SPINAND_WRITE_EN;
-+ break;
-+ case SPINAND_PROGRAM_EXECUTE:
-+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
-+ SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
-+ break;
-+ case SPINAND_PROGRAM_LOAD:
-+ *cmd = SPINAND_PROGRAM_LOAD;
-+ break;
-+ default:
-+ dev_err(snandc->dev, "Opcode not supported: %u\n", opcode);
-+ return -EOPNOTSUPP;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_write_page(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ int ret;
-+ u32 cmd;
-+
-+ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (op->cmd.opcode == SPINAND_PROGRAM_LOAD)
-+ snandc->qspi->data_buf = (u8 *)op->data.buf.out;
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_snand_op s_op = {};
-+ u32 cmd;
-+ int ret, opcode;
-+
-+ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
-+ if (ret < 0)
-+ return ret;
-+
-+ s_op.cmd_reg = cmd;
-+ s_op.addr1_reg = op->addr.val;
-+ s_op.addr2_reg = 0;
-+
-+ opcode = op->cmd.opcode;
-+
-+ switch (opcode) {
-+ case SPINAND_WRITE_EN:
-+ return 0;
-+ case SPINAND_PROGRAM_EXECUTE:
-+ s_op.addr1_reg = op->addr.val << 16;
-+ s_op.addr2_reg = op->addr.val >> 16 & 0xff;
-+ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
-+ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
-+ snandc->qspi->cmd = cpu_to_le32(cmd);
-+ return qcom_spi_program_execute(snandc, op);
-+ case SPINAND_READ:
-+ s_op.addr1_reg = (op->addr.val << 16);
-+ s_op.addr2_reg = op->addr.val >> 16 & 0xff;
-+ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
-+ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
-+ snandc->qspi->cmd = cpu_to_le32(cmd);
-+ return 0;
-+ case SPINAND_ERASE:
-+ s_op.addr2_reg = (op->addr.val >> 16) & 0xffff;
-+ s_op.addr1_reg = op->addr.val;
-+ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16);
-+ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
-+ snandc->qspi->cmd = cpu_to_le32(cmd);
-+ qcom_spi_block_erase(snandc);
-+ return 0;
-+ default:
-+ break;
-+ }
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ snandc->regs->cmd = cpu_to_le32(s_op.cmd_reg);
-+ snandc->regs->exec = cpu_to_le32(1);
-+ snandc->regs->addr0 = cpu_to_le32(s_op.addr1_reg);
-+ snandc->regs->addr1 = cpu_to_le32(s_op.addr2_reg);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret)
-+ dev_err(snandc->dev, "failure in submitting cmd descriptor\n");
-+
-+ return ret;
-+}
-+
-+static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_mem_op *op)
-+{
-+ int ret, val, opcode;
-+ bool copy = false, copy_ftr = false;
-+
-+ ret = qcom_spi_send_cmdaddr(snandc, op);
-+ if (ret)
-+ return ret;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+ opcode = op->cmd.opcode;
-+
-+ switch (opcode) {
-+ case SPINAND_READID:
-+ snandc->buf_count = 4;
-+ qcom_read_reg_dma(snandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-+ copy = true;
-+ break;
-+ case SPINAND_GET_FEATURE:
-+ snandc->buf_count = 4;
-+ qcom_read_reg_dma(snandc, NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
-+ copy_ftr = true;
-+ break;
-+ case SPINAND_SET_FEATURE:
-+ snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out);
-+ qcom_write_reg_dma(snandc, &snandc->regs->flash_feature,
-+ NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
-+ break;
-+ case SPINAND_PROGRAM_EXECUTE:
-+ case SPINAND_WRITE_EN:
-+ case SPINAND_RESET:
-+ case SPINAND_ERASE:
-+ case SPINAND_READ:
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret)
-+ dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode);
-+
-+ if (copy) {
-+ qcom_nandc_dev_to_mem(snandc, true);
-+ memcpy(op->data.buf.in, snandc->reg_read_buf, snandc->buf_count);
-+ }
-+
-+ if (copy_ftr) {
-+ qcom_nandc_dev_to_mem(snandc, true);
-+ val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf);
-+ val >>= 8;
-+ memcpy(op->data.buf.in, &val, snandc->buf_count);
-+ }
-+
-+ return ret;
-+}
-+
-+static bool qcom_spi_is_page_op(const struct spi_mem_op *op)
-+{
-+ if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && op->addr.buswidth != 4)
-+ return false;
-+
-+ if (op->data.dir == SPI_MEM_DATA_IN) {
-+ if (op->addr.buswidth == 4 && op->data.buswidth == 4)
-+ return true;
-+
-+ if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
-+ return true;
-+
-+ } else if (op->data.dir == SPI_MEM_DATA_OUT) {
-+ if (op->data.buswidth == 4)
-+ return true;
-+ if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
-+{
-+ if (!spi_mem_default_supports_op(mem, op))
-+ return false;
-+
-+ if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1)
-+ return false;
-+
-+ if (qcom_spi_is_page_op(op))
-+ return true;
-+
-+ return ((!op->addr.nbytes || op->addr.buswidth == 1) &&
-+ (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
-+ (!op->data.nbytes || op->data.buswidth == 1));
-+}
-+
-+static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
-+{
-+ struct qcom_nand_controller *snandc = spi_controller_get_devdata(mem->spi->controller);
-+
-+ dev_dbg(snandc->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode,
-+ op->addr.val, op->addr.buswidth, op->addr.nbytes,
-+ op->data.buswidth, op->data.nbytes);
-+
-+ if (qcom_spi_is_page_op(op)) {
-+ if (op->data.dir == SPI_MEM_DATA_IN)
-+ return qcom_spi_read_page(snandc, op);
-+ if (op->data.dir == SPI_MEM_DATA_OUT)
-+ return qcom_spi_write_page(snandc, op);
-+ } else {
-+ return qcom_spi_io_op(snandc, op);
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct spi_controller_mem_ops qcom_spi_mem_ops = {
-+ .supports_op = qcom_spi_supports_op,
-+ .exec_op = qcom_spi_exec_op,
-+};
-+
-+static const struct spi_controller_mem_caps qcom_spi_mem_caps = {
-+ .ecc = true,
-+};
-+
-+static int qcom_spi_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct spi_controller *ctlr;
-+ struct qcom_nand_controller *snandc;
-+ struct qpic_spi_nand *qspi;
-+ struct qpic_ecc *ecc;
-+ struct resource *res;
-+ const void *dev_data;
-+ int ret;
-+
-+ ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
-+ if (!ecc)
-+ return -ENOMEM;
-+
-+ qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
-+ if (!qspi)
-+ return -ENOMEM;
-+
-+ ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false);
-+ if (!ctlr)
-+ return -ENOMEM;
-+
-+ platform_set_drvdata(pdev, ctlr);
-+
-+ snandc = spi_controller_get_devdata(ctlr);
-+ qspi->snandc = snandc;
-+
-+ snandc->dev = dev;
-+ snandc->qspi = qspi;
-+ snandc->qspi->ctlr = ctlr;
-+ snandc->qspi->ecc = ecc;
-+
-+ dev_data = of_device_get_match_data(dev);
-+ if (!dev_data) {
-+ dev_err(&pdev->dev, "failed to get device data\n");
-+ return -ENODEV;
-+ }
-+
-+ snandc->props = dev_data;
-+ snandc->dev = &pdev->dev;
-+
-+ snandc->core_clk = devm_clk_get(dev, "core");
-+ if (IS_ERR(snandc->core_clk))
-+ return PTR_ERR(snandc->core_clk);
-+
-+ snandc->aon_clk = devm_clk_get(dev, "aon");
-+ if (IS_ERR(snandc->aon_clk))
-+ return PTR_ERR(snandc->aon_clk);
-+
-+ snandc->qspi->iomacro_clk = devm_clk_get(dev, "iom");
-+ if (IS_ERR(snandc->qspi->iomacro_clk))
-+ return PTR_ERR(snandc->qspi->iomacro_clk);
-+
-+ snandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-+ if (IS_ERR(snandc->base))
-+ return PTR_ERR(snandc->base);
-+
-+ snandc->base_phys = res->start;
-+ snandc->base_dma = dma_map_resource(dev, res->start, resource_size(res),
-+ DMA_BIDIRECTIONAL, 0);
-+ if (dma_mapping_error(dev, snandc->base_dma))
-+ return -ENXIO;
-+
-+ ret = clk_prepare_enable(snandc->core_clk);
-+ if (ret)
-+ goto err_dis_core_clk;
-+
-+ ret = clk_prepare_enable(snandc->aon_clk);
-+ if (ret)
-+ goto err_dis_aon_clk;
-+
-+ ret = clk_prepare_enable(snandc->qspi->iomacro_clk);
-+ if (ret)
-+ goto err_dis_iom_clk;
-+
-+ ret = qcom_nandc_alloc(snandc);
-+ if (ret)
-+ goto err_snand_alloc;
-+
-+ ret = qcom_spi_init(snandc);
-+ if (ret)
-+ goto err_spi_init;
-+
-+ /* setup ECC engine */
-+ snandc->qspi->ecc_eng.dev = &pdev->dev;
-+ snandc->qspi->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
-+ snandc->qspi->ecc_eng.ops = &qcom_spi_ecc_engine_ops_pipelined;
-+ snandc->qspi->ecc_eng.priv = snandc;
-+
-+ ret = nand_ecc_register_on_host_hw_engine(&snandc->qspi->ecc_eng);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to register ecc engine:%d\n", ret);
-+ goto err_spi_init;
-+ }
-+
-+ ctlr->num_chipselect = QPIC_QSPI_NUM_CS;
-+ ctlr->mem_ops = &qcom_spi_mem_ops;
-+ ctlr->mem_caps = &qcom_spi_mem_caps;
-+ ctlr->dev.of_node = pdev->dev.of_node;
-+ ctlr->mode_bits = SPI_TX_DUAL | SPI_RX_DUAL |
-+ SPI_TX_QUAD | SPI_RX_QUAD;
-+
-+ ret = spi_register_controller(ctlr);
-+ if (ret) {
-+ dev_err(&pdev->dev, "spi_register_controller failed.\n");
-+ goto err_spi_init;
-+ }
-+
-+ return 0;
-+
-+err_spi_init:
-+ qcom_nandc_unalloc(snandc);
-+err_snand_alloc:
-+ clk_disable_unprepare(snandc->qspi->iomacro_clk);
-+err_dis_iom_clk:
-+ clk_disable_unprepare(snandc->aon_clk);
-+err_dis_aon_clk:
-+ clk_disable_unprepare(snandc->core_clk);
-+err_dis_core_clk:
-+ dma_unmap_resource(dev, res->start, resource_size(res),
-+ DMA_BIDIRECTIONAL, 0);
-+ return ret;
-+}
-+
-+static void qcom_spi_remove(struct platform_device *pdev)
-+{
-+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
-+ struct qcom_nand_controller *snandc = spi_controller_get_devdata(ctlr);
-+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+
-+ spi_unregister_controller(ctlr);
-+
-+ qcom_nandc_unalloc(snandc);
-+
-+ clk_disable_unprepare(snandc->aon_clk);
-+ clk_disable_unprepare(snandc->core_clk);
-+ clk_disable_unprepare(snandc->qspi->iomacro_clk);
-+
-+ dma_unmap_resource(&pdev->dev, snandc->base_dma, resource_size(res),
-+ DMA_BIDIRECTIONAL, 0);
-+}
-+
-+static const struct qcom_nandc_props ipq9574_snandc_props = {
-+ .dev_cmd_reg_start = 0x7000,
-+ .supports_bam = true,
-+};
-+
-+static const struct of_device_id qcom_snandc_of_match[] = {
-+ {
-+ .compatible = "qcom,ipq9574-snand",
-+ .data = &ipq9574_snandc_props,
-+ },
-+ {}
-+}
-+MODULE_DEVICE_TABLE(of, qcom_snandc_of_match);
-+
-+static struct platform_driver qcom_spi_driver = {
-+ .driver = {
-+ .name = "qcom_snand",
-+ .of_match_table = qcom_snandc_of_match,
-+ },
-+ .probe = qcom_spi_probe,
-+ .remove_new = qcom_spi_remove,
-+};
-+module_platform_driver(qcom_spi_driver);
-+
-+MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores");
-+MODULE_LICENSE("GPL");
-+
---- a/include/linux/mtd/nand-qpic-common.h
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -325,6 +325,10 @@ struct nandc_regs {
- __le32 read_location_last1;
- __le32 read_location_last2;
- __le32 read_location_last3;
-+ __le32 spi_cfg;
-+ __le32 num_addr_cycle;
-+ __le32 busy_wait_cnt;
-+ __le32 flash_feature;
-
- __le32 erased_cw_detect_cfg_clr;
- __le32 erased_cw_detect_cfg_set;
-@@ -339,6 +343,7 @@ struct nandc_regs {
- *
- * @core_clk: controller clock
- * @aon_clk: another controller clock
-+ * @iomacro_clk: io macro clock
- *
- * @regs: a contiguous chunk of memory for DMA register
- * writes. contains the register values to be
-@@ -348,6 +353,7 @@ struct nandc_regs {
- * initialized via DT match data
- *
- * @controller: base controller structure
-+ * @qspi: qpic spi structure
- * @host_list: list containing all the chips attached to the
- * controller
- *
-@@ -392,6 +398,7 @@ struct qcom_nand_controller {
- const struct qcom_nandc_props *props;
-
- struct nand_controller *controller;
-+ struct qpic_spi_nand *qspi;
- struct list_head host_list;
-
- union {
+++ /dev/null
-From cf1ba3cb245020459f2ca446b7a7b199839f5d83 Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Mar 2025 12:40:01 +0300
-Subject: [PATCH] spi: spi-qpic-snand: Fix ECC_CFG_ECC_DISABLE shift in
- qcom_spi_read_last_cw()
-
-The ECC_CFG_ECC_DISABLE define is BIT(0). It's supposed to be used
-directly instead of used as a shifter.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
----
- drivers/spi/spi-qpic-snand.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -514,7 +514,7 @@ static int qcom_spi_read_last_cw(struct
- cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
- 0 << CW_PER_PAGE;
- cfg1 = ecc_cfg->cfg1_raw;
-- ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-+ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
-
- snandc->regs->cmd = snandc->qspi->cmd;
- snandc->regs->cfg0 = cpu_to_le32(cfg0);
+++ /dev/null
-From d450cdd9c4398add1f2aa7200f2c95f1e3b9f9fa Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Mar 2025 19:31:21 +0100
-Subject: [PATCH] spi: spi-qpic-snand: avoid memleak in
- qcom_spi_ecc_init_ctx_pipelined()
-
-When the allocation of the OOB buffer fails, the
-qcom_spi_ecc_init_ctx_pipelined() function returns without freeing
-the memory allocated for 'ecc_cfg' thus it can cause a memory leak.
-
-Call kfree() to free 'ecc_cfg' before returning from the function
-to avoid that.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
----
- drivers/spi/spi-qpic-snand.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -263,8 +263,10 @@ static int qcom_spi_ecc_init_ctx_pipelin
- return -ENOMEM;
- snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
- GFP_KERNEL);
-- if (!snandc->qspi->oob_buf)
-+ if (!snandc->qspi->oob_buf) {
-+ kfree(ecc_cfg);
- return -ENOMEM;
-+ }
-
- memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
-
+++ /dev/null
-From d32c4e58545f17caaa854415f854691e32d42075 Mon Sep 17 00:00:00 2001
-Date: Wed, 26 Mar 2025 15:22:19 +0100
-Subject: [PATCH] spi: SPI_QPIC_SNAND should be tristate and depend on MTD
-
-SPI_QPIC_SNAND is the only driver that selects MTD instead of depending
-on it, which could lead to circular dependencies. Moreover, as
-SPI_QPIC_SNAND is bool, this forces MTD (and various related symbols) to
-be built-in, as can be seen in an allmodconfig kernel.
-
-Except for a missing semicolon, there is no reason why SPI_QPIC_SNAND
-cannot be tristate; all MODULE_*() boilerplate is already present.
-Hence make SPI_QPIC_SNAND tristate, let it depend on MTD, and add the
-missing semicolon.
-
-Fixes: 7304d1909080ef0c ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
-Link: https://patch.msgid.link/b63db431cbf35223a4400e44c296293d32c4543c.1742998909.git.geert+renesas@glider.be
----
- drivers/spi/Kconfig | 4 ++--
- drivers/spi/spi-qpic-snand.c | 2 +-
- 2 files changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -899,9 +899,9 @@ config SPI_QCOM_QSPI
- QSPI(Quad SPI) driver for Qualcomm QSPI controller.
-
- config SPI_QPIC_SNAND
-- bool "QPIC SNAND controller"
-+ tristate "QPIC SNAND controller"
- depends on ARCH_QCOM || COMPILE_TEST
-- select MTD
-+ depends on MTD
- help
- QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller.
- QPIC controller supports both parallel nand and serial nand.
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -1614,7 +1614,7 @@ static const struct of_device_id qcom_sn
- .data = &ipq9574_snandc_props,
- },
- {}
--}
-+};
- MODULE_DEVICE_TABLE(of, qcom_snandc_of_match);
-
- static struct platform_driver qcom_spi_driver = {
+++ /dev/null
-Date: Wed, 23 Apr 2025 21:31:57 +0200
-Subject: [PATCH] spi: spi-qpic-snand: propagate errors from
- qcom_spi_block_erase()
-
-The qcom_spi_block_erase() function returns with error in case of
-failure. Change the qcom_spi_send_cmdaddr() function to propagate
-these errors to the callers instead of returning with success.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
----
- drivers/spi/spi-qpic-snand.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-
----
-base-commit: 9c32cda43eb78f78c73aee4aa344b777714e259b
-change-id: 20250422-qpic-snand-propagate-error-9c95811ab811
-
-Best regards,
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -1307,8 +1307,7 @@ static int qcom_spi_send_cmdaddr(struct
- snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16);
- snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
- snandc->qspi->cmd = cpu_to_le32(cmd);
-- qcom_spi_block_erase(snandc);
-- return 0;
-+ return qcom_spi_block_erase(snandc);
- default:
- break;
- }
+++ /dev/null
-Date: Mon, 28 Apr 2025 09:30:55 +0200
-Subject: [PATCH] spi: spi-qpic-snand: fix NAND_READ_LOCATION_2 register
- handling
-
-The precomputed value for the NAND_READ_LOCATION_2 register should be
-stored in 'snandc->regs->read_location2'.
-
-Fix the qcom_spi_set_read_loc_first() function accordingly.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
----
- drivers/spi/spi-qpic-snand.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-
----
-base-commit: 15cfe55ec58ace931a73e19e5367598734ceb074
-change-id: 20250428-qpic-snand-readloc2-fix-bccd07cf26d3
-
-Best regards,
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -142,7 +142,7 @@ static void qcom_spi_set_read_loc_first(
- else if (reg == NAND_READ_LOCATION_1)
- snandc->regs->read_location1 = locreg_val;
- else if (reg == NAND_READ_LOCATION_2)
-- snandc->regs->read_location1 = locreg_val;
-+ snandc->regs->read_location2 = locreg_val;
- else if (reg == NAND_READ_LOCATION_3)
- snandc->regs->read_location3 = locreg_val;
- }
+++ /dev/null
-From f48d80503504257682e493dc17408f2f0b47bcfa Mon Sep 17 00:00:00 2001
-Date: Thu, 20 Mar 2025 19:11:59 +0100
-Subject: [PATCH] spi: spi-qpic-snand: use kmalloc() for OOB buffer allocation
-
-The qcom_spi_ecc_init_ctx_pipelined() function allocates zeroed
-memory for the OOB buffer, then it fills the buffer with '0xff'
-bytes right after the allocation. In this case zeroing the memory
-during allocation is superfluous, so use kmalloc() instead of
-kzalloc() to avoid that.
-
----
- drivers/spi/spi-qpic-snand.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -261,7 +261,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
- ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
- if (!ecc_cfg)
- return -ENOMEM;
-- snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
-+ snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize,
- GFP_KERNEL);
- if (!snandc->qspi->oob_buf) {
- kfree(ecc_cfg);
+++ /dev/null
-Date: Thu, 24 Apr 2025 20:10:59 +0200
-Subject: [PATCH] spi: spi-qpic-snand: remove unused 'wlen' member of
- 'struct qpic_spi_nand'
-
-The 'wlen' member of the qpic_spi_nand structure is never used in the
-code so remove that.
-
----
- drivers/spi/spi-qpic-snand.c | 1 -
- 1 file changed, 1 deletion(-)
-
-
----
-base-commit: 9c32cda43eb78f78c73aee4aa344b777714e259b
-change-id: 20250424-qpic-snand-remove-wlen-c0cef3801a7f
-
-Best regards,
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -116,7 +116,6 @@ struct qpic_spi_nand {
- struct nand_ecc_engine ecc_eng;
- u8 *data_buf;
- u8 *oob_buf;
-- u32 wlen;
- __le32 addr1;
- __le32 addr2;
- __le32 cmd;
--- /dev/null
+From 03cb793b26834ddca170ba87057c8f883772dd45 Mon Sep 17 00:00:00 2001
+Date: Thu, 3 Oct 2024 00:11:41 +0200
+Subject: [PATCH 1/5] block: add support for defining read-only partitions
+
+Add support for defining read-only partitions and complete support for
+it in the cmdline partition parser as the additional "ro" after a
+partition is scanned but never actually applied.
+
+---
+ block/blk.h | 1 +
+ block/partitions/cmdline.c | 3 +++
+ block/partitions/core.c | 3 +++
+ 3 files changed, 7 insertions(+)
+
+--- a/block/blk.h
++++ b/block/blk.h
+@@ -556,6 +556,7 @@ void blk_free_ext_minor(unsigned int min
+ #define ADDPART_FLAG_NONE 0
+ #define ADDPART_FLAG_RAID 1
+ #define ADDPART_FLAG_WHOLEDISK 2
++#define ADDPART_FLAG_READONLY 4
+ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start,
+ sector_t length);
+ int bdev_del_partition(struct gendisk *disk, int partno);
+--- a/block/partitions/cmdline.c
++++ b/block/partitions/cmdline.c
+@@ -237,6 +237,9 @@ static int add_part(int slot, struct cmd
+ put_partition(state, slot, subpart->from >> 9,
+ subpart->size >> 9);
+
++ if (subpart->flags & PF_RDONLY)
++ state->parts[slot].flags |= ADDPART_FLAG_READONLY;
++
+ info = &state->parts[slot].info;
+
+ strscpy(info->volname, subpart->name, sizeof(info->volname));
+--- a/block/partitions/core.c
++++ b/block/partitions/core.c
+@@ -373,6 +373,9 @@ static struct block_device *add_partitio
+ goto out_del;
+ }
+
++ if (flags & ADDPART_FLAG_READONLY)
++ bdev_set_flag(bdev, BD_READ_ONLY);
++
+ /* everything is up and running, commence */
+ err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
+ if (err)
--- /dev/null
+From e5f587242b6072ffab4f4a084a459a59f3035873 Mon Sep 17 00:00:00 2001
+Date: Thu, 3 Oct 2024 00:11:43 +0200
+Subject: [PATCH 3/5] block: introduce add_disk_fwnode()
+
+Introduce add_disk_fwnode() as a replacement of device_add_disk() that
+permits to pass and attach a fwnode to disk dev.
+
+This variant can be useful for eMMC that might have the partition table
+for the disk defined in DT. A parser can later make use of the attached
+fwnode to parse the related table and init the hardcoded partition for
+the disk.
+
+device_add_disk() is converted to a simple wrapper of add_disk_fwnode()
+with the fwnode entry set as NULL.
+
+---
+ block/genhd.c | 28 ++++++++++++++++++++++++----
+ include/linux/blkdev.h | 3 +++
+ 2 files changed, 27 insertions(+), 4 deletions(-)
+
+--- a/block/genhd.c
++++ b/block/genhd.c
+@@ -383,16 +383,18 @@ int disk_scan_partitions(struct gendisk
+ }
+
+ /**
+- * device_add_disk - add disk information to kernel list
++ * add_disk_fwnode - add disk information to kernel list with fwnode
+ * @parent: parent device for the disk
+ * @disk: per-device partitioning information
+ * @groups: Additional per-device sysfs groups
++ * @fwnode: attached disk fwnode
+ *
+ * This function registers the partitioning information in @disk
+- * with the kernel.
++ * with the kernel. Also attach a fwnode to the disk device.
+ */
+-int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
+- const struct attribute_group **groups)
++int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk,
++ const struct attribute_group **groups,
++ struct fwnode_handle *fwnode)
+
+ {
+ struct device *ddev = disk_to_dev(disk);
+@@ -452,6 +454,8 @@ int __must_check device_add_disk(struct
+ ddev->parent = parent;
+ ddev->groups = groups;
+ dev_set_name(ddev, "%s", disk->disk_name);
++ if (fwnode)
++ device_set_node(ddev, fwnode);
+ if (!(disk->flags & GENHD_FL_HIDDEN))
+ ddev->devt = MKDEV(disk->major, disk->first_minor);
+ ret = device_add(ddev);
+@@ -553,6 +557,22 @@ out_exit_elevator:
+ elevator_exit(disk->queue);
+ return ret;
+ }
++EXPORT_SYMBOL_GPL(add_disk_fwnode);
++
++/**
++ * device_add_disk - add disk information to kernel list
++ * @parent: parent device for the disk
++ * @disk: per-device partitioning information
++ * @groups: Additional per-device sysfs groups
++ *
++ * This function registers the partitioning information in @disk
++ * with the kernel.
++ */
++int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
++ const struct attribute_group **groups)
++{
++ return add_disk_fwnode(parent, disk, groups, NULL);
++}
+ EXPORT_SYMBOL(device_add_disk);
+
+ static void blk_report_disk_dead(struct gendisk *disk, bool surprise)
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -734,6 +734,9 @@ static inline unsigned int blk_queue_dep
+ #define for_each_bio(_bio) \
+ for (; _bio; _bio = _bio->bi_next)
+
++int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk,
++ const struct attribute_group **groups,
++ struct fwnode_handle *fwnode);
+ int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
+ const struct attribute_group **groups);
+ static inline int __must_check add_disk(struct gendisk *disk)
--- /dev/null
+From 45ff6c340ddfc2dade74d5b7a8962c778ab7042c Mon Sep 17 00:00:00 2001
+Date: Thu, 3 Oct 2024 00:11:44 +0200
+Subject: [PATCH 4/5] mmc: block: attach partitions fwnode if found in mmc-card
+
+Attach partitions fwnode if found in mmc-card and register disk with it.
+
+This permits block partition to reference the node and register a
+partition table defined in DT for the special case for embedded device
+that doesn't have a partition table flashed but have an hardcoded
+partition table passed from the system.
+
+JEDEC BOOT partition boot0/boot1 are supported but in DT we refer with
+the JEDEC name of boot1 and boot2 to better adhere to documentation.
+
+Also JEDEC GP partition gp0/1/2/3 are supported but in DT we refer with
+the JEDEC name of gp1/2/3/4 to better adhere to documentration.
+
+---
+ drivers/mmc/core/block.c | 55 +++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 54 insertions(+), 1 deletion(-)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -2517,6 +2517,56 @@ static inline int mmc_blk_readonly(struc
+ !(card->csd.cmdclass & CCC_BLOCK_WRITE);
+ }
+
++/*
++ * Search for a declared partitions node for the disk in mmc-card related node.
++ *
++ * This is to permit support for partition table defined in DT in special case
++ * where a partition table is not written in the disk and is expected to be
++ * passed from the running system.
++ *
++ * For the user disk, "partitions" node is searched.
++ * For the special HW disk, "partitions-" node with the appended name is used
++ * following this conversion table (to adhere to JEDEC naming)
++ * - boot0 -> partitions-boot1
++ * - boot1 -> partitions-boot2
++ * - gp0 -> partitions-gp1
++ * - gp1 -> partitions-gp2
++ * - gp2 -> partitions-gp3
++ * - gp3 -> partitions-gp4
++ */
++static struct fwnode_handle *mmc_blk_get_partitions_node(struct device *mmc_dev,
++ const char *subname)
++{
++ const char *node_name = "partitions";
++
++ if (subname) {
++ mmc_dev = mmc_dev->parent;
++
++ /*
++ * Check if we are allocating a BOOT disk boot0/1 disk.
++ * In DT we use the JEDEC naming boot1/2.
++ */
++ if (!strcmp(subname, "boot0"))
++ node_name = "partitions-boot1";
++ if (!strcmp(subname, "boot1"))
++ node_name = "partitions-boot2";
++ /*
++ * Check if we are allocating a GP disk gp0/1/2/3 disk.
++ * In DT we use the JEDEC naming gp1/2/3/4.
++ */
++ if (!strcmp(subname, "gp0"))
++ node_name = "partitions-gp1";
++ if (!strcmp(subname, "gp1"))
++ node_name = "partitions-gp2";
++ if (!strcmp(subname, "gp2"))
++ node_name = "partitions-gp3";
++ if (!strcmp(subname, "gp3"))
++ node_name = "partitions-gp4";
++ }
++
++ return device_get_named_child_node(mmc_dev, node_name);
++}
++
+ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+ struct device *parent,
+ sector_t size,
+@@ -2525,6 +2575,7 @@ static struct mmc_blk_data *mmc_blk_allo
+ int area_type,
+ unsigned int part_type)
+ {
++ struct fwnode_handle *disk_fwnode;
+ struct mmc_blk_data *md;
+ int devidx, ret;
+ char cap_str[10];
+@@ -2626,7 +2677,9 @@ static struct mmc_blk_data *mmc_blk_allo
+ /* used in ->open, must be set before add_disk: */
+ if (area_type == MMC_BLK_DATA_AREA_MAIN)
+ dev_set_drvdata(&card->dev, md);
+- ret = device_add_disk(md->parent, md->disk, mmc_disk_attr_groups);
++ disk_fwnode = mmc_blk_get_partitions_node(parent, subname);
++ ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups,
++ disk_fwnode);
+ if (ret)
+ goto err_put_disk;
+ return md;
--- /dev/null
+From 884555b557e5e6d41c866e2cd8d7b32f50ec974b Mon Sep 17 00:00:00 2001
+Date: Thu, 3 Oct 2024 00:11:45 +0200
+Subject: [PATCH 5/5] block: add support for partition table defined in OF
+
+Add support for partition table defined in Device Tree. Similar to how
+it's done with MTD, add support for defining a fixed partition table in
+device tree.
+
+A common scenario for this is fixed block (eMMC) embedded devices that
+have no MBR or GPT partition table to save storage space. Bootloader
+access the block device with absolute address of data.
+
+This is to complete the functionality with an equivalent implementation
+with providing partition table with bootargs, for case where the booargs
+can't be modified and tweaking the Device Tree is the only solution to
+have an usabe partition table.
+
+The implementation follow the fixed-partitions parser used on MTD
+devices where a "partitions" node is expected to be declared with
+"fixed-partitions" compatible in the OF node of the disk device
+(mmc-card for eMMC for example) and each child node declare a label
+and a reg with offset and size. If label is not declared, the node name
+is used as fallback. Eventually is also possible to declare the read-only
+property to flag the partition as read-only.
+
+---
+ block/partitions/Kconfig | 9 ++++
+ block/partitions/Makefile | 1 +
+ block/partitions/check.h | 1 +
+ block/partitions/core.c | 3 ++
+ block/partitions/of.c | 110 ++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 124 insertions(+)
+ create mode 100644 block/partitions/of.c
+
+--- a/block/partitions/Kconfig
++++ b/block/partitions/Kconfig
+@@ -270,4 +270,13 @@ config CMDLINE_PARTITION
+ Say Y here if you want to read the partition table from bootargs.
+ The format for the command line is just like mtdparts.
+
++config OF_PARTITION
++ bool "Device Tree partition support" if PARTITION_ADVANCED
++ depends on OF
++ help
++ Say Y here if you want to enable support for partition table
++ defined in Device Tree. (mainly for eMMC)
++ The format for the device tree node is just like MTD fixed-partition
++ schema.
++
+ endmenu
+--- a/block/partitions/Makefile
++++ b/block/partitions/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_CMDLINE_PARTITION) += cmdli
+ obj-$(CONFIG_MAC_PARTITION) += mac.o
+ obj-$(CONFIG_LDM_PARTITION) += ldm.o
+ obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
++obj-$(CONFIG_OF_PARTITION) += of.o
+ obj-$(CONFIG_OSF_PARTITION) += osf.o
+ obj-$(CONFIG_SGI_PARTITION) += sgi.o
+ obj-$(CONFIG_SUN_PARTITION) += sun.o
+--- a/block/partitions/check.h
++++ b/block/partitions/check.h
+@@ -62,6 +62,7 @@ int karma_partition(struct parsed_partit
+ int ldm_partition(struct parsed_partitions *state);
+ int mac_partition(struct parsed_partitions *state);
+ int msdos_partition(struct parsed_partitions *state);
++int of_partition(struct parsed_partitions *state);
+ int osf_partition(struct parsed_partitions *state);
+ int sgi_partition(struct parsed_partitions *state);
+ int sun_partition(struct parsed_partitions *state);
+--- a/block/partitions/core.c
++++ b/block/partitions/core.c
+@@ -43,6 +43,9 @@ static int (*const check_part[])(struct
+ #ifdef CONFIG_CMDLINE_PARTITION
+ cmdline_partition,
+ #endif
++#ifdef CONFIG_OF_PARTITION
++ of_partition, /* cmdline have priority to OF */
++#endif
+ #ifdef CONFIG_EFI_PARTITION
+ efi_partition, /* this must come before msdos */
+ #endif
+--- /dev/null
++++ b/block/partitions/of.c
+@@ -0,0 +1,110 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <linux/blkdev.h>
++#include <linux/major.h>
++#include <linux/of.h>
++#include <linux/string.h>
++#include "check.h"
++
++static int validate_of_partition(struct device_node *np, int slot)
++{
++ u64 offset, size;
++ int len;
++
++ const __be32 *reg = of_get_property(np, "reg", &len);
++ int a_cells = of_n_addr_cells(np);
++ int s_cells = of_n_size_cells(np);
++
++ /* Make sure reg len match the expected addr and size cells */
++ if (len / sizeof(*reg) != a_cells + s_cells)
++ return -EINVAL;
++
++ /* Validate offset conversion from bytes to sectors */
++ offset = of_read_number(reg, a_cells);
++ if (offset % SECTOR_SIZE)
++ return -EINVAL;
++
++ /* Validate size conversion from bytes to sectors */
++ size = of_read_number(reg + a_cells, s_cells);
++ if (!size || size % SECTOR_SIZE)
++ return -EINVAL;
++
++ return 0;
++}
++
++static void add_of_partition(struct parsed_partitions *state, int slot,
++ struct device_node *np)
++{
++ struct partition_meta_info *info;
++ char tmp[sizeof(info->volname) + 4];
++ const char *partname;
++ int len;
++
++ const __be32 *reg = of_get_property(np, "reg", &len);
++ int a_cells = of_n_addr_cells(np);
++ int s_cells = of_n_size_cells(np);
++
++ /* Convert bytes to sector size */
++ u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE;
++ u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE;
++
++ put_partition(state, slot, offset, size);
++
++ if (of_property_read_bool(np, "read-only"))
++ state->parts[slot].flags |= ADDPART_FLAG_READONLY;
++
++ /*
++ * Follow MTD label logic, search for label property,
++ * fallback to node name if not found.
++ */
++ info = &state->parts[slot].info;
++ partname = of_get_property(np, "label", &len);
++ if (!partname)
++ partname = of_get_property(np, "name", &len);
++ strscpy(info->volname, partname, sizeof(info->volname));
++
++ snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
++ strlcat(state->pp_buf, tmp, PAGE_SIZE);
++}
++
++int of_partition(struct parsed_partitions *state)
++{
++ struct device *ddev = disk_to_dev(state->disk);
++ struct device_node *np;
++ int slot;
++
++ struct device_node *partitions_np = of_node_get(ddev->of_node);
++
++ if (!partitions_np ||
++ !of_device_is_compatible(partitions_np, "fixed-partitions"))
++ return 0;
++
++ slot = 1;
++ /* Validate parition offset and size */
++ for_each_child_of_node(partitions_np, np) {
++ if (validate_of_partition(np, slot)) {
++ of_node_put(np);
++ of_node_put(partitions_np);
++
++ return -1;
++ }
++
++ slot++;
++ }
++
++ slot = 1;
++ for_each_child_of_node(partitions_np, np) {
++ if (slot >= state->limit) {
++ of_node_put(np);
++ break;
++ }
++
++ add_of_partition(state, slot, np);
++
++ slot++;
++ }
++
++ strlcat(state->pp_buf, "\n", PAGE_SIZE);
++
++ return 1;
++}
--- /dev/null
+From 9723a77318b7c0cfd06ea207e52a042f8c815318 Mon Sep 17 00:00:00 2001
+Date: Tue, 10 Dec 2024 14:18:16 +0000
+Subject: [PATCH] net: dsa: add hook to determine whether EEE is supported
+
+Add a hook to determine whether the switch supports EEE. This will
+return false if the switch does not, or true if it does. If the
+method is not implemented, we assume (currently) that the switch
+supports EEE.
+
+---
+ include/net/dsa.h | 1 +
+ net/dsa/user.c | 8 ++++++++
+ 2 files changed, 9 insertions(+)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -1003,6 +1003,7 @@ struct dsa_switch_ops {
+ /*
+ * Port's MAC EEE settings
+ */
++ bool (*support_eee)(struct dsa_switch *ds, int port);
+ int (*set_mac_eee)(struct dsa_switch *ds, int port,
+ struct ethtool_keee *e);
+ int (*get_mac_eee)(struct dsa_switch *ds, int port,
+--- a/net/dsa/user.c
++++ b/net/dsa/user.c
+@@ -1231,6 +1231,10 @@ static int dsa_user_set_eee(struct net_d
+ struct dsa_switch *ds = dp->ds;
+ int ret;
+
++ /* Check whether the switch supports EEE */
++ if (ds->ops->support_eee && !ds->ops->support_eee(ds, dp->index))
++ return -EOPNOTSUPP;
++
+ /* Port's PHY and MAC both need to be EEE capable */
+ if (!dev->phydev || !dp->pl)
+ return -ENODEV;
+@@ -1251,6 +1255,10 @@ static int dsa_user_get_eee(struct net_d
+ struct dsa_switch *ds = dp->ds;
+ int ret;
+
++ /* Check whether the switch supports EEE */
++ if (ds->ops->support_eee && !ds->ops->support_eee(ds, dp->index))
++ return -EOPNOTSUPP;
++
+ /* Port's PHY and MAC both need to be EEE capable */
+ if (!dev->phydev || !dp->pl)
+ return -ENODEV;
--- /dev/null
+From 99379f587278c818777cb4778e2c79c6c1440c65 Mon Sep 17 00:00:00 2001
+Date: Tue, 10 Dec 2024 14:18:21 +0000
+Subject: [PATCH] net: dsa: provide implementation of .support_eee()
+
+Provide a trivial implementation for the .support_eee() method which
+switch drivers can use to simply indicate that they support EEE on
+all their user ports.
+
+---
+ include/net/dsa.h | 1 +
+ net/dsa/port.c | 16 ++++++++++++++++
+ 2 files changed, 17 insertions(+)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -1399,5 +1399,6 @@ static inline bool dsa_user_dev_check(co
+
+ netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev);
+ void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up);
++bool dsa_supports_eee(struct dsa_switch *ds, int port);
+
+ #endif
+--- a/net/dsa/port.c
++++ b/net/dsa/port.c
+@@ -1589,6 +1589,22 @@ dsa_port_phylink_mac_select_pcs(struct p
+ return pcs;
+ }
+
++/* dsa_supports_eee - indicate that EEE is supported
++ * @ds: pointer to &struct dsa_switch
++ * @port: port index
++ *
++ * A default implementation for the .support_eee() DSA operations member,
++ * which drivers can use to indicate that they support EEE on all of their
++ * user ports.
++ *
++ * Returns: true
++ */
++bool dsa_supports_eee(struct dsa_switch *ds, int port)
++{
++ return true;
++}
++EXPORT_SYMBOL_GPL(dsa_supports_eee);
++
+ static void dsa_port_phylink_mac_config(struct phylink_config *config,
+ unsigned int mode,
+ const struct phylink_link_state *state)
--- /dev/null
+From f12b363887c706c40611fba645265527a8415832 Mon Sep 17 00:00:00 2001
+Date: Sun, 27 Oct 2024 21:48:28 -0700
+Subject: [PATCH] net: dsa: use ethtool string helpers
+
+These are the preferred way to copy ethtool strings.
+
+Avoids incrementing pointers all over the place.
+
+(for hellcreek driver)
+---
+ drivers/net/dsa/b53/b53_common.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1061,8 +1061,7 @@ void b53_get_strings(struct dsa_switch *
+
+ if (stringset == ETH_SS_STATS) {
+ for (i = 0; i < mib_size; i++)
+- strscpy(data + i * ETH_GSTRING_LEN,
+- mibs[i].name, ETH_GSTRING_LEN);
++ ethtool_puts(&data, mibs[i].name);
+ } else if (stringset == ETH_SS_PHY_STATS) {
+ phydev = b53_get_phy_device(ds, port);
+ if (!phydev)
--- /dev/null
+From c86692fc2cb77d94dd8c166c2b9017f196d02a84 Mon Sep 17 00:00:00 2001
+Date: Tue, 10 Dec 2024 14:18:26 +0000
+Subject: [PATCH] net: dsa: b53/bcm_sf2: implement .support_eee() method
+
+Implement the .support_eee() method to indicate that EEE is not
+supported by two switch variants, rather than making these checks in
+the .set_mac_eee() and .get_mac_eee() methods.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 13 +++++++------
+ drivers/net/dsa/b53/b53_priv.h | 1 +
+ 2 files changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -2358,13 +2358,16 @@ int b53_eee_init(struct dsa_switch *ds,
+ }
+ EXPORT_SYMBOL(b53_eee_init);
+
+-int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e)
++bool b53_support_eee(struct dsa_switch *ds, int port)
+ {
+ struct b53_device *dev = ds->priv;
+
+- if (is5325(dev) || is5365(dev))
+- return -EOPNOTSUPP;
++ return !is5325(dev) && !is5365(dev);
++}
++EXPORT_SYMBOL(b53_support_eee);
+
++int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e)
++{
+ return 0;
+ }
+ EXPORT_SYMBOL(b53_get_mac_eee);
+@@ -2374,9 +2377,6 @@ int b53_set_mac_eee(struct dsa_switch *d
+ struct b53_device *dev = ds->priv;
+ struct ethtool_keee *p = &dev->ports[port].eee;
+
+- if (is5325(dev) || is5365(dev))
+- return -EOPNOTSUPP;
+-
+ p->eee_enabled = e->eee_enabled;
+ b53_eee_enable_set(ds, port, e->eee_enabled);
+
+@@ -2433,6 +2433,7 @@ static const struct dsa_switch_ops b53_s
+ .port_setup = b53_setup_port,
+ .port_enable = b53_enable_port,
+ .port_disable = b53_disable_port,
++ .support_eee = b53_support_eee,
+ .get_mac_eee = b53_get_mac_eee,
+ .set_mac_eee = b53_set_mac_eee,
+ .port_bridge_join = b53_br_join,
+--- a/drivers/net/dsa/b53/b53_priv.h
++++ b/drivers/net/dsa/b53/b53_priv.h
+@@ -387,6 +387,7 @@ int b53_enable_port(struct dsa_switch *d
+ void b53_disable_port(struct dsa_switch *ds, int port);
+ void b53_brcm_hdr_setup(struct dsa_switch *ds, int port);
+ int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy);
++bool b53_support_eee(struct dsa_switch *ds, int port);
+ int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e);
+ int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e);
+
--- /dev/null
+From c4f873c2b65c839ff5e7c996bd9ef5a1e7eae11a Mon Sep 17 00:00:00 2001
+Date: Mon, 17 Feb 2025 09:05:01 +0100
+Subject: [PATCH] net: dsa: b53: mdio: add support for BCM53101
+
+BCM53101 is a ethernet switch, very similar to the BCM53115.
+Enable support for it, in the existing b53 dsa driver.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 14 ++++++++++++++
+ drivers/net/dsa/b53/b53_mdio.c | 1 +
+ drivers/net/dsa/b53/b53_priv.h | 2 ++
+ 3 files changed, 17 insertions(+)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -2552,6 +2552,19 @@ static const struct b53_chip_data b53_sw
+ .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+ },
+ {
++ .chip_id = BCM53101_DEVICE_ID,
++ .dev_name = "BCM53101",
++ .vlans = 4096,
++ .enabled_ports = 0x11f,
++ .arl_bins = 4,
++ .arl_buckets = 512,
++ .vta_regs = B53_VTA_REGS,
++ .imp_port = 8,
++ .duplex_reg = B53_DUPLEX_STAT_GE,
++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
++ },
++ {
+ .chip_id = BCM53115_DEVICE_ID,
+ .dev_name = "BCM53115",
+ .vlans = 4096,
+@@ -2932,6 +2945,7 @@ int b53_switch_detect(struct b53_device
+ return ret;
+
+ switch (id32) {
++ case BCM53101_DEVICE_ID:
+ case BCM53115_DEVICE_ID:
+ case BCM53125_DEVICE_ID:
+ case BCM53128_DEVICE_ID:
+--- a/drivers/net/dsa/b53/b53_mdio.c
++++ b/drivers/net/dsa/b53/b53_mdio.c
+@@ -374,6 +374,7 @@ static void b53_mdio_shutdown(struct mdi
+
+ static const struct of_device_id b53_of_match[] = {
+ { .compatible = "brcm,bcm5325" },
++ { .compatible = "brcm,bcm53101" },
+ { .compatible = "brcm,bcm53115" },
+ { .compatible = "brcm,bcm53125" },
+ { .compatible = "brcm,bcm53128" },
+--- a/drivers/net/dsa/b53/b53_priv.h
++++ b/drivers/net/dsa/b53/b53_priv.h
+@@ -66,6 +66,7 @@ enum {
+ BCM5395_DEVICE_ID = 0x95,
+ BCM5397_DEVICE_ID = 0x97,
+ BCM5398_DEVICE_ID = 0x98,
++ BCM53101_DEVICE_ID = 0x53101,
+ BCM53115_DEVICE_ID = 0x53115,
+ BCM53125_DEVICE_ID = 0x53125,
+ BCM53128_DEVICE_ID = 0x53128,
+@@ -190,6 +191,7 @@ static inline int is531x5(struct b53_dev
+ {
+ return dev->chip_id == BCM53115_DEVICE_ID ||
+ dev->chip_id == BCM53125_DEVICE_ID ||
++ dev->chip_id == BCM53101_DEVICE_ID ||
+ dev->chip_id == BCM53128_DEVICE_ID ||
+ dev->chip_id == BCM53134_DEVICE_ID;
+ }
--- /dev/null
+From e39d14a760c039af0653e3df967e7525413924a0 Mon Sep 17 00:00:00 2001
+Date: Sat, 10 May 2025 11:22:11 +0200
+Subject: [PATCH] net: dsa: b53: implement setting ageing time
+
+b53 supported switches support configuring ageing time between 1 and
+1,048,575 seconds, so add an appropriate setter.
+
+This allows b53 to pass the FDB learning test for both vlan aware and
+vlan unaware bridges.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 28 ++++++++++++++++++++++++++++
+ drivers/net/dsa/b53/b53_priv.h | 1 +
+ drivers/net/dsa/b53/b53_regs.h | 7 +++++++
+ 3 files changed, 36 insertions(+)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -21,6 +21,7 @@
+ #include <linux/export.h>
+ #include <linux/gpio.h>
+ #include <linux/kernel.h>
++#include <linux/math.h>
+ #include <linux/module.h>
+ #include <linux/platform_data/b53.h>
+ #include <linux/phy.h>
+@@ -1202,6 +1203,10 @@ static int b53_setup(struct dsa_switch *
+ */
+ ds->untag_vlan_aware_bridge_pvid = true;
+
++ /* Ageing time is set in seconds */
++ ds->ageing_time_min = 1 * 1000;
++ ds->ageing_time_max = AGE_TIME_MAX * 1000;
++
+ ret = b53_reset_switch(dev);
+ if (ret) {
+ dev_err(ds->dev, "failed to reset switch\n");
+@@ -2412,6 +2417,28 @@ static int b53_get_max_mtu(struct dsa_sw
+ return B53_MAX_MTU;
+ }
+
++int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
++{
++ struct b53_device *dev = ds->priv;
++ u32 atc;
++ int reg;
++
++ if (is63xx(dev))
++ reg = B53_AGING_TIME_CONTROL_63XX;
++ else
++ reg = B53_AGING_TIME_CONTROL;
++
++ atc = DIV_ROUND_CLOSEST(msecs, 1000);
++
++ if (!is5325(dev) && !is5365(dev))
++ atc |= AGE_CHANGE;
++
++ b53_write32(dev, B53_MGMT_PAGE, reg, atc);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(b53_set_ageing_time);
++
+ static const struct phylink_mac_ops b53_phylink_mac_ops = {
+ .mac_select_pcs = b53_phylink_mac_select_pcs,
+ .mac_config = b53_phylink_mac_config,
+@@ -2436,6 +2463,7 @@ static const struct dsa_switch_ops b53_s
+ .support_eee = b53_support_eee,
+ .get_mac_eee = b53_get_mac_eee,
+ .set_mac_eee = b53_set_mac_eee,
++ .set_ageing_time = b53_set_ageing_time,
+ .port_bridge_join = b53_br_join,
+ .port_bridge_leave = b53_br_leave,
+ .port_pre_bridge_flags = b53_br_flags_pre,
+--- a/drivers/net/dsa/b53/b53_priv.h
++++ b/drivers/net/dsa/b53/b53_priv.h
+@@ -343,6 +343,7 @@ void b53_get_strings(struct dsa_switch *
+ void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
+ int b53_get_sset_count(struct dsa_switch *ds, int port, int sset);
+ void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data);
++int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs);
+ int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
+ bool *tx_fwd_offload, struct netlink_ext_ack *extack);
+ void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge);
+--- a/drivers/net/dsa/b53/b53_regs.h
++++ b/drivers/net/dsa/b53/b53_regs.h
+@@ -220,6 +220,13 @@
+ #define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */
+ #define BRCM_HDR_P7_EN BIT(2) /* Enable tagging on port 7 */
+
++/* Aging Time control register (32 bit) */
++#define B53_AGING_TIME_CONTROL 0x06
++#define B53_AGING_TIME_CONTROL_63XX 0x08
++#define AGE_CHANGE BIT(20)
++#define AGE_TIME_MASK 0x7ffff
++#define AGE_TIME_MAX 1048575
++
+ /* Mirror capture control register (16 bit) */
+ #define B53_MIR_CAP_CTL 0x10
+ #define CAP_PORT_MASK 0xf
--- /dev/null
+From 1237c2d4a8db79dfd4369bff6930b0e385ed7d5c Mon Sep 17 00:00:00 2001
+Date: Mon, 2 Jun 2025 21:39:49 +0200
+Subject: [PATCH] net: dsa: b53: do not enable EEE on bcm63xx
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM63xx internal switches do not support EEE, but provide multiple RGMII
+ports where external PHYs may be connected. If one of these PHYs are EEE
+capable, we may try to enable EEE for the MACs, which then hangs the
+system on access of the (non-existent) EEE registers.
+
+Fix this by checking if the switch actually supports EEE before
+attempting to configure it.
+
+Fixes: 22256b0afb12 ("net: dsa: b53: Move EEE functions to b53")
+---
+ drivers/net/dsa/b53/b53_common.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -2353,6 +2353,9 @@ int b53_eee_init(struct dsa_switch *ds,
+ {
+ int ret;
+
++ if (!b53_support_eee(ds, port))
++ return 0;
++
+ ret = phy_init_eee(phy, false);
+ if (ret)
+ return 0;
+@@ -2367,7 +2370,7 @@ bool b53_support_eee(struct dsa_switch *
+ {
+ struct b53_device *dev = ds->priv;
+
+- return !is5325(dev) && !is5365(dev);
++ return !is5325(dev) && !is5365(dev) && !is63xx(dev);
+ }
+ EXPORT_SYMBOL(b53_support_eee);
+
--- /dev/null
+From 4af523551d876ab8b8057d1e5303a860fd736fcb Mon Sep 17 00:00:00 2001
+Date: Mon, 2 Jun 2025 21:39:50 +0200
+Subject: [PATCH] net: dsa: b53: do not enable RGMII delay on bcm63xx
+
+bcm63xx's RGMII ports are always in MAC mode, never in PHY mode, so we
+shouldn't enable any delays and let the PHY handle any delays as
+necessary.
+
+This fixes using RGMII ports with normal PHYs like BCM54612E, which will
+handle the delay in the PHY.
+
+Fixes: ce3bf94871f7 ("net: dsa: b53: add support for BCM63xx RGMIIs")
+---
+ drivers/net/dsa/b53/b53_common.c | 19 +------------------
+ 1 file changed, 1 insertion(+), 18 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1330,24 +1330,7 @@ static void b53_adjust_63xx_rgmii(struct
+ off = B53_RGMII_CTRL_P(port);
+
+ b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
+-
+- switch (interface) {
+- case PHY_INTERFACE_MODE_RGMII_ID:
+- rgmii_ctrl |= (RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
+- break;
+- case PHY_INTERFACE_MODE_RGMII_RXID:
+- rgmii_ctrl &= ~(RGMII_CTRL_DLL_TXC);
+- rgmii_ctrl |= RGMII_CTRL_DLL_RXC;
+- break;
+- case PHY_INTERFACE_MODE_RGMII_TXID:
+- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC);
+- rgmii_ctrl |= RGMII_CTRL_DLL_TXC;
+- break;
+- case PHY_INTERFACE_MODE_RGMII:
+- default:
+- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
+- break;
+- }
++ rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
+
+ if (port != dev->imp_port) {
+ if (is63268(dev))
--- /dev/null
+From 75f4f7b2b13008803f84768ff90396f9d7553221 Mon Sep 17 00:00:00 2001
+Date: Mon, 2 Jun 2025 21:39:51 +0200
+Subject: [PATCH] net: dsa: b53: do not configure bcm63xx's IMP port interface
+
+The IMP port is not a valid RGMII interface, but hard wired to internal,
+so we shouldn't touch the undefined register B53_RGMII_CTRL_IMP.
+
+While this does not seem to have any side effects, let's not touch it at
+all, so limit RGMII configuration on bcm63xx to the actual RGMII ports.
+
+Fixes: ce3bf94871f7 ("net: dsa: b53: add support for BCM63xx RGMIIs")
+---
+ drivers/net/dsa/b53/b53_common.c | 22 ++++++++--------------
+ 1 file changed, 8 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -22,6 +22,7 @@
+ #include <linux/gpio.h>
+ #include <linux/kernel.h>
+ #include <linux/math.h>
++#include <linux/minmax.h>
+ #include <linux/module.h>
+ #include <linux/platform_data/b53.h>
+ #include <linux/phy.h>
+@@ -1322,24 +1323,17 @@ static void b53_adjust_63xx_rgmii(struct
+ phy_interface_t interface)
+ {
+ struct b53_device *dev = ds->priv;
+- u8 rgmii_ctrl = 0, off;
++ u8 rgmii_ctrl = 0;
+
+- if (port == dev->imp_port)
+- off = B53_RGMII_CTRL_IMP;
+- else
+- off = B53_RGMII_CTRL_P(port);
+-
+- b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
++ b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl);
+ rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
+
+- if (port != dev->imp_port) {
+- if (is63268(dev))
+- rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
++ if (is63268(dev))
++ rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
+
+- rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
+- }
++ rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
+
+- b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl);
++ b53_write8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), rgmii_ctrl);
+
+ dev_dbg(ds->dev, "Configured port %d for %s\n", port,
+ phy_modes(interface));
+@@ -1484,7 +1478,7 @@ static void b53_phylink_mac_config(struc
+ struct b53_device *dev = ds->priv;
+ int port = dp->index;
+
+- if (is63xx(dev) && port >= B53_63XX_RGMII0)
++ if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4))
+ b53_adjust_63xx_rgmii(ds, port, interface);
+
+ if (mode == MLO_AN_FIXED) {
--- /dev/null
+From 5ea0d42c1980e6d10e5cb56a78021db5bfcebaaf Mon Sep 17 00:00:00 2001
+Date: Mon, 2 Jun 2025 21:39:52 +0200
+Subject: [PATCH] net: dsa: b53: allow RGMII for bcm63xx RGMII ports
+
+Add RGMII to supported interfaces for BCM63xx RGMII ports so they can be
+actually used in RGMII mode.
+
+Without this, phylink will fail to configure them:
+
+[ 3.580000] b53-switch 10700000.switch GbE3 (uninitialized): validation of rgmii with support 0000000,00000000,00000000,000062ff and advertisement 0000000,00000000,00000000,000062ff failed: -EINVAL
+[ 3.600000] b53-switch 10700000.switch GbE3 (uninitialized): failed to connect to PHY: -EINVAL
+[ 3.610000] b53-switch 10700000.switch GbE3 (uninitialized): error -22 setting up PHY for tree 0, switch 0, port 4
+
+Fixes: ce3bf94871f7 ("net: dsa: b53: add support for BCM63xx RGMIIs")
+---
+ drivers/net/dsa/b53/b53_common.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1439,6 +1439,10 @@ static void b53_phylink_get_caps(struct
+ __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_REVMII, config->supported_interfaces);
+
++ /* BCM63xx RGMII ports support RGMII */
++ if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4))
++ phy_interface_set_rgmii(config->supported_interfaces);
++
+ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
+ MAC_10 | MAC_100;
+
--- /dev/null
+From bc1a65eb81a21e2aa3c3dca058ee8adf687b6ef5 Mon Sep 17 00:00:00 2001
+Date: Mon, 2 Jun 2025 21:39:53 +0200
+Subject: [PATCH] net: dsa: b53: do not touch DLL_IQQD on bcm53115
+
+According to OpenMDK, bit 2 of the RGMII register has a different
+meaning for BCM53115 [1]:
+
+"DLL_IQQD 1: In the IDDQ mode, power is down0: Normal function
+ mode"
+
+Configuring RGMII delay works without setting this bit, so let's keep it
+at the default. For other chips, we always set it, so not clearing it
+is not an issue.
+
+One would assume BCM53118 works the same, but OpenMDK is not quite sure
+what this bit actually means [2]:
+
+"BYPASS_IMP_2NS_DEL #1: In the IDDQ mode, power is down#0: Normal
+ function mode1: Bypass dll65_2ns_del IP0: Use
+ dll65_2ns_del IP"
+
+So lets keep setting it for now.
+
+[1] https://github.com/Broadcom-Network-Switching-Software/OpenMDK/blob/master/cdk/PKG/chip/bcm53115/bcm53115_a0_defs.h#L19871
+[2] https://github.com/Broadcom-Network-Switching-Software/OpenMDK/blob/master/cdk/PKG/chip/bcm53118/bcm53118_a0_defs.h#L14392
+
+Fixes: 967dd82ffc52 ("net: dsa: b53: Add support for Broadcom RoboSwitch")
+---
+ drivers/net/dsa/b53/b53_common.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1354,8 +1354,7 @@ static void b53_adjust_531x5_rgmii(struc
+ * tx_clk aligned timing (restoring to reset defaults)
+ */
+ b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
+- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC |
+- RGMII_CTRL_TIMING_SEL);
++ rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
+
+ /* PHY_INTERFACE_MODE_RGMII_TXID means TX internal delay, make
+ * sure that we enable the port TX clock internal delay to
+@@ -1375,7 +1374,10 @@ static void b53_adjust_531x5_rgmii(struc
+ rgmii_ctrl |= RGMII_CTRL_DLL_TXC;
+ if (interface == PHY_INTERFACE_MODE_RGMII)
+ rgmii_ctrl |= RGMII_CTRL_DLL_TXC | RGMII_CTRL_DLL_RXC;
+- rgmii_ctrl |= RGMII_CTRL_TIMING_SEL;
++
++ if (dev->chip_id != BCM53115_DEVICE_ID)
++ rgmii_ctrl |= RGMII_CTRL_TIMING_SEL;
++
+ b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl);
+
+ dev_info(ds->dev, "Configured port %d for %s\n", port,
--- /dev/null
+From efdddc4484859082da6c7877ed144c8121c8ea55 Mon Sep 17 00:00:00 2001
+Date: Thu, 29 May 2025 14:44:06 +0200
+Subject: [PATCH] net: dsa: tag_brcm: legacy: fix pskb_may_pull length
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BRCM_LEG_PORT_ID was incorrectly used for pskb_may_pull length.
+The correct check is BRCM_LEG_TAG_LEN + VLAN_HLEN, or 10 bytes.
+
+Fixes: 964dbf186eaa ("net: dsa: tag_brcm: add support for legacy tags")
+---
+ net/dsa/tag_brcm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/dsa/tag_brcm.c
++++ b/net/dsa/tag_brcm.c
+@@ -257,7 +257,7 @@ static struct sk_buff *brcm_leg_tag_rcv(
+ int source_port;
+ u8 *brcm_tag;
+
+- if (unlikely(!pskb_may_pull(skb, BRCM_LEG_PORT_ID)))
++ if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN)))
+ return NULL;
+
+ brcm_tag = dsa_etype_header_pos_rx(skb);
+++ /dev/null
-From 9723a77318b7c0cfd06ea207e52a042f8c815318 Mon Sep 17 00:00:00 2001
-Date: Tue, 10 Dec 2024 14:18:16 +0000
-Subject: [PATCH] net: dsa: add hook to determine whether EEE is supported
-
-Add a hook to determine whether the switch supports EEE. This will
-return false if the switch does not, or true if it does. If the
-method is not implemented, we assume (currently) that the switch
-supports EEE.
-
----
- include/net/dsa.h | 1 +
- net/dsa/user.c | 8 ++++++++
- 2 files changed, 9 insertions(+)
-
---- a/include/net/dsa.h
-+++ b/include/net/dsa.h
-@@ -1003,6 +1003,7 @@ struct dsa_switch_ops {
- /*
- * Port's MAC EEE settings
- */
-+ bool (*support_eee)(struct dsa_switch *ds, int port);
- int (*set_mac_eee)(struct dsa_switch *ds, int port,
- struct ethtool_keee *e);
- int (*get_mac_eee)(struct dsa_switch *ds, int port,
---- a/net/dsa/user.c
-+++ b/net/dsa/user.c
-@@ -1231,6 +1231,10 @@ static int dsa_user_set_eee(struct net_d
- struct dsa_switch *ds = dp->ds;
- int ret;
-
-+ /* Check whether the switch supports EEE */
-+ if (ds->ops->support_eee && !ds->ops->support_eee(ds, dp->index))
-+ return -EOPNOTSUPP;
-+
- /* Port's PHY and MAC both need to be EEE capable */
- if (!dev->phydev || !dp->pl)
- return -ENODEV;
-@@ -1251,6 +1255,10 @@ static int dsa_user_get_eee(struct net_d
- struct dsa_switch *ds = dp->ds;
- int ret;
-
-+ /* Check whether the switch supports EEE */
-+ if (ds->ops->support_eee && !ds->ops->support_eee(ds, dp->index))
-+ return -EOPNOTSUPP;
-+
- /* Port's PHY and MAC both need to be EEE capable */
- if (!dev->phydev || !dp->pl)
- return -ENODEV;
+++ /dev/null
-From 99379f587278c818777cb4778e2c79c6c1440c65 Mon Sep 17 00:00:00 2001
-Date: Tue, 10 Dec 2024 14:18:21 +0000
-Subject: [PATCH] net: dsa: provide implementation of .support_eee()
-
-Provide a trivial implementation for the .support_eee() method which
-switch drivers can use to simply indicate that they support EEE on
-all their user ports.
-
----
- include/net/dsa.h | 1 +
- net/dsa/port.c | 16 ++++++++++++++++
- 2 files changed, 17 insertions(+)
-
---- a/include/net/dsa.h
-+++ b/include/net/dsa.h
-@@ -1399,5 +1399,6 @@ static inline bool dsa_user_dev_check(co
-
- netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev);
- void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up);
-+bool dsa_supports_eee(struct dsa_switch *ds, int port);
-
- #endif
---- a/net/dsa/port.c
-+++ b/net/dsa/port.c
-@@ -1589,6 +1589,22 @@ dsa_port_phylink_mac_select_pcs(struct p
- return pcs;
- }
-
-+/* dsa_supports_eee - indicate that EEE is supported
-+ * @ds: pointer to &struct dsa_switch
-+ * @port: port index
-+ *
-+ * A default implementation for the .support_eee() DSA operations member,
-+ * which drivers can use to indicate that they support EEE on all of their
-+ * user ports.
-+ *
-+ * Returns: true
-+ */
-+bool dsa_supports_eee(struct dsa_switch *ds, int port)
-+{
-+ return true;
-+}
-+EXPORT_SYMBOL_GPL(dsa_supports_eee);
-+
- static void dsa_port_phylink_mac_config(struct phylink_config *config,
- unsigned int mode,
- const struct phylink_link_state *state)
+++ /dev/null
-From f12b363887c706c40611fba645265527a8415832 Mon Sep 17 00:00:00 2001
-Date: Sun, 27 Oct 2024 21:48:28 -0700
-Subject: [PATCH] net: dsa: use ethtool string helpers
-
-These are the preferred way to copy ethtool strings.
-
-Avoids incrementing pointers all over the place.
-
-(for hellcreek driver)
----
- drivers/net/dsa/b53/b53_common.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -1061,8 +1061,7 @@ void b53_get_strings(struct dsa_switch *
-
- if (stringset == ETH_SS_STATS) {
- for (i = 0; i < mib_size; i++)
-- strscpy(data + i * ETH_GSTRING_LEN,
-- mibs[i].name, ETH_GSTRING_LEN);
-+ ethtool_puts(&data, mibs[i].name);
- } else if (stringset == ETH_SS_PHY_STATS) {
- phydev = b53_get_phy_device(ds, port);
- if (!phydev)
+++ /dev/null
-From c86692fc2cb77d94dd8c166c2b9017f196d02a84 Mon Sep 17 00:00:00 2001
-Date: Tue, 10 Dec 2024 14:18:26 +0000
-Subject: [PATCH] net: dsa: b53/bcm_sf2: implement .support_eee() method
-
-Implement the .support_eee() method to indicate that EEE is not
-supported by two switch variants, rather than making these checks in
-the .set_mac_eee() and .get_mac_eee() methods.
-
----
- drivers/net/dsa/b53/b53_common.c | 13 +++++++------
- drivers/net/dsa/b53/b53_priv.h | 1 +
- 2 files changed, 8 insertions(+), 6 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -2358,13 +2358,16 @@ int b53_eee_init(struct dsa_switch *ds,
- }
- EXPORT_SYMBOL(b53_eee_init);
-
--int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e)
-+bool b53_support_eee(struct dsa_switch *ds, int port)
- {
- struct b53_device *dev = ds->priv;
-
-- if (is5325(dev) || is5365(dev))
-- return -EOPNOTSUPP;
-+ return !is5325(dev) && !is5365(dev);
-+}
-+EXPORT_SYMBOL(b53_support_eee);
-
-+int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e)
-+{
- return 0;
- }
- EXPORT_SYMBOL(b53_get_mac_eee);
-@@ -2374,9 +2377,6 @@ int b53_set_mac_eee(struct dsa_switch *d
- struct b53_device *dev = ds->priv;
- struct ethtool_keee *p = &dev->ports[port].eee;
-
-- if (is5325(dev) || is5365(dev))
-- return -EOPNOTSUPP;
--
- p->eee_enabled = e->eee_enabled;
- b53_eee_enable_set(ds, port, e->eee_enabled);
-
-@@ -2433,6 +2433,7 @@ static const struct dsa_switch_ops b53_s
- .port_setup = b53_setup_port,
- .port_enable = b53_enable_port,
- .port_disable = b53_disable_port,
-+ .support_eee = b53_support_eee,
- .get_mac_eee = b53_get_mac_eee,
- .set_mac_eee = b53_set_mac_eee,
- .port_bridge_join = b53_br_join,
---- a/drivers/net/dsa/b53/b53_priv.h
-+++ b/drivers/net/dsa/b53/b53_priv.h
-@@ -387,6 +387,7 @@ int b53_enable_port(struct dsa_switch *d
- void b53_disable_port(struct dsa_switch *ds, int port);
- void b53_brcm_hdr_setup(struct dsa_switch *ds, int port);
- int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy);
-+bool b53_support_eee(struct dsa_switch *ds, int port);
- int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e);
- int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e);
-
+++ /dev/null
-From c4f873c2b65c839ff5e7c996bd9ef5a1e7eae11a Mon Sep 17 00:00:00 2001
-Date: Mon, 17 Feb 2025 09:05:01 +0100
-Subject: [PATCH] net: dsa: b53: mdio: add support for BCM53101
-
-BCM53101 is a ethernet switch, very similar to the BCM53115.
-Enable support for it, in the existing b53 dsa driver.
-
----
- drivers/net/dsa/b53/b53_common.c | 14 ++++++++++++++
- drivers/net/dsa/b53/b53_mdio.c | 1 +
- drivers/net/dsa/b53/b53_priv.h | 2 ++
- 3 files changed, 17 insertions(+)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -2552,6 +2552,19 @@ static const struct b53_chip_data b53_sw
- .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
- },
- {
-+ .chip_id = BCM53101_DEVICE_ID,
-+ .dev_name = "BCM53101",
-+ .vlans = 4096,
-+ .enabled_ports = 0x11f,
-+ .arl_bins = 4,
-+ .arl_buckets = 512,
-+ .vta_regs = B53_VTA_REGS,
-+ .imp_port = 8,
-+ .duplex_reg = B53_DUPLEX_STAT_GE,
-+ .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+ .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+ },
-+ {
- .chip_id = BCM53115_DEVICE_ID,
- .dev_name = "BCM53115",
- .vlans = 4096,
-@@ -2932,6 +2945,7 @@ int b53_switch_detect(struct b53_device
- return ret;
-
- switch (id32) {
-+ case BCM53101_DEVICE_ID:
- case BCM53115_DEVICE_ID:
- case BCM53125_DEVICE_ID:
- case BCM53128_DEVICE_ID:
---- a/drivers/net/dsa/b53/b53_mdio.c
-+++ b/drivers/net/dsa/b53/b53_mdio.c
-@@ -374,6 +374,7 @@ static void b53_mdio_shutdown(struct mdi
-
- static const struct of_device_id b53_of_match[] = {
- { .compatible = "brcm,bcm5325" },
-+ { .compatible = "brcm,bcm53101" },
- { .compatible = "brcm,bcm53115" },
- { .compatible = "brcm,bcm53125" },
- { .compatible = "brcm,bcm53128" },
---- a/drivers/net/dsa/b53/b53_priv.h
-+++ b/drivers/net/dsa/b53/b53_priv.h
-@@ -66,6 +66,7 @@ enum {
- BCM5395_DEVICE_ID = 0x95,
- BCM5397_DEVICE_ID = 0x97,
- BCM5398_DEVICE_ID = 0x98,
-+ BCM53101_DEVICE_ID = 0x53101,
- BCM53115_DEVICE_ID = 0x53115,
- BCM53125_DEVICE_ID = 0x53125,
- BCM53128_DEVICE_ID = 0x53128,
-@@ -190,6 +191,7 @@ static inline int is531x5(struct b53_dev
- {
- return dev->chip_id == BCM53115_DEVICE_ID ||
- dev->chip_id == BCM53125_DEVICE_ID ||
-+ dev->chip_id == BCM53101_DEVICE_ID ||
- dev->chip_id == BCM53128_DEVICE_ID ||
- dev->chip_id == BCM53134_DEVICE_ID;
- }
+++ /dev/null
-From e39d14a760c039af0653e3df967e7525413924a0 Mon Sep 17 00:00:00 2001
-Date: Sat, 10 May 2025 11:22:11 +0200
-Subject: [PATCH] net: dsa: b53: implement setting ageing time
-
-b53 supported switches support configuring ageing time between 1 and
-1,048,575 seconds, so add an appropriate setter.
-
-This allows b53 to pass the FDB learning test for both vlan aware and
-vlan unaware bridges.
-
----
- drivers/net/dsa/b53/b53_common.c | 28 ++++++++++++++++++++++++++++
- drivers/net/dsa/b53/b53_priv.h | 1 +
- drivers/net/dsa/b53/b53_regs.h | 7 +++++++
- 3 files changed, 36 insertions(+)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -21,6 +21,7 @@
- #include <linux/export.h>
- #include <linux/gpio.h>
- #include <linux/kernel.h>
-+#include <linux/math.h>
- #include <linux/module.h>
- #include <linux/platform_data/b53.h>
- #include <linux/phy.h>
-@@ -1202,6 +1203,10 @@ static int b53_setup(struct dsa_switch *
- */
- ds->untag_vlan_aware_bridge_pvid = true;
-
-+ /* Ageing time is set in seconds */
-+ ds->ageing_time_min = 1 * 1000;
-+ ds->ageing_time_max = AGE_TIME_MAX * 1000;
-+
- ret = b53_reset_switch(dev);
- if (ret) {
- dev_err(ds->dev, "failed to reset switch\n");
-@@ -2412,6 +2417,28 @@ static int b53_get_max_mtu(struct dsa_sw
- return B53_MAX_MTU;
- }
-
-+int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
-+{
-+ struct b53_device *dev = ds->priv;
-+ u32 atc;
-+ int reg;
-+
-+ if (is63xx(dev))
-+ reg = B53_AGING_TIME_CONTROL_63XX;
-+ else
-+ reg = B53_AGING_TIME_CONTROL;
-+
-+ atc = DIV_ROUND_CLOSEST(msecs, 1000);
-+
-+ if (!is5325(dev) && !is5365(dev))
-+ atc |= AGE_CHANGE;
-+
-+ b53_write32(dev, B53_MGMT_PAGE, reg, atc);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(b53_set_ageing_time);
-+
- static const struct phylink_mac_ops b53_phylink_mac_ops = {
- .mac_select_pcs = b53_phylink_mac_select_pcs,
- .mac_config = b53_phylink_mac_config,
-@@ -2436,6 +2463,7 @@ static const struct dsa_switch_ops b53_s
- .support_eee = b53_support_eee,
- .get_mac_eee = b53_get_mac_eee,
- .set_mac_eee = b53_set_mac_eee,
-+ .set_ageing_time = b53_set_ageing_time,
- .port_bridge_join = b53_br_join,
- .port_bridge_leave = b53_br_leave,
- .port_pre_bridge_flags = b53_br_flags_pre,
---- a/drivers/net/dsa/b53/b53_priv.h
-+++ b/drivers/net/dsa/b53/b53_priv.h
-@@ -343,6 +343,7 @@ void b53_get_strings(struct dsa_switch *
- void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
- int b53_get_sset_count(struct dsa_switch *ds, int port, int sset);
- void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data);
-+int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs);
- int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
- bool *tx_fwd_offload, struct netlink_ext_ack *extack);
- void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge);
---- a/drivers/net/dsa/b53/b53_regs.h
-+++ b/drivers/net/dsa/b53/b53_regs.h
-@@ -220,6 +220,13 @@
- #define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */
- #define BRCM_HDR_P7_EN BIT(2) /* Enable tagging on port 7 */
-
-+/* Aging Time control register (32 bit) */
-+#define B53_AGING_TIME_CONTROL 0x06
-+#define B53_AGING_TIME_CONTROL_63XX 0x08
-+#define AGE_CHANGE BIT(20)
-+#define AGE_TIME_MASK 0x7ffff
-+#define AGE_TIME_MAX 1048575
-+
- /* Mirror capture control register (16 bit) */
- #define B53_MIR_CAP_CTL 0x10
- #define CAP_PORT_MASK 0xf
+++ /dev/null
-From 1237c2d4a8db79dfd4369bff6930b0e385ed7d5c Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Jun 2025 21:39:49 +0200
-Subject: [PATCH] net: dsa: b53: do not enable EEE on bcm63xx
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM63xx internal switches do not support EEE, but provide multiple RGMII
-ports where external PHYs may be connected. If one of these PHYs are EEE
-capable, we may try to enable EEE for the MACs, which then hangs the
-system on access of the (non-existent) EEE registers.
-
-Fix this by checking if the switch actually supports EEE before
-attempting to configure it.
-
-Fixes: 22256b0afb12 ("net: dsa: b53: Move EEE functions to b53")
----
- drivers/net/dsa/b53/b53_common.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -2353,6 +2353,9 @@ int b53_eee_init(struct dsa_switch *ds,
- {
- int ret;
-
-+ if (!b53_support_eee(ds, port))
-+ return 0;
-+
- ret = phy_init_eee(phy, false);
- if (ret)
- return 0;
-@@ -2367,7 +2370,7 @@ bool b53_support_eee(struct dsa_switch *
- {
- struct b53_device *dev = ds->priv;
-
-- return !is5325(dev) && !is5365(dev);
-+ return !is5325(dev) && !is5365(dev) && !is63xx(dev);
- }
- EXPORT_SYMBOL(b53_support_eee);
-
+++ /dev/null
-From 4af523551d876ab8b8057d1e5303a860fd736fcb Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Jun 2025 21:39:50 +0200
-Subject: [PATCH] net: dsa: b53: do not enable RGMII delay on bcm63xx
-
-bcm63xx's RGMII ports are always in MAC mode, never in PHY mode, so we
-shouldn't enable any delays and let the PHY handle any delays as
-necessary.
-
-This fixes using RGMII ports with normal PHYs like BCM54612E, which will
-handle the delay in the PHY.
-
-Fixes: ce3bf94871f7 ("net: dsa: b53: add support for BCM63xx RGMIIs")
----
- drivers/net/dsa/b53/b53_common.c | 19 +------------------
- 1 file changed, 1 insertion(+), 18 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -1330,24 +1330,7 @@ static void b53_adjust_63xx_rgmii(struct
- off = B53_RGMII_CTRL_P(port);
-
- b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
--
-- switch (interface) {
-- case PHY_INTERFACE_MODE_RGMII_ID:
-- rgmii_ctrl |= (RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
-- break;
-- case PHY_INTERFACE_MODE_RGMII_RXID:
-- rgmii_ctrl &= ~(RGMII_CTRL_DLL_TXC);
-- rgmii_ctrl |= RGMII_CTRL_DLL_RXC;
-- break;
-- case PHY_INTERFACE_MODE_RGMII_TXID:
-- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC);
-- rgmii_ctrl |= RGMII_CTRL_DLL_TXC;
-- break;
-- case PHY_INTERFACE_MODE_RGMII:
-- default:
-- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
-- break;
-- }
-+ rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
-
- if (port != dev->imp_port) {
- if (is63268(dev))
+++ /dev/null
-From 75f4f7b2b13008803f84768ff90396f9d7553221 Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Jun 2025 21:39:51 +0200
-Subject: [PATCH] net: dsa: b53: do not configure bcm63xx's IMP port interface
-
-The IMP port is not a valid RGMII interface, but hard wired to internal,
-so we shouldn't touch the undefined register B53_RGMII_CTRL_IMP.
-
-While this does not seem to have any side effects, let's not touch it at
-all, so limit RGMII configuration on bcm63xx to the actual RGMII ports.
-
-Fixes: ce3bf94871f7 ("net: dsa: b53: add support for BCM63xx RGMIIs")
----
- drivers/net/dsa/b53/b53_common.c | 22 ++++++++--------------
- 1 file changed, 8 insertions(+), 14 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -22,6 +22,7 @@
- #include <linux/gpio.h>
- #include <linux/kernel.h>
- #include <linux/math.h>
-+#include <linux/minmax.h>
- #include <linux/module.h>
- #include <linux/platform_data/b53.h>
- #include <linux/phy.h>
-@@ -1322,24 +1323,17 @@ static void b53_adjust_63xx_rgmii(struct
- phy_interface_t interface)
- {
- struct b53_device *dev = ds->priv;
-- u8 rgmii_ctrl = 0, off;
-+ u8 rgmii_ctrl = 0;
-
-- if (port == dev->imp_port)
-- off = B53_RGMII_CTRL_IMP;
-- else
-- off = B53_RGMII_CTRL_P(port);
--
-- b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
-+ b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl);
- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
-
-- if (port != dev->imp_port) {
-- if (is63268(dev))
-- rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
-+ if (is63268(dev))
-+ rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
-
-- rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
-- }
-+ rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
-
-- b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl);
-+ b53_write8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), rgmii_ctrl);
-
- dev_dbg(ds->dev, "Configured port %d for %s\n", port,
- phy_modes(interface));
-@@ -1484,7 +1478,7 @@ static void b53_phylink_mac_config(struc
- struct b53_device *dev = ds->priv;
- int port = dp->index;
-
-- if (is63xx(dev) && port >= B53_63XX_RGMII0)
-+ if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4))
- b53_adjust_63xx_rgmii(ds, port, interface);
-
- if (mode == MLO_AN_FIXED) {
+++ /dev/null
-From 5ea0d42c1980e6d10e5cb56a78021db5bfcebaaf Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Jun 2025 21:39:52 +0200
-Subject: [PATCH] net: dsa: b53: allow RGMII for bcm63xx RGMII ports
-
-Add RGMII to supported interfaces for BCM63xx RGMII ports so they can be
-actually used in RGMII mode.
-
-Without this, phylink will fail to configure them:
-
-[ 3.580000] b53-switch 10700000.switch GbE3 (uninitialized): validation of rgmii with support 0000000,00000000,00000000,000062ff and advertisement 0000000,00000000,00000000,000062ff failed: -EINVAL
-[ 3.600000] b53-switch 10700000.switch GbE3 (uninitialized): failed to connect to PHY: -EINVAL
-[ 3.610000] b53-switch 10700000.switch GbE3 (uninitialized): error -22 setting up PHY for tree 0, switch 0, port 4
-
-Fixes: ce3bf94871f7 ("net: dsa: b53: add support for BCM63xx RGMIIs")
----
- drivers/net/dsa/b53/b53_common.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -1439,6 +1439,10 @@ static void b53_phylink_get_caps(struct
- __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_REVMII, config->supported_interfaces);
-
-+ /* BCM63xx RGMII ports support RGMII */
-+ if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4))
-+ phy_interface_set_rgmii(config->supported_interfaces);
-+
- config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
- MAC_10 | MAC_100;
-
+++ /dev/null
-From bc1a65eb81a21e2aa3c3dca058ee8adf687b6ef5 Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Jun 2025 21:39:53 +0200
-Subject: [PATCH] net: dsa: b53: do not touch DLL_IQQD on bcm53115
-
-According to OpenMDK, bit 2 of the RGMII register has a different
-meaning for BCM53115 [1]:
-
-"DLL_IQQD 1: In the IDDQ mode, power is down0: Normal function
- mode"
-
-Configuring RGMII delay works without setting this bit, so let's keep it
-at the default. For other chips, we always set it, so not clearing it
-is not an issue.
-
-One would assume BCM53118 works the same, but OpenMDK is not quite sure
-what this bit actually means [2]:
-
-"BYPASS_IMP_2NS_DEL #1: In the IDDQ mode, power is down#0: Normal
- function mode1: Bypass dll65_2ns_del IP0: Use
- dll65_2ns_del IP"
-
-So lets keep setting it for now.
-
-[1] https://github.com/Broadcom-Network-Switching-Software/OpenMDK/blob/master/cdk/PKG/chip/bcm53115/bcm53115_a0_defs.h#L19871
-[2] https://github.com/Broadcom-Network-Switching-Software/OpenMDK/blob/master/cdk/PKG/chip/bcm53118/bcm53118_a0_defs.h#L14392
-
-Fixes: 967dd82ffc52 ("net: dsa: b53: Add support for Broadcom RoboSwitch")
----
- drivers/net/dsa/b53/b53_common.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -1354,8 +1354,7 @@ static void b53_adjust_531x5_rgmii(struc
- * tx_clk aligned timing (restoring to reset defaults)
- */
- b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
-- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC |
-- RGMII_CTRL_TIMING_SEL);
-+ rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
-
- /* PHY_INTERFACE_MODE_RGMII_TXID means TX internal delay, make
- * sure that we enable the port TX clock internal delay to
-@@ -1375,7 +1374,10 @@ static void b53_adjust_531x5_rgmii(struc
- rgmii_ctrl |= RGMII_CTRL_DLL_TXC;
- if (interface == PHY_INTERFACE_MODE_RGMII)
- rgmii_ctrl |= RGMII_CTRL_DLL_TXC | RGMII_CTRL_DLL_RXC;
-- rgmii_ctrl |= RGMII_CTRL_TIMING_SEL;
-+
-+ if (dev->chip_id != BCM53115_DEVICE_ID)
-+ rgmii_ctrl |= RGMII_CTRL_TIMING_SEL;
-+
- b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl);
-
- dev_info(ds->dev, "Configured port %d for %s\n", port,
--- /dev/null
+From 8cae5a0d91fea01d90ce7c1827e26934a22ca2fa Mon Sep 17 00:00:00 2001
+Date: Wed, 5 Mar 2025 11:53:56 +0000
+Subject: [PATCH] igc: enable HW vlan tag insertion/stripping by default
+
+This is enabled by default in other Intel drivers I've checked (e1000, e1000e,
+iavf, igb and ice). Fixes an out-of-the-box performance issue when running
+OpenWrt on typical mini-PCs with igc-supported Ethernet controllers and 802.1Q
+VLAN configurations, as ethtool isn't part of the default packages and sane
+defaults are expected.
+
+In my specific case, with an Intel N100-based machine with four I226-V Ethernet
+controllers, my upload performance increased from under 30 Mb/s to the expected
+~1 Gb/s.
+
+---
+ drivers/net/ethernet/intel/igc/igc_main.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/net/ethernet/intel/igc/igc_main.c
++++ b/drivers/net/ethernet/intel/igc/igc_main.c
+@@ -7066,6 +7066,9 @@ static int igc_probe(struct pci_dev *pde
+ netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
+ NETDEV_XDP_ACT_XSK_ZEROCOPY;
+
++ /* enable HW vlan tag insertion/stripping by default */
++ netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
++
+ /* MTU range: 68 - 9216 */
+ netdev->min_mtu = ETH_MIN_MTU;
+ netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE;
+++ /dev/null
-From efdddc4484859082da6c7877ed144c8121c8ea55 Mon Sep 17 00:00:00 2001
-Date: Thu, 29 May 2025 14:44:06 +0200
-Subject: [PATCH] net: dsa: tag_brcm: legacy: fix pskb_may_pull length
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BRCM_LEG_PORT_ID was incorrectly used for pskb_may_pull length.
-The correct check is BRCM_LEG_TAG_LEN + VLAN_HLEN, or 10 bytes.
-
-Fixes: 964dbf186eaa ("net: dsa: tag_brcm: add support for legacy tags")
----
- net/dsa/tag_brcm.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/net/dsa/tag_brcm.c
-+++ b/net/dsa/tag_brcm.c
-@@ -257,7 +257,7 @@ static struct sk_buff *brcm_leg_tag_rcv(
- int source_port;
- u8 *brcm_tag;
-
-- if (unlikely(!pskb_may_pull(skb, BRCM_LEG_PORT_ID)))
-+ if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN)))
- return NULL;
-
- brcm_tag = dsa_etype_header_pos_rx(skb);
--- /dev/null
+From 277f96c1f3f71d6e1d3bcf650d7cd84c1442210f Mon Sep 17 00:00:00 2001
+Date: Thu, 17 Oct 2024 11:22:11 +0800
+Subject: [PATCH 01/20] net: phy: mediatek-ge-soc: Fix coding style
+
+This patch fixes spelling errors, re-arrange vars with
+reverse Xmas tree and remove unnecessary parens in
+mediatek-ge-soc.c.
+
+---
+ drivers/net/phy/mediatek-ge-soc.c | 36 ++++++++++++++++---------------
+ 1 file changed, 19 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/phy/mediatek-ge-soc.c
++++ b/drivers/net/phy/mediatek-ge-soc.c
+@@ -408,16 +408,17 @@ static int tx_offset_cal_efuse(struct ph
+
+ static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
+ {
+- int i;
+- int bias[16] = {};
+- const int vals_9461[16] = { 7, 1, 4, 7,
+- 7, 1, 4, 7,
+- 7, 1, 4, 7,
+- 7, 1, 4, 7 };
+ const int vals_9481[16] = { 10, 6, 6, 10,
+ 10, 6, 6, 10,
+ 10, 6, 6, 10,
+ 10, 6, 6, 10 };
++ const int vals_9461[16] = { 7, 1, 4, 7,
++ 7, 1, 4, 7,
++ 7, 1, 4, 7,
++ 7, 1, 4, 7 };
++ int bias[16] = {};
++ int i;
++
+ switch (phydev->drv->phy_id) {
+ case MTK_GPHY_ID_MT7981:
+ /* We add some calibration to efuse values
+@@ -1069,10 +1070,10 @@ static int start_cal(struct phy_device *
+
+ static int mt798x_phy_calibration(struct phy_device *phydev)
+ {
++ struct nvmem_cell *cell;
+ int ret = 0;
+- u32 *buf;
+ size_t len;
+- struct nvmem_cell *cell;
++ u32 *buf;
+
+ cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
+ if (IS_ERR(cell)) {
+@@ -1210,14 +1211,15 @@ static int mt798x_phy_led_brightness_set
+ return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
+ }
+
+-static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+- BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+- BIT(TRIGGER_NETDEV_LINK) |
+- BIT(TRIGGER_NETDEV_LINK_10) |
+- BIT(TRIGGER_NETDEV_LINK_100) |
+- BIT(TRIGGER_NETDEV_LINK_1000) |
+- BIT(TRIGGER_NETDEV_RX) |
+- BIT(TRIGGER_NETDEV_TX));
++static const unsigned long supported_triggers =
++ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
++ BIT(TRIGGER_NETDEV_LINK) |
++ BIT(TRIGGER_NETDEV_LINK_10) |
++ BIT(TRIGGER_NETDEV_LINK_100) |
++ BIT(TRIGGER_NETDEV_LINK_1000) |
++ BIT(TRIGGER_NETDEV_RX) |
++ BIT(TRIGGER_NETDEV_TX);
+
+ static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+@@ -1415,7 +1417,7 @@ static int mt7988_phy_probe_shared(struc
+ * LED_C and LED_D respectively. At the same time those pins are used to
+ * bootstrap configuration of the reference clock source (LED_A),
+ * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
+- * In practise this is done using a LED and a resistor pulling the pin
++ * In practice this is done using a LED and a resistor pulling the pin
+ * either to GND or to VIO.
+ * The detected value at boot time is accessible at run-time using the
+ * TPBANK0 register located in the gpio base of the pinctrl, in order
--- /dev/null
+From c0dc1b412f9d840c51c5ee8927bf066e15a59550 Mon Sep 17 00:00:00 2001
+Date: Thu, 17 Oct 2024 11:22:12 +0800
+Subject: [PATCH 02/20] net: phy: mediatek-ge-soc: Shrink line wrapping to 80
+ characters
+
+This patch shrinks line wrapping to 80 chars. Also, in
+tx_amp_fill_result(), use FIELD_PREP() to prettify code.
+
+---
+ drivers/net/phy/mediatek-ge-soc.c | 125 +++++++++++++++++++++---------
+ 1 file changed, 88 insertions(+), 37 deletions(-)
+
+--- a/drivers/net/phy/mediatek-ge-soc.c
++++ b/drivers/net/phy/mediatek-ge-soc.c
+@@ -342,7 +342,8 @@ static int cal_cycle(struct phy_device *
+ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
+ MTK_PHY_RG_AD_CAL_CLK, reg_val,
+ reg_val & MTK_PHY_DA_CAL_CLK, 500,
+- ANALOG_INTERNAL_OPERATION_MAX_US, false);
++ ANALOG_INTERNAL_OPERATION_MAX_US,
++ false);
+ if (ret) {
+ phydev_err(phydev, "Calibration cycle timeout\n");
+ return ret;
+@@ -441,40 +442,72 @@ static int tx_amp_fill_result(struct phy
+ }
+
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+- MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10);
++ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
++ buf[0] + bias[0]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+- MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]);
++ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
++ buf[0] + bias[1]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+- MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10);
++ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
++ buf[0] + bias[2]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+- MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]);
++ MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
++ buf[0] + bias[3]));
+
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+- MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8);
++ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
++ buf[1] + bias[4]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+- MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]);
++ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
++ buf[1] + bias[5]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+- MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8);
++ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
++ buf[1] + bias[6]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+- MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]);
++ MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
++ buf[1] + bias[7]));
+
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+- MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8);
++ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
++ buf[2] + bias[8]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+- MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]);
++ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
++ buf[2] + bias[9]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+- MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8);
++ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
++ buf[2] + bias[10]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+- MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]);
++ MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
++ buf[2] + bias[11]));
+
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+- MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8);
++ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
++ buf[3] + bias[12]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+- MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]);
++ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
++ buf[3] + bias[13]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+- MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8);
++ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
++ buf[3] + bias[14]));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+- MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]);
++ MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
++ buf[3] + bias[15]));
+
+ return 0;
+ }
+@@ -663,7 +696,8 @@ static int tx_vcm_cal_sw(struct phy_devi
+ goto restore;
+
+ /* We calibrate TX-VCM in different logic. Check upper index and then
+- * lower index. If this calibration is valid, apply lower index's result.
++ * lower index. If this calibration is valid, apply lower index's
++ * result.
+ */
+ ret = upper_ret - lower_ret;
+ if (ret == 1) {
+@@ -692,7 +726,8 @@ static int tx_vcm_cal_sw(struct phy_devi
+ } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
+ lower_ret == 0) {
+ ret = 0;
+- phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n",
++ phydev_warn(phydev,
++ "TX-VCM SW cal result at high margin 0x%x\n",
+ upper_idx);
+ } else {
+ ret = -EINVAL;
+@@ -796,7 +831,8 @@ static void mt7981_phy_finetune(struct p
+
+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
++ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
++ MTK_PHY_LPF_X_AVERAGE_MASK,
+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
+
+ /* rg_tr_lpf_cnt_val = 512 */
+@@ -865,7 +901,8 @@ static void mt7988_phy_finetune(struct p
+
+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
++ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
++ MTK_PHY_LPF_X_AVERAGE_MASK,
+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
+
+ /* rg_tr_lpf_cnt_val = 1023 */
+@@ -977,7 +1014,8 @@ static void mt798x_phy_eee(struct phy_de
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
+- __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
++ __phy_modify(phydev, MTK_PHY_LPI_REG_14,
++ MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
+ FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
+
+ __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
+@@ -987,7 +1025,8 @@ static void mt798x_phy_eee(struct phy_de
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
+ MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff));
++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++ 0xff));
+ }
+
+ static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
+@@ -1147,7 +1186,8 @@ static int mt798x_phy_hw_led_on_set(stru
+ (index ? 16 : 0), &priv->led_state);
+ if (changed)
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++ MTK_PHY_LED1_ON_CTRL :
++ MTK_PHY_LED0_ON_CTRL,
+ MTK_PHY_LED_ON_MASK,
+ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+ else
+@@ -1157,7 +1197,8 @@ static int mt798x_phy_hw_led_on_set(stru
+ static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+ bool blinking)
+ {
+- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++ (index ? 16 : 0);
+ struct mtk_socphy_priv *priv = phydev->priv;
+ bool changed;
+
+@@ -1170,8 +1211,10 @@ static int mt798x_phy_hw_led_blink_set(s
+ (index ? 16 : 0), &priv->led_state);
+ if (changed)
+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL,
+- blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
++ MTK_PHY_LED1_BLINK_CTRL :
++ MTK_PHY_LED0_BLINK_CTRL,
++ blinking ?
++ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+ else
+ return 0;
+ }
+@@ -1237,7 +1280,8 @@ static int mt798x_phy_led_hw_is_supporte
+ static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules)
+ {
+- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++ (index ? 16 : 0);
+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+ struct mtk_socphy_priv *priv = phydev->priv;
+@@ -1258,8 +1302,8 @@ static int mt798x_phy_led_hw_control_get
+ if (blink < 0)
+ return -EIO;
+
+- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX |
+- MTK_PHY_LED_ON_LINKDOWN)) ||
++ if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
++ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
+ (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
+ set_bit(bit_netdev, &priv->led_state);
+ else
+@@ -1333,17 +1377,23 @@ static int mt798x_phy_led_hw_control_set
+
+ if (rules & BIT(TRIGGER_NETDEV_RX)) {
+ blink |= (on & MTK_PHY_LED_ON_LINK) ?
+- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) :
++ (((on & MTK_PHY_LED_ON_LINK10) ?
++ MTK_PHY_LED_BLINK_10RX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK100) ?
++ MTK_PHY_LED_BLINK_100RX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK1000) ?
++ MTK_PHY_LED_BLINK_1000RX : 0)) :
+ MTK_PHY_LED_BLINK_RX;
+ }
+
+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
+ blink |= (on & MTK_PHY_LED_ON_LINK) ?
+- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) :
++ (((on & MTK_PHY_LED_ON_LINK10) ?
++ MTK_PHY_LED_BLINK_10TX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK100) ?
++ MTK_PHY_LED_BLINK_100TX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK1000) ?
++ MTK_PHY_LED_BLINK_1000TX : 0)) :
+ MTK_PHY_LED_BLINK_TX;
+ }
+
+@@ -1400,7 +1450,8 @@ static int mt7988_phy_fix_leds_polaritie
+ /* Only now setup pinctrl to avoid bogus blinking */
+ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
+ if (IS_ERR(pinctrl))
+- dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n");
++ dev_err(&phydev->mdio.bus->dev,
++ "Failed to setup PHY LED pinctrl\n");
+
+ return 0;
+ }
--- /dev/null
+From bcbbfb4f62c4ba35783cc617997a2e92d91e3940 Mon Sep 17 00:00:00 2001
+Date: Thu, 17 Oct 2024 11:22:13 +0800
+Subject: [PATCH 03/20] net: phy: mediatek-ge-soc: Propagate error code
+ correctly in cal_cycle()
+
+This patch propagates error code correctly in cal_cycle()
+and improve with FIELD_GET().
+
+---
+ drivers/net/phy/mediatek-ge-soc.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/phy/mediatek-ge-soc.c
++++ b/drivers/net/phy/mediatek-ge-soc.c
+@@ -110,7 +110,7 @@
+ #define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
+
+ #define MTK_PHY_RG_AD_CAL_COMP 0x17a
+-#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8)
++#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8)
+
+ #define MTK_PHY_RG_AD_CAL_CLK 0x17b
+ #define MTK_PHY_DA_CAL_CLK BIT(0)
+@@ -351,8 +351,10 @@ static int cal_cycle(struct phy_device *
+
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+ MTK_PHY_DA_CALIN_FLAG);
+- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >>
+- MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
++ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
++ if (ret < 0)
++ return ret;
++ ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
+ phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
+
+ return ret;
--- /dev/null
+From e062f073dc0df4fcd338043cb0b69b6bcd31e4af Mon Sep 17 00:00:00 2001
+Date: Sat, 9 Nov 2024 00:34:51 +0800
+Subject: [PATCH 04/20] net: phy: mediatek: Re-organize MediaTek ethernet phy
+ drivers
+
+Re-organize MediaTek ethernet phy driver files and get ready to integrate
+some common functions and add new 2.5G phy driver.
+mtk-ge.c: MT7530 Gphy on MT7621 & MT7531 Gphy
+mtk-ge-soc.c: Built-in Gphy on MT7981 & Built-in switch Gphy on MT7988
+mtk-2p5ge.c: Planned for built-in 2.5G phy on MT7988
+
+---
+ MAINTAINERS | 4 ++--
+ drivers/net/phy/Kconfig | 17 +-------------
+ drivers/net/phy/Makefile | 3 +--
+ drivers/net/phy/mediatek/Kconfig | 22 +++++++++++++++++++
+ drivers/net/phy/mediatek/Makefile | 3 +++
+ .../mtk-ge-soc.c} | 0
+ .../phy/{mediatek-ge.c => mediatek/mtk-ge.c} | 0
+ 7 files changed, 29 insertions(+), 20 deletions(-)
+ create mode 100644 drivers/net/phy/mediatek/Kconfig
+ create mode 100644 drivers/net/phy/mediatek/Makefile
+ rename drivers/net/phy/{mediatek-ge-soc.c => mediatek/mtk-ge-soc.c} (100%)
+ rename drivers/net/phy/{mediatek-ge.c => mediatek/mtk-ge.c} (100%)
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+ S: Maintained
+-F: drivers/net/phy/mediatek-ge-soc.c
+-F: drivers/net/phy/mediatek-ge.c
++F: drivers/net/phy/mediatek/mtk-ge-soc.c
++F: drivers/net/phy/mediatek/mtk-ge.c
+ F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c
+
+ MEDIATEK I2C CONTROLLER DRIVER
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -266,22 +266,7 @@ config MAXLINEAR_GPHY
+ Support for the Maxlinear GPY115, GPY211, GPY212, GPY215,
+ GPY241, GPY245 PHYs.
+
+-config MEDIATEK_GE_PHY
+- tristate "MediaTek Gigabit Ethernet PHYs"
+- help
+- Supports the MediaTek Gigabit Ethernet PHYs.
+-
+-config MEDIATEK_GE_SOC_PHY
+- tristate "MediaTek SoC Ethernet PHYs"
+- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
+- depends on NVMEM_MTK_EFUSE
+- help
+- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+-
+- Include support for built-in Ethernet PHYs which are present in
+- the MT7981 and MT7988 SoCs. These PHYs need calibration data
+- present in the SoCs efuse and will dynamically calibrate VCM
+- (common-mode voltage) during startup.
++source "drivers/net/phy/mediatek/Kconfig"
+
+ config MICREL_PHY
+ tristate "Micrel PHYs"
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -74,8 +74,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o
+ obj-$(CONFIG_MARVELL_88Q2XXX_PHY) += marvell-88q2xxx.o
+ obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o
+ obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o
+-obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
+-obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o
++obj-y += mediatek/
+ obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
+ obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
+ obj-$(CONFIG_MICREL_PHY) += micrel.o
+--- /dev/null
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -0,0 +1,22 @@
++# SPDX-License-Identifier: GPL-2.0-only
++config MEDIATEK_GE_PHY
++ tristate "MediaTek Gigabit Ethernet PHYs"
++ help
++ Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
++
++ Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531.
++ You may find mt7530 inside mt7621. This driver shares some
++ common operations with MediaTek SoC built-in Gigabit
++ Ethernet PHYs.
++
++config MEDIATEK_GE_SOC_PHY
++ tristate "MediaTek SoC Ethernet PHYs"
++ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
++ depends on NVMEM_MTK_EFUSE
++ help
++ Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
++
++ Include support for built-in Ethernet PHYs which are present in
++ the MT7981 and MT7988 SoCs. These PHYs need calibration data
++ present in the SoCs efuse and will dynamically calibrate VCM
++ (common-mode voltage) during startup.
+--- /dev/null
++++ b/drivers/net/phy/mediatek/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
++obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
+--- a/drivers/net/phy/mediatek-ge-soc.c
++++ /dev/null
+@@ -1,1610 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0+
+-#include <linux/bitfield.h>
+-#include <linux/bitmap.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/module.h>
+-#include <linux/nvmem-consumer.h>
+-#include <linux/pinctrl/consumer.h>
+-#include <linux/phy.h>
+-#include <linux/regmap.h>
+-
+-#define MTK_GPHY_ID_MT7981 0x03a29461
+-#define MTK_GPHY_ID_MT7988 0x03a29481
+-
+-#define MTK_EXT_PAGE_ACCESS 0x1f
+-#define MTK_PHY_PAGE_STANDARD 0x0000
+-#define MTK_PHY_PAGE_EXTENDED_3 0x0003
+-
+-#define MTK_PHY_LPI_REG_14 0x14
+-#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0)
+-
+-#define MTK_PHY_LPI_REG_1c 0x1c
+-#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
+-
+-#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+-
+-#define ANALOG_INTERNAL_OPERATION_MAX_US 20
+-#define TXRESERVE_MIN 0
+-#define TXRESERVE_MAX 7
+-
+-#define MTK_PHY_ANARG_RG 0x10
+-#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8)
+-
+-/* Registers on MDIO_MMD_VEND1 */
+-#define MTK_PHY_TXVLD_DA_RG 0x12
+-#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10)
+-#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16
+-#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10)
+-#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17
+-#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8)
+-#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18
+-#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8)
+-#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19
+-#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8)
+-#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20
+-#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8)
+-#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21
+-#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8)
+-#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22
+-#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8)
+-#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0)
+-
+-#define MTK_PHY_RXADC_CTRL_RG7 0xc6
+-#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
+-
+-#define MTK_PHY_RXADC_CTRL_RG9 0xc8
+-#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12)
+-#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8)
+-#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4)
+-#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0)
+-
+-#define MTK_PHY_LDO_OUTPUT_V 0xd7
+-
+-#define MTK_PHY_RG_ANA_CAL_RG0 0xdb
+-#define MTK_PHY_RG_CAL_CKINV BIT(12)
+-#define MTK_PHY_RG_ANA_CALEN BIT(8)
+-#define MTK_PHY_RG_ZCALEN_A BIT(0)
+-
+-#define MTK_PHY_RG_ANA_CAL_RG1 0xdc
+-#define MTK_PHY_RG_ZCALEN_B BIT(12)
+-#define MTK_PHY_RG_ZCALEN_C BIT(8)
+-#define MTK_PHY_RG_ZCALEN_D BIT(4)
+-#define MTK_PHY_RG_TXVOS_CALEN BIT(0)
+-
+-#define MTK_PHY_RG_ANA_CAL_RG5 0xe0
+-#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8)
+-
+-#define MTK_PHY_RG_TX_FILTER 0xfe
+-
+-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120
+-#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8)
+-#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0)
+-
+-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122
+-#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0)
+-
+-#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144
+-#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5)
+-
+-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172
+-#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8)
+-#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0)
+-
+-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173
+-#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8)
+-#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
+-
+-#define MTK_PHY_RG_AD_CAL_COMP 0x17a
+-#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8)
+-
+-#define MTK_PHY_RG_AD_CAL_CLK 0x17b
+-#define MTK_PHY_DA_CAL_CLK BIT(0)
+-
+-#define MTK_PHY_RG_AD_CALIN 0x17c
+-#define MTK_PHY_DA_CALIN_FLAG BIT(0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d
+-#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e
+-#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f
+-#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180
+-#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181
+-#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182
+-#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183
+-#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184
+-#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DEV1E_REG19b 0x19b
+-#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8)
+-
+-#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a
+-#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b
+-#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c
+-#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d
+-#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e
+-#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f
+-#define MTK_PHY_RG_LP_IIR2_K4_L 0x230
+-#define MTK_PHY_RG_LP_IIR2_K4_U 0x231
+-#define MTK_PHY_RG_LP_IIR2_K5_L 0x232
+-#define MTK_PHY_RG_LP_IIR2_K5_U 0x233
+-
+-#define MTK_PHY_RG_DEV1E_REG234 0x234
+-#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0)
+-#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4)
+-#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12)
+-
+-#define MTK_PHY_RG_LPF_CNT_VAL 0x235
+-
+-#define MTK_PHY_RG_DEV1E_REG238 0x238
+-#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0)
+-#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12)
+-
+-#define MTK_PHY_RG_DEV1E_REG239 0x239
+-#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0)
+-#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12)
+-
+-#define MTK_PHY_RG_DEV1E_REG27C 0x27c
+-#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8)
+-#define MTK_PHY_RG_DEV1E_REG27D 0x27d
+-#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0)
+-
+-#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7
+-#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0)
+-#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8)
+-
+-#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1
+-#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0)
+-#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8)
+-#define MTK_PHY_LPI_TR_READY BIT(9)
+-#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10)
+-
+-#define MTK_PHY_RG_DEV1E_REG323 0x323
+-#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0)
+-#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4)
+-
+-#define MTK_PHY_RG_DEV1E_REG324 0x324
+-#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0)
+-#define MTK_PHY_SMI_DET_MAX_EN BIT(8)
+-
+-#define MTK_PHY_RG_DEV1E_REG326 0x326
+-#define MTK_PHY_LPI_MODE_SD_ON BIT(0)
+-#define MTK_PHY_RESET_RANDUPD_CNT BIT(1)
+-#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2)
+-#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4)
+-#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5)
+-
+-#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502
+-#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503
+-
+-#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d
+-#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e
+-#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f
+-#define MTK_PHY_DA_TX_R50_PAIR_D 0x540
+-
+-/* Registers on MDIO_MMD_VEND2 */
+-#define MTK_PHY_LED0_ON_CTRL 0x24
+-#define MTK_PHY_LED1_ON_CTRL 0x26
+-#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
+-#define MTK_PHY_LED_ON_LINK1000 BIT(0)
+-#define MTK_PHY_LED_ON_LINK100 BIT(1)
+-#define MTK_PHY_LED_ON_LINK10 BIT(2)
+-#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
+- MTK_PHY_LED_ON_LINK100 |\
+- MTK_PHY_LED_ON_LINK1000)
+-#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
+-#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
+-#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
+-#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
+-#define MTK_PHY_LED_ON_POLARITY BIT(14)
+-#define MTK_PHY_LED_ON_ENABLE BIT(15)
+-
+-#define MTK_PHY_LED0_BLINK_CTRL 0x25
+-#define MTK_PHY_LED1_BLINK_CTRL 0x27
+-#define MTK_PHY_LED_BLINK_1000TX BIT(0)
+-#define MTK_PHY_LED_BLINK_1000RX BIT(1)
+-#define MTK_PHY_LED_BLINK_100TX BIT(2)
+-#define MTK_PHY_LED_BLINK_100RX BIT(3)
+-#define MTK_PHY_LED_BLINK_10TX BIT(4)
+-#define MTK_PHY_LED_BLINK_10RX BIT(5)
+-#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
+- MTK_PHY_LED_BLINK_100RX |\
+- MTK_PHY_LED_BLINK_1000RX)
+-#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
+- MTK_PHY_LED_BLINK_100TX |\
+- MTK_PHY_LED_BLINK_1000TX)
+-#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
+-#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
+-#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
+-#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
+-
+-#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
+-
+-#define MTK_PHY_RG_BG_RASEL 0x115
+-#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0)
+-
+-/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
+-#define RG_GPIO_MISC_TPBANK0 0x6f0
+-#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8)
+-
+-/* These macro privides efuse parsing for internal phy. */
+-#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0))
+-#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0))
+-#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0))
+-#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0))
+-#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0))
+-
+-#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0))
+-#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0))
+-#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0))
+-#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0))
+-#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0))
+-
+-#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0))
+-#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0))
+-
+-#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0))
+-#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0))
+-
+-enum {
+- NO_PAIR,
+- PAIR_A,
+- PAIR_B,
+- PAIR_C,
+- PAIR_D,
+-};
+-
+-enum calibration_mode {
+- EFUSE_K,
+- SW_K
+-};
+-
+-enum CAL_ITEM {
+- REXT,
+- TX_OFFSET,
+- TX_AMP,
+- TX_R50,
+- TX_VCM
+-};
+-
+-enum CAL_MODE {
+- EFUSE_M,
+- SW_M
+-};
+-
+-#define MTK_PHY_LED_STATE_FORCE_ON 0
+-#define MTK_PHY_LED_STATE_FORCE_BLINK 1
+-#define MTK_PHY_LED_STATE_NETDEV 2
+-
+-struct mtk_socphy_priv {
+- unsigned long led_state;
+-};
+-
+-struct mtk_socphy_shared {
+- u32 boottrap;
+- struct mtk_socphy_priv priv[4];
+-};
+-
+-static int mtk_socphy_read_page(struct phy_device *phydev)
+-{
+- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_socphy_write_page(struct phy_device *phydev, int page)
+-{
+- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+-/* One calibration cycle consists of:
+- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
+- * until AD_CAL_COMP is ready to output calibration result.
+- * 2.Wait until DA_CAL_CLK is available.
+- * 3.Fetch AD_CAL_COMP_OUT.
+- */
+-static int cal_cycle(struct phy_device *phydev, int devad,
+- u32 regnum, u16 mask, u16 cal_val)
+-{
+- int reg_val;
+- int ret;
+-
+- phy_modify_mmd(phydev, devad, regnum,
+- mask, cal_val);
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+- MTK_PHY_DA_CALIN_FLAG);
+-
+- ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_AD_CAL_CLK, reg_val,
+- reg_val & MTK_PHY_DA_CAL_CLK, 500,
+- ANALOG_INTERNAL_OPERATION_MAX_US,
+- false);
+- if (ret) {
+- phydev_err(phydev, "Calibration cycle timeout\n");
+- return ret;
+- }
+-
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+- MTK_PHY_DA_CALIN_FLAG);
+- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
+- if (ret < 0)
+- return ret;
+- ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
+- phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
+-
+- return ret;
+-}
+-
+-static int rext_fill_result(struct phy_device *phydev, u16 *buf)
+-{
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+- MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
+- phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
+- MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
+-
+- return 0;
+-}
+-
+-static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
+-{
+- u16 rext_cal_val[2];
+-
+- rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
+- rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
+- rext_fill_result(phydev, rext_cal_val);
+-
+- return 0;
+-}
+-
+-static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
+-{
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
+- MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
+- MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
+- MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
+- MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
+-
+- return 0;
+-}
+-
+-static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
+-{
+- u16 tx_offset_cal_val[4];
+-
+- tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
+- tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
+- tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
+- tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
+-
+- tx_offset_fill_result(phydev, tx_offset_cal_val);
+-
+- return 0;
+-}
+-
+-static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
+-{
+- const int vals_9481[16] = { 10, 6, 6, 10,
+- 10, 6, 6, 10,
+- 10, 6, 6, 10,
+- 10, 6, 6, 10 };
+- const int vals_9461[16] = { 7, 1, 4, 7,
+- 7, 1, 4, 7,
+- 7, 1, 4, 7,
+- 7, 1, 4, 7 };
+- int bias[16] = {};
+- int i;
+-
+- switch (phydev->drv->phy_id) {
+- case MTK_GPHY_ID_MT7981:
+- /* We add some calibration to efuse values
+- * due to board level influence.
+- * GBE: +7, TBT: +1, HBT: +4, TST: +7
+- */
+- memcpy(bias, (const void *)vals_9461, sizeof(bias));
+- break;
+- case MTK_GPHY_ID_MT7988:
+- memcpy(bias, (const void *)vals_9481, sizeof(bias));
+- break;
+- }
+-
+- /* Prevent overflow */
+- for (i = 0; i < 12; i++) {
+- if (buf[i >> 2] + bias[i] > 63) {
+- buf[i >> 2] = 63;
+- bias[i] = 0;
+- }
+- }
+-
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+- MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
+- buf[0] + bias[0]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+- MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
+- buf[0] + bias[1]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+- MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
+- buf[0] + bias[2]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+- MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
+- buf[0] + bias[3]));
+-
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+- MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
+- buf[1] + bias[4]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+- MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
+- buf[1] + bias[5]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+- MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
+- buf[1] + bias[6]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+- MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
+- buf[1] + bias[7]));
+-
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+- MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
+- buf[2] + bias[8]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+- MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
+- buf[2] + bias[9]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+- MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
+- buf[2] + bias[10]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+- MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
+- buf[2] + bias[11]));
+-
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+- MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
+- buf[3] + bias[12]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+- MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
+- buf[3] + bias[13]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+- MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
+- buf[3] + bias[14]));
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+- MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
+- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
+- buf[3] + bias[15]));
+-
+- return 0;
+-}
+-
+-static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
+-{
+- u16 tx_amp_cal_val[4];
+-
+- tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
+- tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
+- tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
+- tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
+- tx_amp_fill_result(phydev, tx_amp_cal_val);
+-
+- return 0;
+-}
+-
+-static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
+- u8 txg_calen_x)
+-{
+- int bias = 0;
+- u16 reg, val;
+-
+- if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
+- bias = -1;
+-
+- val = clamp_val(bias + tx_r50_cal_val, 0, 63);
+-
+- switch (txg_calen_x) {
+- case PAIR_A:
+- reg = MTK_PHY_DA_TX_R50_PAIR_A;
+- break;
+- case PAIR_B:
+- reg = MTK_PHY_DA_TX_R50_PAIR_B;
+- break;
+- case PAIR_C:
+- reg = MTK_PHY_DA_TX_R50_PAIR_C;
+- break;
+- case PAIR_D:
+- reg = MTK_PHY_DA_TX_R50_PAIR_D;
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
+-
+- return 0;
+-}
+-
+-static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
+- u8 txg_calen_x)
+-{
+- u16 tx_r50_cal_val;
+-
+- switch (txg_calen_x) {
+- case PAIR_A:
+- tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
+- break;
+- case PAIR_B:
+- tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
+- break;
+- case PAIR_C:
+- tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
+- break;
+- case PAIR_D:
+- tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
+- break;
+- default:
+- return -EINVAL;
+- }
+- tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
+-
+- return 0;
+-}
+-
+-static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
+-{
+- u8 lower_idx, upper_idx, txreserve_val;
+- u8 lower_ret, upper_ret;
+- int ret;
+-
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+- MTK_PHY_RG_ANA_CALEN);
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+- MTK_PHY_RG_CAL_CKINV);
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+- MTK_PHY_RG_TXVOS_CALEN);
+-
+- switch (rg_txreserve_x) {
+- case PAIR_A:
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DASN_DAC_IN0_A,
+- MTK_PHY_DASN_DAC_IN0_A_MASK);
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DASN_DAC_IN1_A,
+- MTK_PHY_DASN_DAC_IN1_A_MASK);
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_ANA_CAL_RG0,
+- MTK_PHY_RG_ZCALEN_A);
+- break;
+- case PAIR_B:
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DASN_DAC_IN0_B,
+- MTK_PHY_DASN_DAC_IN0_B_MASK);
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DASN_DAC_IN1_B,
+- MTK_PHY_DASN_DAC_IN1_B_MASK);
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_ANA_CAL_RG1,
+- MTK_PHY_RG_ZCALEN_B);
+- break;
+- case PAIR_C:
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DASN_DAC_IN0_C,
+- MTK_PHY_DASN_DAC_IN0_C_MASK);
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DASN_DAC_IN1_C,
+- MTK_PHY_DASN_DAC_IN1_C_MASK);
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_ANA_CAL_RG1,
+- MTK_PHY_RG_ZCALEN_C);
+- break;
+- case PAIR_D:
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DASN_DAC_IN0_D,
+- MTK_PHY_DASN_DAC_IN0_D_MASK);
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DASN_DAC_IN1_D,
+- MTK_PHY_DASN_DAC_IN1_D_MASK);
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_ANA_CAL_RG1,
+- MTK_PHY_RG_ZCALEN_D);
+- break;
+- default:
+- ret = -EINVAL;
+- goto restore;
+- }
+-
+- lower_idx = TXRESERVE_MIN;
+- upper_idx = TXRESERVE_MAX;
+-
+- phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
+- while ((upper_idx - lower_idx) > 1) {
+- txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
+- ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+- MTK_PHY_DA_RX_PSBN_TBT_MASK |
+- MTK_PHY_DA_RX_PSBN_HBT_MASK |
+- MTK_PHY_DA_RX_PSBN_GBE_MASK |
+- MTK_PHY_DA_RX_PSBN_LP_MASK,
+- txreserve_val << 12 | txreserve_val << 8 |
+- txreserve_val << 4 | txreserve_val);
+- if (ret == 1) {
+- upper_idx = txreserve_val;
+- upper_ret = ret;
+- } else if (ret == 0) {
+- lower_idx = txreserve_val;
+- lower_ret = ret;
+- } else {
+- goto restore;
+- }
+- }
+-
+- if (lower_idx == TXRESERVE_MIN) {
+- lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RXADC_CTRL_RG9,
+- MTK_PHY_DA_RX_PSBN_TBT_MASK |
+- MTK_PHY_DA_RX_PSBN_HBT_MASK |
+- MTK_PHY_DA_RX_PSBN_GBE_MASK |
+- MTK_PHY_DA_RX_PSBN_LP_MASK,
+- lower_idx << 12 | lower_idx << 8 |
+- lower_idx << 4 | lower_idx);
+- ret = lower_ret;
+- } else if (upper_idx == TXRESERVE_MAX) {
+- upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RXADC_CTRL_RG9,
+- MTK_PHY_DA_RX_PSBN_TBT_MASK |
+- MTK_PHY_DA_RX_PSBN_HBT_MASK |
+- MTK_PHY_DA_RX_PSBN_GBE_MASK |
+- MTK_PHY_DA_RX_PSBN_LP_MASK,
+- upper_idx << 12 | upper_idx << 8 |
+- upper_idx << 4 | upper_idx);
+- ret = upper_ret;
+- }
+- if (ret < 0)
+- goto restore;
+-
+- /* We calibrate TX-VCM in different logic. Check upper index and then
+- * lower index. If this calibration is valid, apply lower index's
+- * result.
+- */
+- ret = upper_ret - lower_ret;
+- if (ret == 1) {
+- ret = 0;
+- /* Make sure we use upper_idx in our calibration system */
+- cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+- MTK_PHY_DA_RX_PSBN_TBT_MASK |
+- MTK_PHY_DA_RX_PSBN_HBT_MASK |
+- MTK_PHY_DA_RX_PSBN_GBE_MASK |
+- MTK_PHY_DA_RX_PSBN_LP_MASK,
+- upper_idx << 12 | upper_idx << 8 |
+- upper_idx << 4 | upper_idx);
+- phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
+- } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
+- lower_ret == 1) {
+- ret = 0;
+- cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+- MTK_PHY_DA_RX_PSBN_TBT_MASK |
+- MTK_PHY_DA_RX_PSBN_HBT_MASK |
+- MTK_PHY_DA_RX_PSBN_GBE_MASK |
+- MTK_PHY_DA_RX_PSBN_LP_MASK,
+- lower_idx << 12 | lower_idx << 8 |
+- lower_idx << 4 | lower_idx);
+- phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
+- lower_idx);
+- } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
+- lower_ret == 0) {
+- ret = 0;
+- phydev_warn(phydev,
+- "TX-VCM SW cal result at high margin 0x%x\n",
+- upper_idx);
+- } else {
+- ret = -EINVAL;
+- }
+-
+-restore:
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+- MTK_PHY_RG_ANA_CALEN);
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+- MTK_PHY_RG_TXVOS_CALEN);
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+- MTK_PHY_RG_ZCALEN_A);
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+- MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
+- MTK_PHY_RG_ZCALEN_D);
+-
+- return ret;
+-}
+-
+-static void mt798x_phy_common_finetune(struct phy_device *phydev)
+-{
+- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
+- __phy_write(phydev, 0x11, 0xc71);
+- __phy_write(phydev, 0x12, 0xc);
+- __phy_write(phydev, 0x10, 0x8fae);
+-
+- /* EnabRandUpdTrig = 1 */
+- __phy_write(phydev, 0x11, 0x2f00);
+- __phy_write(phydev, 0x12, 0xe);
+- __phy_write(phydev, 0x10, 0x8fb0);
+-
+- /* NormMseLoThresh = 85 */
+- __phy_write(phydev, 0x11, 0x55a0);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x83aa);
+-
+- /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
+- __phy_write(phydev, 0x11, 0x240);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x9680);
+-
+- /* TrFreeze = 0 (mt7988 default) */
+- __phy_write(phydev, 0x11, 0x0);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x9686);
+-
+- /* SSTrKp100 = 5 */
+- /* SSTrKf100 = 6 */
+- /* SSTrKp1000Mas = 5 */
+- /* SSTrKf1000Mas = 6 */
+- /* SSTrKp1000Slv = 5 */
+- /* SSTrKf1000Slv = 6 */
+- __phy_write(phydev, 0x11, 0xbaef);
+- __phy_write(phydev, 0x12, 0x2e);
+- __phy_write(phydev, 0x10, 0x968c);
+- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-}
+-
+-static void mt7981_phy_finetune(struct phy_device *phydev)
+-{
+- u16 val[8] = { 0x01ce, 0x01c1,
+- 0x020f, 0x0202,
+- 0x03d0, 0x03c0,
+- 0x0013, 0x0005 };
+- int i, k;
+-
+- /* 100M eye finetune:
+- * Keep middle level of TX MLT3 shapper as default.
+- * Only change TX MLT3 overshoot level here.
+- */
+- for (k = 0, i = 1; i < 12; i++) {
+- if (i % 3 == 0)
+- continue;
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
+- }
+-
+- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- /* ResetSyncOffset = 6 */
+- __phy_write(phydev, 0x11, 0x600);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x8fc0);
+-
+- /* VgaDecRate = 1 */
+- __phy_write(phydev, 0x11, 0x4c2a);
+- __phy_write(phydev, 0x12, 0x3e);
+- __phy_write(phydev, 0x10, 0x8fa4);
+-
+- /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
+- * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
+- */
+- __phy_write(phydev, 0x11, 0xd10a);
+- __phy_write(phydev, 0x12, 0x34);
+- __phy_write(phydev, 0x10, 0x8f82);
+-
+- /* VcoSlicerThreshBitsHigh */
+- __phy_write(phydev, 0x11, 0x5555);
+- __phy_write(phydev, 0x12, 0x55);
+- __phy_write(phydev, 0x10, 0x8ec0);
+- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+- MTK_PHY_TR_OPEN_LOOP_EN_MASK |
+- MTK_PHY_LPF_X_AVERAGE_MASK,
+- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
+-
+- /* rg_tr_lpf_cnt_val = 512 */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
+-
+- /* IIR2 related */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
+-
+- /* FFE peaking */
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
+- MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
+- MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
+-
+- /* Disable LDO pump */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
+- /* Adjust LDO output voltage */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
+-}
+-
+-static void mt7988_phy_finetune(struct phy_device *phydev)
+-{
+- u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
+- 0x020d, 0x0206, 0x0384, 0x03d0,
+- 0x03c6, 0x030a, 0x0011, 0x0005 };
+- int i;
+-
+- /* Set default MLT3 shaper first */
+- for (i = 0; i < 12; i++)
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
+-
+- /* TCT finetune */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
+-
+- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- /* ResetSyncOffset = 5 */
+- __phy_write(phydev, 0x11, 0x500);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x8fc0);
+-
+- /* VgaDecRate is 1 at default on mt7988 */
+-
+- /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
+- * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
+- */
+- __phy_write(phydev, 0x11, 0xb90a);
+- __phy_write(phydev, 0x12, 0x6f);
+- __phy_write(phydev, 0x10, 0x8f82);
+-
+- /* RemAckCntLimitCtrl = 1 */
+- __phy_write(phydev, 0x11, 0xfbba);
+- __phy_write(phydev, 0x12, 0xc3);
+- __phy_write(phydev, 0x10, 0x87f8);
+-
+- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+- MTK_PHY_TR_OPEN_LOOP_EN_MASK |
+- MTK_PHY_LPF_X_AVERAGE_MASK,
+- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
+-
+- /* rg_tr_lpf_cnt_val = 1023 */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
+-}
+-
+-static void mt798x_phy_eee(struct phy_device *phydev)
+-{
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
+- MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
+- MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
+- FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
+- FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
+-
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
+- MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+- 0xff));
+-
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_TESTMUX_ADC_CTRL,
+- MTK_PHY_RG_TXEN_DIG_MASK);
+-
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
+-
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
+-
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
+- MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
+- MTK_PHY_LPI_SLV_SEND_TX_EN,
+- FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
+-
+- /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
+- MTK_PHY_LPI_TXPCS_LOC_RCV);
+-
+- /* This also fixes some IoT issues, such as CH340 */
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
+- MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
+- FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
+- FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
+-
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
+- MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
+- FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
+- 0x33) |
+- MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
+- MTK_PHY_LPI_VCO_EEE_STG0_EN);
+-
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
+- MTK_PHY_EEE_WAKE_MAS_INT_DC |
+- MTK_PHY_EEE_WAKE_SLV_INT_DC);
+-
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
+- MTK_PHY_SMI_DETCNT_MAX_MASK,
+- FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
+- MTK_PHY_SMI_DET_MAX_EN);
+-
+- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
+- MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
+- MTK_PHY_TREC_UPDATE_ENAB_CLR |
+- MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
+- MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
+-
+- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- /* Regsigdet_sel_1000 = 0 */
+- __phy_write(phydev, 0x11, 0xb);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x9690);
+-
+- /* REG_EEE_st2TrKf1000 = 2 */
+- __phy_write(phydev, 0x11, 0x114f);
+- __phy_write(phydev, 0x12, 0x2);
+- __phy_write(phydev, 0x10, 0x969a);
+-
+- /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
+- __phy_write(phydev, 0x11, 0x3028);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x969e);
+-
+- /* RegEEE_slv_wake_int_timer_tar = 8 */
+- __phy_write(phydev, 0x11, 0x5010);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x96a0);
+-
+- /* RegEEE_trfreeze_timer2 = 586 */
+- __phy_write(phydev, 0x11, 0x24a);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x96a8);
+-
+- /* RegEEE100Stg1_tar = 16 */
+- __phy_write(phydev, 0x11, 0x3210);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x96b8);
+-
+- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
+- __phy_write(phydev, 0x11, 0x1463);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x96ca);
+-
+- /* DfeTailEnableVgaThresh1000 = 27 */
+- __phy_write(phydev, 0x11, 0x36);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x8f80);
+- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
+- __phy_modify(phydev, MTK_PHY_LPI_REG_14,
+- MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
+- FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
+-
+- __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
+- FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
+- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
+- MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+- 0xff));
+-}
+-
+-static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
+- u8 start_pair, u8 end_pair)
+-{
+- u8 pair_n;
+- int ret;
+-
+- for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
+- /* TX_OFFSET & TX_AMP have no SW calibration. */
+- switch (cal_item) {
+- case TX_VCM:
+- ret = tx_vcm_cal_sw(phydev, pair_n);
+- break;
+- default:
+- return -EINVAL;
+- }
+- if (ret)
+- return ret;
+- }
+- return 0;
+-}
+-
+-static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
+- u8 start_pair, u8 end_pair, u32 *buf)
+-{
+- u8 pair_n;
+- int ret;
+-
+- for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
+- /* TX_VCM has no efuse calibration. */
+- switch (cal_item) {
+- case REXT:
+- ret = rext_cal_efuse(phydev, buf);
+- break;
+- case TX_OFFSET:
+- ret = tx_offset_cal_efuse(phydev, buf);
+- break;
+- case TX_AMP:
+- ret = tx_amp_cal_efuse(phydev, buf);
+- break;
+- case TX_R50:
+- ret = tx_r50_cal_efuse(phydev, buf, pair_n);
+- break;
+- default:
+- return -EINVAL;
+- }
+- if (ret)
+- return ret;
+- }
+-
+- return 0;
+-}
+-
+-static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
+- enum CAL_MODE cal_mode, u8 start_pair,
+- u8 end_pair, u32 *buf)
+-{
+- int ret;
+-
+- switch (cal_mode) {
+- case EFUSE_M:
+- ret = cal_efuse(phydev, cal_item, start_pair,
+- end_pair, buf);
+- break;
+- case SW_M:
+- ret = cal_sw(phydev, cal_item, start_pair, end_pair);
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- if (ret) {
+- phydev_err(phydev, "cal %d failed\n", cal_item);
+- return -EIO;
+- }
+-
+- return 0;
+-}
+-
+-static int mt798x_phy_calibration(struct phy_device *phydev)
+-{
+- struct nvmem_cell *cell;
+- int ret = 0;
+- size_t len;
+- u32 *buf;
+-
+- cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
+- if (IS_ERR(cell)) {
+- if (PTR_ERR(cell) == -EPROBE_DEFER)
+- return PTR_ERR(cell);
+- return 0;
+- }
+-
+- buf = (u32 *)nvmem_cell_read(cell, &len);
+- if (IS_ERR(buf))
+- return PTR_ERR(buf);
+- nvmem_cell_put(cell);
+-
+- if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
+- phydev_err(phydev, "invalid efuse data\n");
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
+- if (ret)
+- goto out;
+- ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
+- if (ret)
+- goto out;
+- ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
+- if (ret)
+- goto out;
+- ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
+- if (ret)
+- goto out;
+- ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
+- if (ret)
+- goto out;
+-
+-out:
+- kfree(buf);
+- return ret;
+-}
+-
+-static int mt798x_phy_config_init(struct phy_device *phydev)
+-{
+- switch (phydev->drv->phy_id) {
+- case MTK_GPHY_ID_MT7981:
+- mt7981_phy_finetune(phydev);
+- break;
+- case MTK_GPHY_ID_MT7988:
+- mt7988_phy_finetune(phydev);
+- break;
+- }
+-
+- mt798x_phy_common_finetune(phydev);
+- mt798x_phy_eee(phydev);
+-
+- return mt798x_phy_calibration(phydev);
+-}
+-
+-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+- bool on)
+-{
+- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+- struct mtk_socphy_priv *priv = phydev->priv;
+- bool changed;
+-
+- if (on)
+- changed = !test_and_set_bit(bit_on, &priv->led_state);
+- else
+- changed = !!test_and_clear_bit(bit_on, &priv->led_state);
+-
+- changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
+- (index ? 16 : 0), &priv->led_state);
+- if (changed)
+- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_ON_CTRL :
+- MTK_PHY_LED0_ON_CTRL,
+- MTK_PHY_LED_ON_MASK,
+- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+- else
+- return 0;
+-}
+-
+-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+- bool blinking)
+-{
+- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+- (index ? 16 : 0);
+- struct mtk_socphy_priv *priv = phydev->priv;
+- bool changed;
+-
+- if (blinking)
+- changed = !test_and_set_bit(bit_blink, &priv->led_state);
+- else
+- changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
+-
+- changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
+- (index ? 16 : 0), &priv->led_state);
+- if (changed)
+- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_BLINK_CTRL :
+- MTK_PHY_LED0_BLINK_CTRL,
+- blinking ?
+- MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+- else
+- return 0;
+-}
+-
+-static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
+- unsigned long *delay_on,
+- unsigned long *delay_off)
+-{
+- bool blinking = false;
+- int err = 0;
+-
+- if (index > 1)
+- return -EINVAL;
+-
+- if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+- blinking = true;
+- *delay_on = 50;
+- *delay_off = 50;
+- }
+-
+- err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
+- if (err)
+- return err;
+-
+- return mt798x_phy_hw_led_on_set(phydev, index, false);
+-}
+-
+-static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
+- u8 index, enum led_brightness value)
+-{
+- int err;
+-
+- err = mt798x_phy_hw_led_blink_set(phydev, index, false);
+- if (err)
+- return err;
+-
+- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
+-}
+-
+-static const unsigned long supported_triggers =
+- BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+- BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+- BIT(TRIGGER_NETDEV_LINK) |
+- BIT(TRIGGER_NETDEV_LINK_10) |
+- BIT(TRIGGER_NETDEV_LINK_100) |
+- BIT(TRIGGER_NETDEV_LINK_1000) |
+- BIT(TRIGGER_NETDEV_RX) |
+- BIT(TRIGGER_NETDEV_TX);
+-
+-static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+- unsigned long rules)
+-{
+- if (index > 1)
+- return -EINVAL;
+-
+- /* All combinations of the supported triggers are allowed */
+- if (rules & ~supported_triggers)
+- return -EOPNOTSUPP;
+-
+- return 0;
+-};
+-
+-static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+- unsigned long *rules)
+-{
+- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+- (index ? 16 : 0);
+- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+- struct mtk_socphy_priv *priv = phydev->priv;
+- int on, blink;
+-
+- if (index > 1)
+- return -EINVAL;
+-
+- on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+- index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
+-
+- if (on < 0)
+- return -EIO;
+-
+- blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+- index ? MTK_PHY_LED1_BLINK_CTRL :
+- MTK_PHY_LED0_BLINK_CTRL);
+- if (blink < 0)
+- return -EIO;
+-
+- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
+- MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
+- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
+- set_bit(bit_netdev, &priv->led_state);
+- else
+- clear_bit(bit_netdev, &priv->led_state);
+-
+- if (on & MTK_PHY_LED_ON_FORCE_ON)
+- set_bit(bit_on, &priv->led_state);
+- else
+- clear_bit(bit_on, &priv->led_state);
+-
+- if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
+- set_bit(bit_blink, &priv->led_state);
+- else
+- clear_bit(bit_blink, &priv->led_state);
+-
+- if (!rules)
+- return 0;
+-
+- if (on & MTK_PHY_LED_ON_LINK)
+- *rules |= BIT(TRIGGER_NETDEV_LINK);
+-
+- if (on & MTK_PHY_LED_ON_LINK10)
+- *rules |= BIT(TRIGGER_NETDEV_LINK_10);
+-
+- if (on & MTK_PHY_LED_ON_LINK100)
+- *rules |= BIT(TRIGGER_NETDEV_LINK_100);
+-
+- if (on & MTK_PHY_LED_ON_LINK1000)
+- *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+-
+- if (on & MTK_PHY_LED_ON_FDX)
+- *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+-
+- if (on & MTK_PHY_LED_ON_HDX)
+- *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
+-
+- if (blink & MTK_PHY_LED_BLINK_RX)
+- *rules |= BIT(TRIGGER_NETDEV_RX);
+-
+- if (blink & MTK_PHY_LED_BLINK_TX)
+- *rules |= BIT(TRIGGER_NETDEV_TX);
+-
+- return 0;
+-};
+-
+-static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
+- unsigned long rules)
+-{
+- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+- struct mtk_socphy_priv *priv = phydev->priv;
+- u16 on = 0, blink = 0;
+- int ret;
+-
+- if (index > 1)
+- return -EINVAL;
+-
+- if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+- on |= MTK_PHY_LED_ON_FDX;
+-
+- if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
+- on |= MTK_PHY_LED_ON_HDX;
+-
+- if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
+- on |= MTK_PHY_LED_ON_LINK10;
+-
+- if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+- on |= MTK_PHY_LED_ON_LINK100;
+-
+- if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+- on |= MTK_PHY_LED_ON_LINK1000;
+-
+- if (rules & BIT(TRIGGER_NETDEV_RX)) {
+- blink |= (on & MTK_PHY_LED_ON_LINK) ?
+- (((on & MTK_PHY_LED_ON_LINK10) ?
+- MTK_PHY_LED_BLINK_10RX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK100) ?
+- MTK_PHY_LED_BLINK_100RX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK1000) ?
+- MTK_PHY_LED_BLINK_1000RX : 0)) :
+- MTK_PHY_LED_BLINK_RX;
+- }
+-
+- if (rules & BIT(TRIGGER_NETDEV_TX)) {
+- blink |= (on & MTK_PHY_LED_ON_LINK) ?
+- (((on & MTK_PHY_LED_ON_LINK10) ?
+- MTK_PHY_LED_BLINK_10TX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK100) ?
+- MTK_PHY_LED_BLINK_100TX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK1000) ?
+- MTK_PHY_LED_BLINK_1000TX : 0)) :
+- MTK_PHY_LED_BLINK_TX;
+- }
+-
+- if (blink || on)
+- set_bit(bit_netdev, &priv->led_state);
+- else
+- clear_bit(bit_netdev, &priv->led_state);
+-
+- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_ON_CTRL :
+- MTK_PHY_LED0_ON_CTRL,
+- MTK_PHY_LED_ON_FDX |
+- MTK_PHY_LED_ON_HDX |
+- MTK_PHY_LED_ON_LINK,
+- on);
+-
+- if (ret)
+- return ret;
+-
+- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_BLINK_CTRL :
+- MTK_PHY_LED0_BLINK_CTRL, blink);
+-};
+-
+-static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
+-{
+- struct mtk_socphy_shared *priv = phydev->shared->priv;
+- u32 polarities;
+-
+- if (led_num == 0)
+- polarities = ~(priv->boottrap);
+- else
+- polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
+-
+- if (polarities & BIT(phydev->mdio.addr))
+- return true;
+-
+- return false;
+-}
+-
+-static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
+-{
+- struct pinctrl *pinctrl;
+- int index;
+-
+- /* Setup LED polarity according to bootstrap use of LED pins */
+- for (index = 0; index < 2; ++index)
+- phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+- MTK_PHY_LED_ON_POLARITY,
+- mt7988_phy_led_get_polarity(phydev, index) ?
+- MTK_PHY_LED_ON_POLARITY : 0);
+-
+- /* Only now setup pinctrl to avoid bogus blinking */
+- pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
+- if (IS_ERR(pinctrl))
+- dev_err(&phydev->mdio.bus->dev,
+- "Failed to setup PHY LED pinctrl\n");
+-
+- return 0;
+-}
+-
+-static int mt7988_phy_probe_shared(struct phy_device *phydev)
+-{
+- struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
+- struct mtk_socphy_shared *shared = phydev->shared->priv;
+- struct regmap *regmap;
+- u32 reg;
+- int ret;
+-
+- /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
+- * LED_C and LED_D respectively. At the same time those pins are used to
+- * bootstrap configuration of the reference clock source (LED_A),
+- * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
+- * In practice this is done using a LED and a resistor pulling the pin
+- * either to GND or to VIO.
+- * The detected value at boot time is accessible at run-time using the
+- * TPBANK0 register located in the gpio base of the pinctrl, in order
+- * to read it here it needs to be referenced by a phandle called
+- * 'mediatek,pio' in the MDIO bus hosting the PHY.
+- * The 4 bits in TPBANK0 are kept as package shared data and are used to
+- * set LED polarity for each of the LED0.
+- */
+- regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
+- if (IS_ERR(regmap))
+- return PTR_ERR(regmap);
+-
+- ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®);
+- if (ret)
+- return ret;
+-
+- shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
+-
+- return 0;
+-}
+-
+-static void mt798x_phy_leds_state_init(struct phy_device *phydev)
+-{
+- int i;
+-
+- for (i = 0; i < 2; ++i)
+- mt798x_phy_led_hw_control_get(phydev, i, NULL);
+-}
+-
+-static int mt7988_phy_probe(struct phy_device *phydev)
+-{
+- struct mtk_socphy_shared *shared;
+- struct mtk_socphy_priv *priv;
+- int err;
+-
+- if (phydev->mdio.addr > 3)
+- return -EINVAL;
+-
+- err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
+- sizeof(struct mtk_socphy_shared));
+- if (err)
+- return err;
+-
+- if (phy_package_probe_once(phydev)) {
+- err = mt7988_phy_probe_shared(phydev);
+- if (err)
+- return err;
+- }
+-
+- shared = phydev->shared->priv;
+- priv = &shared->priv[phydev->mdio.addr];
+-
+- phydev->priv = priv;
+-
+- mt798x_phy_leds_state_init(phydev);
+-
+- err = mt7988_phy_fix_leds_polarities(phydev);
+- if (err)
+- return err;
+-
+- /* Disable TX power saving at probing to:
+- * 1. Meet common mode compliance test criteria
+- * 2. Make sure that TX-VCM calibration works fine
+- */
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
+- MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
+-
+- return mt798x_phy_calibration(phydev);
+-}
+-
+-static int mt7981_phy_probe(struct phy_device *phydev)
+-{
+- struct mtk_socphy_priv *priv;
+-
+- priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
+- GFP_KERNEL);
+- if (!priv)
+- return -ENOMEM;
+-
+- phydev->priv = priv;
+-
+- mt798x_phy_leds_state_init(phydev);
+-
+- return mt798x_phy_calibration(phydev);
+-}
+-
+-static struct phy_driver mtk_socphy_driver[] = {
+- {
+- PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
+- .name = "MediaTek MT7981 PHY",
+- .config_init = mt798x_phy_config_init,
+- .config_intr = genphy_no_config_intr,
+- .handle_interrupt = genphy_handle_interrupt_no_ack,
+- .probe = mt7981_phy_probe,
+- .suspend = genphy_suspend,
+- .resume = genphy_resume,
+- .read_page = mtk_socphy_read_page,
+- .write_page = mtk_socphy_write_page,
+- .led_blink_set = mt798x_phy_led_blink_set,
+- .led_brightness_set = mt798x_phy_led_brightness_set,
+- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+- .led_hw_control_set = mt798x_phy_led_hw_control_set,
+- .led_hw_control_get = mt798x_phy_led_hw_control_get,
+- },
+- {
+- PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
+- .name = "MediaTek MT7988 PHY",
+- .config_init = mt798x_phy_config_init,
+- .config_intr = genphy_no_config_intr,
+- .handle_interrupt = genphy_handle_interrupt_no_ack,
+- .probe = mt7988_phy_probe,
+- .suspend = genphy_suspend,
+- .resume = genphy_resume,
+- .read_page = mtk_socphy_read_page,
+- .write_page = mtk_socphy_write_page,
+- .led_blink_set = mt798x_phy_led_blink_set,
+- .led_brightness_set = mt798x_phy_led_brightness_set,
+- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+- .led_hw_control_set = mt798x_phy_led_hw_control_set,
+- .led_hw_control_get = mt798x_phy_led_hw_control_get,
+- },
+-};
+-
+-module_phy_driver(mtk_socphy_driver);
+-
+-static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
+- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
+- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
+- { }
+-};
+-
+-MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver");
+-MODULE_LICENSE("GPL");
+-
+-MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
+--- a/drivers/net/phy/mediatek-ge.c
++++ /dev/null
+@@ -1,111 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0+
+-#include <linux/bitfield.h>
+-#include <linux/module.h>
+-#include <linux/phy.h>
+-
+-#define MTK_EXT_PAGE_ACCESS 0x1f
+-#define MTK_PHY_PAGE_STANDARD 0x0000
+-#define MTK_PHY_PAGE_EXTENDED 0x0001
+-#define MTK_PHY_PAGE_EXTENDED_2 0x0002
+-#define MTK_PHY_PAGE_EXTENDED_3 0x0003
+-#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+-
+-static int mtk_gephy_read_page(struct phy_device *phydev)
+-{
+- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_gephy_write_page(struct phy_device *phydev, int page)
+-{
+- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+-static void mtk_gephy_config_init(struct phy_device *phydev)
+-{
+- /* Enable HW auto downshift */
+- phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
+-
+- /* Increase SlvDPSready time */
+- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- __phy_write(phydev, 0x10, 0xafae);
+- __phy_write(phydev, 0x12, 0x2f);
+- __phy_write(phydev, 0x10, 0x8fae);
+- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+- /* Adjust 100_mse_threshold */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
+-
+- /* Disable mcc */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
+-}
+-
+-static int mt7530_phy_config_init(struct phy_device *phydev)
+-{
+- mtk_gephy_config_init(phydev);
+-
+- /* Increase post_update_timer */
+- phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
+-
+- return 0;
+-}
+-
+-static int mt7531_phy_config_init(struct phy_device *phydev)
+-{
+- mtk_gephy_config_init(phydev);
+-
+- /* PHY link down power saving enable */
+- phy_set_bits(phydev, 0x17, BIT(4));
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
+-
+- /* Set TX Pair delay selection */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
+-
+- return 0;
+-}
+-
+-static struct phy_driver mtk_gephy_driver[] = {
+- {
+- PHY_ID_MATCH_EXACT(0x03a29412),
+- .name = "MediaTek MT7530 PHY",
+- .config_init = mt7530_phy_config_init,
+- /* Interrupts are handled by the switch, not the PHY
+- * itself.
+- */
+- .config_intr = genphy_no_config_intr,
+- .handle_interrupt = genphy_handle_interrupt_no_ack,
+- .suspend = genphy_suspend,
+- .resume = genphy_resume,
+- .read_page = mtk_gephy_read_page,
+- .write_page = mtk_gephy_write_page,
+- },
+- {
+- PHY_ID_MATCH_EXACT(0x03a29441),
+- .name = "MediaTek MT7531 PHY",
+- .config_init = mt7531_phy_config_init,
+- /* Interrupts are handled by the switch, not the PHY
+- * itself.
+- */
+- .config_intr = genphy_no_config_intr,
+- .handle_interrupt = genphy_handle_interrupt_no_ack,
+- .suspend = genphy_suspend,
+- .resume = genphy_resume,
+- .read_page = mtk_gephy_read_page,
+- .write_page = mtk_gephy_write_page,
+- },
+-};
+-
+-module_phy_driver(mtk_gephy_driver);
+-
+-static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
+- { PHY_ID_MATCH_EXACT(0x03a29441) },
+- { PHY_ID_MATCH_EXACT(0x03a29412) },
+- { }
+-};
+-
+-MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
+-MODULE_LICENSE("GPL");
+-
+-MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -0,0 +1,1610 @@
++// SPDX-License-Identifier: GPL-2.0+
++#include <linux/bitfield.h>
++#include <linux/bitmap.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/phy.h>
++#include <linux/regmap.h>
++
++#define MTK_GPHY_ID_MT7981 0x03a29461
++#define MTK_GPHY_ID_MT7988 0x03a29481
++
++#define MTK_EXT_PAGE_ACCESS 0x1f
++#define MTK_PHY_PAGE_STANDARD 0x0000
++#define MTK_PHY_PAGE_EXTENDED_3 0x0003
++
++#define MTK_PHY_LPI_REG_14 0x14
++#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0)
++
++#define MTK_PHY_LPI_REG_1c 0x1c
++#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
++
++#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
++#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
++
++#define ANALOG_INTERNAL_OPERATION_MAX_US 20
++#define TXRESERVE_MIN 0
++#define TXRESERVE_MAX 7
++
++#define MTK_PHY_ANARG_RG 0x10
++#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8)
++
++/* Registers on MDIO_MMD_VEND1 */
++#define MTK_PHY_TXVLD_DA_RG 0x12
++#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10)
++#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16
++#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10)
++#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17
++#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18
++#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19
++#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20
++#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21
++#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22
++#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0)
++
++#define MTK_PHY_RXADC_CTRL_RG7 0xc6
++#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
++
++#define MTK_PHY_RXADC_CTRL_RG9 0xc8
++#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12)
++#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8)
++#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4)
++#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0)
++
++#define MTK_PHY_LDO_OUTPUT_V 0xd7
++
++#define MTK_PHY_RG_ANA_CAL_RG0 0xdb
++#define MTK_PHY_RG_CAL_CKINV BIT(12)
++#define MTK_PHY_RG_ANA_CALEN BIT(8)
++#define MTK_PHY_RG_ZCALEN_A BIT(0)
++
++#define MTK_PHY_RG_ANA_CAL_RG1 0xdc
++#define MTK_PHY_RG_ZCALEN_B BIT(12)
++#define MTK_PHY_RG_ZCALEN_C BIT(8)
++#define MTK_PHY_RG_ZCALEN_D BIT(4)
++#define MTK_PHY_RG_TXVOS_CALEN BIT(0)
++
++#define MTK_PHY_RG_ANA_CAL_RG5 0xe0
++#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8)
++
++#define MTK_PHY_RG_TX_FILTER 0xfe
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120
++#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8)
++#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0)
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122
++#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0)
++
++#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144
++#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5)
++
++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172
++#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8)
++#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0)
++
++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173
++#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8)
++#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
++
++#define MTK_PHY_RG_AD_CAL_COMP 0x17a
++#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8)
++
++#define MTK_PHY_RG_AD_CAL_CLK 0x17b
++#define MTK_PHY_DA_CAL_CLK BIT(0)
++
++#define MTK_PHY_RG_AD_CALIN 0x17c
++#define MTK_PHY_DA_CALIN_FLAG BIT(0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d
++#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e
++#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f
++#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180
++#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181
++#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182
++#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183
++#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184
++#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DEV1E_REG19b 0x19b
++#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8)
++
++#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a
++#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b
++#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c
++#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d
++#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e
++#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f
++#define MTK_PHY_RG_LP_IIR2_K4_L 0x230
++#define MTK_PHY_RG_LP_IIR2_K4_U 0x231
++#define MTK_PHY_RG_LP_IIR2_K5_L 0x232
++#define MTK_PHY_RG_LP_IIR2_K5_U 0x233
++
++#define MTK_PHY_RG_DEV1E_REG234 0x234
++#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0)
++#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4)
++#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12)
++
++#define MTK_PHY_RG_LPF_CNT_VAL 0x235
++
++#define MTK_PHY_RG_DEV1E_REG238 0x238
++#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0)
++#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12)
++
++#define MTK_PHY_RG_DEV1E_REG239 0x239
++#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0)
++#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12)
++
++#define MTK_PHY_RG_DEV1E_REG27C 0x27c
++#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8)
++#define MTK_PHY_RG_DEV1E_REG27D 0x27d
++#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0)
++
++#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7
++#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0)
++#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8)
++
++#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1
++#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0)
++#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8)
++#define MTK_PHY_LPI_TR_READY BIT(9)
++#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10)
++
++#define MTK_PHY_RG_DEV1E_REG323 0x323
++#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0)
++#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4)
++
++#define MTK_PHY_RG_DEV1E_REG324 0x324
++#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0)
++#define MTK_PHY_SMI_DET_MAX_EN BIT(8)
++
++#define MTK_PHY_RG_DEV1E_REG326 0x326
++#define MTK_PHY_LPI_MODE_SD_ON BIT(0)
++#define MTK_PHY_RESET_RANDUPD_CNT BIT(1)
++#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2)
++#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4)
++#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5)
++
++#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502
++#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503
++
++#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d
++#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e
++#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f
++#define MTK_PHY_DA_TX_R50_PAIR_D 0x540
++
++/* Registers on MDIO_MMD_VEND2 */
++#define MTK_PHY_LED0_ON_CTRL 0x24
++#define MTK_PHY_LED1_ON_CTRL 0x26
++#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
++#define MTK_PHY_LED_ON_LINK1000 BIT(0)
++#define MTK_PHY_LED_ON_LINK100 BIT(1)
++#define MTK_PHY_LED_ON_LINK10 BIT(2)
++#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
++ MTK_PHY_LED_ON_LINK100 |\
++ MTK_PHY_LED_ON_LINK1000)
++#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
++#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
++#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
++#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
++#define MTK_PHY_LED_ON_POLARITY BIT(14)
++#define MTK_PHY_LED_ON_ENABLE BIT(15)
++
++#define MTK_PHY_LED0_BLINK_CTRL 0x25
++#define MTK_PHY_LED1_BLINK_CTRL 0x27
++#define MTK_PHY_LED_BLINK_1000TX BIT(0)
++#define MTK_PHY_LED_BLINK_1000RX BIT(1)
++#define MTK_PHY_LED_BLINK_100TX BIT(2)
++#define MTK_PHY_LED_BLINK_100RX BIT(3)
++#define MTK_PHY_LED_BLINK_10TX BIT(4)
++#define MTK_PHY_LED_BLINK_10RX BIT(5)
++#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
++ MTK_PHY_LED_BLINK_100RX |\
++ MTK_PHY_LED_BLINK_1000RX)
++#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
++ MTK_PHY_LED_BLINK_100TX |\
++ MTK_PHY_LED_BLINK_1000TX)
++#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
++#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
++#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
++#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
++
++#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
++
++#define MTK_PHY_RG_BG_RASEL 0x115
++#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0)
++
++/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
++#define RG_GPIO_MISC_TPBANK0 0x6f0
++#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8)
++
++/* These macro privides efuse parsing for internal phy. */
++#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0))
++
++#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0))
++
++#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0))
++
++#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0))
++#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0))
++
++enum {
++ NO_PAIR,
++ PAIR_A,
++ PAIR_B,
++ PAIR_C,
++ PAIR_D,
++};
++
++enum calibration_mode {
++ EFUSE_K,
++ SW_K
++};
++
++enum CAL_ITEM {
++ REXT,
++ TX_OFFSET,
++ TX_AMP,
++ TX_R50,
++ TX_VCM
++};
++
++enum CAL_MODE {
++ EFUSE_M,
++ SW_M
++};
++
++#define MTK_PHY_LED_STATE_FORCE_ON 0
++#define MTK_PHY_LED_STATE_FORCE_BLINK 1
++#define MTK_PHY_LED_STATE_NETDEV 2
++
++struct mtk_socphy_priv {
++ unsigned long led_state;
++};
++
++struct mtk_socphy_shared {
++ u32 boottrap;
++ struct mtk_socphy_priv priv[4];
++};
++
++static int mtk_socphy_read_page(struct phy_device *phydev)
++{
++ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++
++static int mtk_socphy_write_page(struct phy_device *phydev, int page)
++{
++ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++
++/* One calibration cycle consists of:
++ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
++ * until AD_CAL_COMP is ready to output calibration result.
++ * 2.Wait until DA_CAL_CLK is available.
++ * 3.Fetch AD_CAL_COMP_OUT.
++ */
++static int cal_cycle(struct phy_device *phydev, int devad,
++ u32 regnum, u16 mask, u16 cal_val)
++{
++ int reg_val;
++ int ret;
++
++ phy_modify_mmd(phydev, devad, regnum,
++ mask, cal_val);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
++ MTK_PHY_DA_CALIN_FLAG);
++
++ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_AD_CAL_CLK, reg_val,
++ reg_val & MTK_PHY_DA_CAL_CLK, 500,
++ ANALOG_INTERNAL_OPERATION_MAX_US,
++ false);
++ if (ret) {
++ phydev_err(phydev, "Calibration cycle timeout\n");
++ return ret;
++ }
++
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
++ MTK_PHY_DA_CALIN_FLAG);
++ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
++ if (ret < 0)
++ return ret;
++ ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
++ phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
++
++ return ret;
++}
++
++static int rext_fill_result(struct phy_device *phydev, u16 *buf)
++{
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
++ MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
++ MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
++
++ return 0;
++}
++
++static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++ u16 rext_cal_val[2];
++
++ rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
++ rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
++ rext_fill_result(phydev, rext_cal_val);
++
++ return 0;
++}
++
++static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
++{
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
++ MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
++ MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
++ MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
++ MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
++
++ return 0;
++}
++
++static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++ u16 tx_offset_cal_val[4];
++
++ tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
++ tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
++ tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
++ tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
++
++ tx_offset_fill_result(phydev, tx_offset_cal_val);
++
++ return 0;
++}
++
++static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
++{
++ const int vals_9481[16] = { 10, 6, 6, 10,
++ 10, 6, 6, 10,
++ 10, 6, 6, 10,
++ 10, 6, 6, 10 };
++ const int vals_9461[16] = { 7, 1, 4, 7,
++ 7, 1, 4, 7,
++ 7, 1, 4, 7,
++ 7, 1, 4, 7 };
++ int bias[16] = {};
++ int i;
++
++ switch (phydev->drv->phy_id) {
++ case MTK_GPHY_ID_MT7981:
++ /* We add some calibration to efuse values
++ * due to board level influence.
++ * GBE: +7, TBT: +1, HBT: +4, TST: +7
++ */
++ memcpy(bias, (const void *)vals_9461, sizeof(bias));
++ break;
++ case MTK_GPHY_ID_MT7988:
++ memcpy(bias, (const void *)vals_9481, sizeof(bias));
++ break;
++ }
++
++ /* Prevent overflow */
++ for (i = 0; i < 12; i++) {
++ if (buf[i >> 2] + bias[i] > 63) {
++ buf[i >> 2] = 63;
++ bias[i] = 0;
++ }
++ }
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
++ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
++ buf[0] + bias[0]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
++ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
++ buf[0] + bias[1]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
++ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
++ buf[0] + bias[2]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
++ MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
++ buf[0] + bias[3]));
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
++ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
++ buf[1] + bias[4]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
++ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
++ buf[1] + bias[5]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
++ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
++ buf[1] + bias[6]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
++ MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
++ buf[1] + bias[7]));
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
++ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
++ buf[2] + bias[8]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
++ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
++ buf[2] + bias[9]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
++ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
++ buf[2] + bias[10]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
++ MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
++ buf[2] + bias[11]));
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
++ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
++ buf[3] + bias[12]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
++ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
++ buf[3] + bias[13]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
++ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
++ buf[3] + bias[14]));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
++ MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
++ buf[3] + bias[15]));
++
++ return 0;
++}
++
++static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++ u16 tx_amp_cal_val[4];
++
++ tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
++ tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
++ tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
++ tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
++ tx_amp_fill_result(phydev, tx_amp_cal_val);
++
++ return 0;
++}
++
++static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
++ u8 txg_calen_x)
++{
++ int bias = 0;
++ u16 reg, val;
++
++ if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
++ bias = -1;
++
++ val = clamp_val(bias + tx_r50_cal_val, 0, 63);
++
++ switch (txg_calen_x) {
++ case PAIR_A:
++ reg = MTK_PHY_DA_TX_R50_PAIR_A;
++ break;
++ case PAIR_B:
++ reg = MTK_PHY_DA_TX_R50_PAIR_B;
++ break;
++ case PAIR_C:
++ reg = MTK_PHY_DA_TX_R50_PAIR_C;
++ break;
++ case PAIR_D:
++ reg = MTK_PHY_DA_TX_R50_PAIR_D;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
++
++ return 0;
++}
++
++static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
++ u8 txg_calen_x)
++{
++ u16 tx_r50_cal_val;
++
++ switch (txg_calen_x) {
++ case PAIR_A:
++ tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
++ break;
++ case PAIR_B:
++ tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
++ break;
++ case PAIR_C:
++ tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
++ break;
++ case PAIR_D:
++ tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
++ break;
++ default:
++ return -EINVAL;
++ }
++ tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
++
++ return 0;
++}
++
++static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
++{
++ u8 lower_idx, upper_idx, txreserve_val;
++ u8 lower_ret, upper_ret;
++ int ret;
++
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_ANA_CALEN);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_CAL_CKINV);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_TXVOS_CALEN);
++
++ switch (rg_txreserve_x) {
++ case PAIR_A:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN0_A,
++ MTK_PHY_DASN_DAC_IN0_A_MASK);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN1_A,
++ MTK_PHY_DASN_DAC_IN1_A_MASK);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_ZCALEN_A);
++ break;
++ case PAIR_B:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN0_B,
++ MTK_PHY_DASN_DAC_IN0_B_MASK);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN1_B,
++ MTK_PHY_DASN_DAC_IN1_B_MASK);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_ZCALEN_B);
++ break;
++ case PAIR_C:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN0_C,
++ MTK_PHY_DASN_DAC_IN0_C_MASK);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN1_C,
++ MTK_PHY_DASN_DAC_IN1_C_MASK);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_ZCALEN_C);
++ break;
++ case PAIR_D:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN0_D,
++ MTK_PHY_DASN_DAC_IN0_D_MASK);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN1_D,
++ MTK_PHY_DASN_DAC_IN1_D_MASK);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_ZCALEN_D);
++ break;
++ default:
++ ret = -EINVAL;
++ goto restore;
++ }
++
++ lower_idx = TXRESERVE_MIN;
++ upper_idx = TXRESERVE_MAX;
++
++ phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
++ while ((upper_idx - lower_idx) > 1) {
++ txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
++ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ txreserve_val << 12 | txreserve_val << 8 |
++ txreserve_val << 4 | txreserve_val);
++ if (ret == 1) {
++ upper_idx = txreserve_val;
++ upper_ret = ret;
++ } else if (ret == 0) {
++ lower_idx = txreserve_val;
++ lower_ret = ret;
++ } else {
++ goto restore;
++ }
++ }
++
++ if (lower_idx == TXRESERVE_MIN) {
++ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ lower_idx << 12 | lower_idx << 8 |
++ lower_idx << 4 | lower_idx);
++ ret = lower_ret;
++ } else if (upper_idx == TXRESERVE_MAX) {
++ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ upper_idx << 12 | upper_idx << 8 |
++ upper_idx << 4 | upper_idx);
++ ret = upper_ret;
++ }
++ if (ret < 0)
++ goto restore;
++
++ /* We calibrate TX-VCM in different logic. Check upper index and then
++ * lower index. If this calibration is valid, apply lower index's
++ * result.
++ */
++ ret = upper_ret - lower_ret;
++ if (ret == 1) {
++ ret = 0;
++ /* Make sure we use upper_idx in our calibration system */
++ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ upper_idx << 12 | upper_idx << 8 |
++ upper_idx << 4 | upper_idx);
++ phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
++ } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
++ lower_ret == 1) {
++ ret = 0;
++ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ lower_idx << 12 | lower_idx << 8 |
++ lower_idx << 4 | lower_idx);
++ phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
++ lower_idx);
++ } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
++ lower_ret == 0) {
++ ret = 0;
++ phydev_warn(phydev,
++ "TX-VCM SW cal result at high margin 0x%x\n",
++ upper_idx);
++ } else {
++ ret = -EINVAL;
++ }
++
++restore:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_ANA_CALEN);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_TXVOS_CALEN);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_ZCALEN_A);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
++ MTK_PHY_RG_ZCALEN_D);
++
++ return ret;
++}
++
++static void mt798x_phy_common_finetune(struct phy_device *phydev)
++{
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
++ __phy_write(phydev, 0x11, 0xc71);
++ __phy_write(phydev, 0x12, 0xc);
++ __phy_write(phydev, 0x10, 0x8fae);
++
++ /* EnabRandUpdTrig = 1 */
++ __phy_write(phydev, 0x11, 0x2f00);
++ __phy_write(phydev, 0x12, 0xe);
++ __phy_write(phydev, 0x10, 0x8fb0);
++
++ /* NormMseLoThresh = 85 */
++ __phy_write(phydev, 0x11, 0x55a0);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x83aa);
++
++ /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
++ __phy_write(phydev, 0x11, 0x240);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x9680);
++
++ /* TrFreeze = 0 (mt7988 default) */
++ __phy_write(phydev, 0x11, 0x0);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x9686);
++
++ /* SSTrKp100 = 5 */
++ /* SSTrKf100 = 6 */
++ /* SSTrKp1000Mas = 5 */
++ /* SSTrKf1000Mas = 6 */
++ /* SSTrKp1000Slv = 5 */
++ /* SSTrKf1000Slv = 6 */
++ __phy_write(phydev, 0x11, 0xbaef);
++ __phy_write(phydev, 0x12, 0x2e);
++ __phy_write(phydev, 0x10, 0x968c);
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++}
++
++static void mt7981_phy_finetune(struct phy_device *phydev)
++{
++ u16 val[8] = { 0x01ce, 0x01c1,
++ 0x020f, 0x0202,
++ 0x03d0, 0x03c0,
++ 0x0013, 0x0005 };
++ int i, k;
++
++ /* 100M eye finetune:
++ * Keep middle level of TX MLT3 shapper as default.
++ * Only change TX MLT3 overshoot level here.
++ */
++ for (k = 0, i = 1; i < 12; i++) {
++ if (i % 3 == 0)
++ continue;
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
++ }
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ /* ResetSyncOffset = 6 */
++ __phy_write(phydev, 0x11, 0x600);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x8fc0);
++
++ /* VgaDecRate = 1 */
++ __phy_write(phydev, 0x11, 0x4c2a);
++ __phy_write(phydev, 0x12, 0x3e);
++ __phy_write(phydev, 0x10, 0x8fa4);
++
++ /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
++ * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
++ */
++ __phy_write(phydev, 0x11, 0xd10a);
++ __phy_write(phydev, 0x12, 0x34);
++ __phy_write(phydev, 0x10, 0x8f82);
++
++ /* VcoSlicerThreshBitsHigh */
++ __phy_write(phydev, 0x11, 0x5555);
++ __phy_write(phydev, 0x12, 0x55);
++ __phy_write(phydev, 0x10, 0x8ec0);
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
++ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
++ MTK_PHY_LPF_X_AVERAGE_MASK,
++ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
++
++ /* rg_tr_lpf_cnt_val = 512 */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
++
++ /* IIR2 related */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
++
++ /* FFE peaking */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
++ MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
++ MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
++
++ /* Disable LDO pump */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
++ /* Adjust LDO output voltage */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
++}
++
++static void mt7988_phy_finetune(struct phy_device *phydev)
++{
++ u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
++ 0x020d, 0x0206, 0x0384, 0x03d0,
++ 0x03c6, 0x030a, 0x0011, 0x0005 };
++ int i;
++
++ /* Set default MLT3 shaper first */
++ for (i = 0; i < 12; i++)
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
++
++ /* TCT finetune */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ /* ResetSyncOffset = 5 */
++ __phy_write(phydev, 0x11, 0x500);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x8fc0);
++
++ /* VgaDecRate is 1 at default on mt7988 */
++
++ /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
++ * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
++ */
++ __phy_write(phydev, 0x11, 0xb90a);
++ __phy_write(phydev, 0x12, 0x6f);
++ __phy_write(phydev, 0x10, 0x8f82);
++
++ /* RemAckCntLimitCtrl = 1 */
++ __phy_write(phydev, 0x11, 0xfbba);
++ __phy_write(phydev, 0x12, 0xc3);
++ __phy_write(phydev, 0x10, 0x87f8);
++
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
++ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
++ MTK_PHY_LPF_X_AVERAGE_MASK,
++ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
++
++ /* rg_tr_lpf_cnt_val = 1023 */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
++}
++
++static void mt798x_phy_eee(struct phy_device *phydev)
++{
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
++ MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
++ MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
++ FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
++ FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
++ MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++ 0xff));
++
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_TESTMUX_ADC_CTRL,
++ MTK_PHY_RG_TXEN_DIG_MASK);
++
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
++
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
++ MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
++ MTK_PHY_LPI_SLV_SEND_TX_EN,
++ FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
++
++ /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
++ MTK_PHY_LPI_TXPCS_LOC_RCV);
++
++ /* This also fixes some IoT issues, such as CH340 */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
++ MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
++ FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
++ FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
++ MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
++ FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
++ 0x33) |
++ MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
++ MTK_PHY_LPI_VCO_EEE_STG0_EN);
++
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
++ MTK_PHY_EEE_WAKE_MAS_INT_DC |
++ MTK_PHY_EEE_WAKE_SLV_INT_DC);
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
++ MTK_PHY_SMI_DETCNT_MAX_MASK,
++ FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
++ MTK_PHY_SMI_DET_MAX_EN);
++
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
++ MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
++ MTK_PHY_TREC_UPDATE_ENAB_CLR |
++ MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
++ MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ /* Regsigdet_sel_1000 = 0 */
++ __phy_write(phydev, 0x11, 0xb);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x9690);
++
++ /* REG_EEE_st2TrKf1000 = 2 */
++ __phy_write(phydev, 0x11, 0x114f);
++ __phy_write(phydev, 0x12, 0x2);
++ __phy_write(phydev, 0x10, 0x969a);
++
++ /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
++ __phy_write(phydev, 0x11, 0x3028);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x969e);
++
++ /* RegEEE_slv_wake_int_timer_tar = 8 */
++ __phy_write(phydev, 0x11, 0x5010);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x96a0);
++
++ /* RegEEE_trfreeze_timer2 = 586 */
++ __phy_write(phydev, 0x11, 0x24a);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x96a8);
++
++ /* RegEEE100Stg1_tar = 16 */
++ __phy_write(phydev, 0x11, 0x3210);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x96b8);
++
++ /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
++ __phy_write(phydev, 0x11, 0x1463);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x96ca);
++
++ /* DfeTailEnableVgaThresh1000 = 27 */
++ __phy_write(phydev, 0x11, 0x36);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x8f80);
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
++ __phy_modify(phydev, MTK_PHY_LPI_REG_14,
++ MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
++ FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
++
++ __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
++ FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
++ MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++ 0xff));
++}
++
++static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
++ u8 start_pair, u8 end_pair)
++{
++ u8 pair_n;
++ int ret;
++
++ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
++ /* TX_OFFSET & TX_AMP have no SW calibration. */
++ switch (cal_item) {
++ case TX_VCM:
++ ret = tx_vcm_cal_sw(phydev, pair_n);
++ break;
++ default:
++ return -EINVAL;
++ }
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
++ u8 start_pair, u8 end_pair, u32 *buf)
++{
++ u8 pair_n;
++ int ret;
++
++ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
++ /* TX_VCM has no efuse calibration. */
++ switch (cal_item) {
++ case REXT:
++ ret = rext_cal_efuse(phydev, buf);
++ break;
++ case TX_OFFSET:
++ ret = tx_offset_cal_efuse(phydev, buf);
++ break;
++ case TX_AMP:
++ ret = tx_amp_cal_efuse(phydev, buf);
++ break;
++ case TX_R50:
++ ret = tx_r50_cal_efuse(phydev, buf, pair_n);
++ break;
++ default:
++ return -EINVAL;
++ }
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
++ enum CAL_MODE cal_mode, u8 start_pair,
++ u8 end_pair, u32 *buf)
++{
++ int ret;
++
++ switch (cal_mode) {
++ case EFUSE_M:
++ ret = cal_efuse(phydev, cal_item, start_pair,
++ end_pair, buf);
++ break;
++ case SW_M:
++ ret = cal_sw(phydev, cal_item, start_pair, end_pair);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ if (ret) {
++ phydev_err(phydev, "cal %d failed\n", cal_item);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int mt798x_phy_calibration(struct phy_device *phydev)
++{
++ struct nvmem_cell *cell;
++ int ret = 0;
++ size_t len;
++ u32 *buf;
++
++ cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
++ if (IS_ERR(cell)) {
++ if (PTR_ERR(cell) == -EPROBE_DEFER)
++ return PTR_ERR(cell);
++ return 0;
++ }
++
++ buf = (u32 *)nvmem_cell_read(cell, &len);
++ if (IS_ERR(buf))
++ return PTR_ERR(buf);
++ nvmem_cell_put(cell);
++
++ if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
++ phydev_err(phydev, "invalid efuse data\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++ if (ret)
++ goto out;
++ ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++ if (ret)
++ goto out;
++ ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++ if (ret)
++ goto out;
++ ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
++ if (ret)
++ goto out;
++ ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
++ if (ret)
++ goto out;
++
++out:
++ kfree(buf);
++ return ret;
++}
++
++static int mt798x_phy_config_init(struct phy_device *phydev)
++{
++ switch (phydev->drv->phy_id) {
++ case MTK_GPHY_ID_MT7981:
++ mt7981_phy_finetune(phydev);
++ break;
++ case MTK_GPHY_ID_MT7988:
++ mt7988_phy_finetune(phydev);
++ break;
++ }
++
++ mt798x_phy_common_finetune(phydev);
++ mt798x_phy_eee(phydev);
++
++ return mt798x_phy_calibration(phydev);
++}
++
++static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
++ bool on)
++{
++ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ bool changed;
++
++ if (on)
++ changed = !test_and_set_bit(bit_on, &priv->led_state);
++ else
++ changed = !!test_and_clear_bit(bit_on, &priv->led_state);
++
++ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
++ (index ? 16 : 0), &priv->led_state);
++ if (changed)
++ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_ON_CTRL :
++ MTK_PHY_LED0_ON_CTRL,
++ MTK_PHY_LED_ON_MASK,
++ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
++ else
++ return 0;
++}
++
++static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
++ bool blinking)
++{
++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++ (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ bool changed;
++
++ if (blinking)
++ changed = !test_and_set_bit(bit_blink, &priv->led_state);
++ else
++ changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
++
++ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
++ (index ? 16 : 0), &priv->led_state);
++ if (changed)
++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_BLINK_CTRL :
++ MTK_PHY_LED0_BLINK_CTRL,
++ blinking ?
++ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
++ else
++ return 0;
++}
++
++static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
++ unsigned long *delay_on,
++ unsigned long *delay_off)
++{
++ bool blinking = false;
++ int err = 0;
++
++ if (index > 1)
++ return -EINVAL;
++
++ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
++ blinking = true;
++ *delay_on = 50;
++ *delay_off = 50;
++ }
++
++ err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
++ if (err)
++ return err;
++
++ return mt798x_phy_hw_led_on_set(phydev, index, false);
++}
++
++static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
++ u8 index, enum led_brightness value)
++{
++ int err;
++
++ err = mt798x_phy_hw_led_blink_set(phydev, index, false);
++ if (err)
++ return err;
++
++ return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
++}
++
++static const unsigned long supported_triggers =
++ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
++ BIT(TRIGGER_NETDEV_LINK) |
++ BIT(TRIGGER_NETDEV_LINK_10) |
++ BIT(TRIGGER_NETDEV_LINK_100) |
++ BIT(TRIGGER_NETDEV_LINK_1000) |
++ BIT(TRIGGER_NETDEV_RX) |
++ BIT(TRIGGER_NETDEV_TX);
++
++static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ if (index > 1)
++ return -EINVAL;
++
++ /* All combinations of the supported triggers are allowed */
++ if (rules & ~supported_triggers)
++ return -EOPNOTSUPP;
++
++ return 0;
++};
++
++static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
++ unsigned long *rules)
++{
++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++ (index ? 16 : 0);
++ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ int on, blink;
++
++ if (index > 1)
++ return -EINVAL;
++
++ on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
++
++ if (on < 0)
++ return -EIO;
++
++ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++ index ? MTK_PHY_LED1_BLINK_CTRL :
++ MTK_PHY_LED0_BLINK_CTRL);
++ if (blink < 0)
++ return -EIO;
++
++ if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
++ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
++ (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
++ set_bit(bit_netdev, &priv->led_state);
++ else
++ clear_bit(bit_netdev, &priv->led_state);
++
++ if (on & MTK_PHY_LED_ON_FORCE_ON)
++ set_bit(bit_on, &priv->led_state);
++ else
++ clear_bit(bit_on, &priv->led_state);
++
++ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
++ set_bit(bit_blink, &priv->led_state);
++ else
++ clear_bit(bit_blink, &priv->led_state);
++
++ if (!rules)
++ return 0;
++
++ if (on & MTK_PHY_LED_ON_LINK)
++ *rules |= BIT(TRIGGER_NETDEV_LINK);
++
++ if (on & MTK_PHY_LED_ON_LINK10)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
++
++ if (on & MTK_PHY_LED_ON_LINK100)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++ if (on & MTK_PHY_LED_ON_LINK1000)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++ if (on & MTK_PHY_LED_ON_FDX)
++ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
++
++ if (on & MTK_PHY_LED_ON_HDX)
++ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
++
++ if (blink & MTK_PHY_LED_BLINK_RX)
++ *rules |= BIT(TRIGGER_NETDEV_RX);
++
++ if (blink & MTK_PHY_LED_BLINK_TX)
++ *rules |= BIT(TRIGGER_NETDEV_TX);
++
++ return 0;
++};
++
++static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ u16 on = 0, blink = 0;
++ int ret;
++
++ if (index > 1)
++ return -EINVAL;
++
++ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
++ on |= MTK_PHY_LED_ON_FDX;
++
++ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
++ on |= MTK_PHY_LED_ON_HDX;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK10;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK100;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK1000;
++
++ if (rules & BIT(TRIGGER_NETDEV_RX)) {
++ blink |= (on & MTK_PHY_LED_ON_LINK) ?
++ (((on & MTK_PHY_LED_ON_LINK10) ?
++ MTK_PHY_LED_BLINK_10RX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK100) ?
++ MTK_PHY_LED_BLINK_100RX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK1000) ?
++ MTK_PHY_LED_BLINK_1000RX : 0)) :
++ MTK_PHY_LED_BLINK_RX;
++ }
++
++ if (rules & BIT(TRIGGER_NETDEV_TX)) {
++ blink |= (on & MTK_PHY_LED_ON_LINK) ?
++ (((on & MTK_PHY_LED_ON_LINK10) ?
++ MTK_PHY_LED_BLINK_10TX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK100) ?
++ MTK_PHY_LED_BLINK_100TX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK1000) ?
++ MTK_PHY_LED_BLINK_1000TX : 0)) :
++ MTK_PHY_LED_BLINK_TX;
++ }
++
++ if (blink || on)
++ set_bit(bit_netdev, &priv->led_state);
++ else
++ clear_bit(bit_netdev, &priv->led_state);
++
++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_ON_CTRL :
++ MTK_PHY_LED0_ON_CTRL,
++ MTK_PHY_LED_ON_FDX |
++ MTK_PHY_LED_ON_HDX |
++ MTK_PHY_LED_ON_LINK,
++ on);
++
++ if (ret)
++ return ret;
++
++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_BLINK_CTRL :
++ MTK_PHY_LED0_BLINK_CTRL, blink);
++};
++
++static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
++{
++ struct mtk_socphy_shared *priv = phydev->shared->priv;
++ u32 polarities;
++
++ if (led_num == 0)
++ polarities = ~(priv->boottrap);
++ else
++ polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
++
++ if (polarities & BIT(phydev->mdio.addr))
++ return true;
++
++ return false;
++}
++
++static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
++{
++ struct pinctrl *pinctrl;
++ int index;
++
++ /* Setup LED polarity according to bootstrap use of LED pins */
++ for (index = 0; index < 2; ++index)
++ phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++ MTK_PHY_LED_ON_POLARITY,
++ mt7988_phy_led_get_polarity(phydev, index) ?
++ MTK_PHY_LED_ON_POLARITY : 0);
++
++ /* Only now setup pinctrl to avoid bogus blinking */
++ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
++ if (IS_ERR(pinctrl))
++ dev_err(&phydev->mdio.bus->dev,
++ "Failed to setup PHY LED pinctrl\n");
++
++ return 0;
++}
++
++static int mt7988_phy_probe_shared(struct phy_device *phydev)
++{
++ struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
++ struct mtk_socphy_shared *shared = phydev->shared->priv;
++ struct regmap *regmap;
++ u32 reg;
++ int ret;
++
++ /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
++ * LED_C and LED_D respectively. At the same time those pins are used to
++ * bootstrap configuration of the reference clock source (LED_A),
++ * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
++ * In practice this is done using a LED and a resistor pulling the pin
++ * either to GND or to VIO.
++ * The detected value at boot time is accessible at run-time using the
++ * TPBANK0 register located in the gpio base of the pinctrl, in order
++ * to read it here it needs to be referenced by a phandle called
++ * 'mediatek,pio' in the MDIO bus hosting the PHY.
++ * The 4 bits in TPBANK0 are kept as package shared data and are used to
++ * set LED polarity for each of the LED0.
++ */
++ regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
++ if (IS_ERR(regmap))
++ return PTR_ERR(regmap);
++
++ ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®);
++ if (ret)
++ return ret;
++
++ shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
++
++ return 0;
++}
++
++static void mt798x_phy_leds_state_init(struct phy_device *phydev)
++{
++ int i;
++
++ for (i = 0; i < 2; ++i)
++ mt798x_phy_led_hw_control_get(phydev, i, NULL);
++}
++
++static int mt7988_phy_probe(struct phy_device *phydev)
++{
++ struct mtk_socphy_shared *shared;
++ struct mtk_socphy_priv *priv;
++ int err;
++
++ if (phydev->mdio.addr > 3)
++ return -EINVAL;
++
++ err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
++ sizeof(struct mtk_socphy_shared));
++ if (err)
++ return err;
++
++ if (phy_package_probe_once(phydev)) {
++ err = mt7988_phy_probe_shared(phydev);
++ if (err)
++ return err;
++ }
++
++ shared = phydev->shared->priv;
++ priv = &shared->priv[phydev->mdio.addr];
++
++ phydev->priv = priv;
++
++ mt798x_phy_leds_state_init(phydev);
++
++ err = mt7988_phy_fix_leds_polarities(phydev);
++ if (err)
++ return err;
++
++ /* Disable TX power saving at probing to:
++ * 1. Meet common mode compliance test criteria
++ * 2. Make sure that TX-VCM calibration works fine
++ */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
++ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
++
++ return mt798x_phy_calibration(phydev);
++}
++
++static int mt7981_phy_probe(struct phy_device *phydev)
++{
++ struct mtk_socphy_priv *priv;
++
++ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
++ GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ phydev->priv = priv;
++
++ mt798x_phy_leds_state_init(phydev);
++
++ return mt798x_phy_calibration(phydev);
++}
++
++static struct phy_driver mtk_socphy_driver[] = {
++ {
++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
++ .name = "MediaTek MT7981 PHY",
++ .config_init = mt798x_phy_config_init,
++ .config_intr = genphy_no_config_intr,
++ .handle_interrupt = genphy_handle_interrupt_no_ack,
++ .probe = mt7981_phy_probe,
++ .suspend = genphy_suspend,
++ .resume = genphy_resume,
++ .read_page = mtk_socphy_read_page,
++ .write_page = mtk_socphy_write_page,
++ .led_blink_set = mt798x_phy_led_blink_set,
++ .led_brightness_set = mt798x_phy_led_brightness_set,
++ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
++ .led_hw_control_set = mt798x_phy_led_hw_control_set,
++ .led_hw_control_get = mt798x_phy_led_hw_control_get,
++ },
++ {
++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
++ .name = "MediaTek MT7988 PHY",
++ .config_init = mt798x_phy_config_init,
++ .config_intr = genphy_no_config_intr,
++ .handle_interrupt = genphy_handle_interrupt_no_ack,
++ .probe = mt7988_phy_probe,
++ .suspend = genphy_suspend,
++ .resume = genphy_resume,
++ .read_page = mtk_socphy_read_page,
++ .write_page = mtk_socphy_write_page,
++ .led_blink_set = mt798x_phy_led_blink_set,
++ .led_brightness_set = mt798x_phy_led_brightness_set,
++ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
++ .led_hw_control_set = mt798x_phy_led_hw_control_set,
++ .led_hw_control_get = mt798x_phy_led_hw_control_get,
++ },
++};
++
++module_phy_driver(mtk_socphy_driver);
++
++static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
++ { }
++};
++
++MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver");
++MODULE_LICENSE("GPL");
++
++MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -0,0 +1,111 @@
++// SPDX-License-Identifier: GPL-2.0+
++#include <linux/bitfield.h>
++#include <linux/module.h>
++#include <linux/phy.h>
++
++#define MTK_EXT_PAGE_ACCESS 0x1f
++#define MTK_PHY_PAGE_STANDARD 0x0000
++#define MTK_PHY_PAGE_EXTENDED 0x0001
++#define MTK_PHY_PAGE_EXTENDED_2 0x0002
++#define MTK_PHY_PAGE_EXTENDED_3 0x0003
++#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
++#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
++
++static int mtk_gephy_read_page(struct phy_device *phydev)
++{
++ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++
++static int mtk_gephy_write_page(struct phy_device *phydev, int page)
++{
++ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++
++static void mtk_gephy_config_init(struct phy_device *phydev)
++{
++ /* Enable HW auto downshift */
++ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
++
++ /* Increase SlvDPSready time */
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ __phy_write(phydev, 0x10, 0xafae);
++ __phy_write(phydev, 0x12, 0x2f);
++ __phy_write(phydev, 0x10, 0x8fae);
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ /* Adjust 100_mse_threshold */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
++
++ /* Disable mcc */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
++}
++
++static int mt7530_phy_config_init(struct phy_device *phydev)
++{
++ mtk_gephy_config_init(phydev);
++
++ /* Increase post_update_timer */
++ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
++
++ return 0;
++}
++
++static int mt7531_phy_config_init(struct phy_device *phydev)
++{
++ mtk_gephy_config_init(phydev);
++
++ /* PHY link down power saving enable */
++ phy_set_bits(phydev, 0x17, BIT(4));
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
++
++ /* Set TX Pair delay selection */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
++
++ return 0;
++}
++
++static struct phy_driver mtk_gephy_driver[] = {
++ {
++ PHY_ID_MATCH_EXACT(0x03a29412),
++ .name = "MediaTek MT7530 PHY",
++ .config_init = mt7530_phy_config_init,
++ /* Interrupts are handled by the switch, not the PHY
++ * itself.
++ */
++ .config_intr = genphy_no_config_intr,
++ .handle_interrupt = genphy_handle_interrupt_no_ack,
++ .suspend = genphy_suspend,
++ .resume = genphy_resume,
++ .read_page = mtk_gephy_read_page,
++ .write_page = mtk_gephy_write_page,
++ },
++ {
++ PHY_ID_MATCH_EXACT(0x03a29441),
++ .name = "MediaTek MT7531 PHY",
++ .config_init = mt7531_phy_config_init,
++ /* Interrupts are handled by the switch, not the PHY
++ * itself.
++ */
++ .config_intr = genphy_no_config_intr,
++ .handle_interrupt = genphy_handle_interrupt_no_ack,
++ .suspend = genphy_suspend,
++ .resume = genphy_resume,
++ .read_page = mtk_gephy_read_page,
++ .write_page = mtk_gephy_write_page,
++ },
++};
++
++module_phy_driver(mtk_gephy_driver);
++
++static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
++ { PHY_ID_MATCH_EXACT(0x03a29441) },
++ { PHY_ID_MATCH_EXACT(0x03a29412) },
++ { }
++};
++
++MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
++MODULE_LICENSE("GPL");
++
++MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
--- /dev/null
+From 71d88c7409b91c853d7f9c933f5e27933d656e5e Mon Sep 17 00:00:00 2001
+Date: Sat, 9 Nov 2024 00:34:52 +0800
+Subject: [PATCH 05/20] net: phy: mediatek: Move LED helper functions into mtk
+ phy lib
+
+This patch creates mtk-phy-lib.c & mtk-phy.h and integrates mtk-ge-soc.c's
+LED helper functions so that we can use those helper functions in other
+MTK's ethernet phy driver.
+
+---
+ MAINTAINERS | 2 +
+ drivers/net/phy/mediatek/Kconfig | 4 +
+ drivers/net/phy/mediatek/Makefile | 1 +
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 280 +++----------------------
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 254 ++++++++++++++++++++++
+ drivers/net/phy/mediatek/mtk.h | 86 ++++++++
+ 6 files changed, 372 insertions(+), 255 deletions(-)
+ create mode 100644 drivers/net/phy/mediatek/mtk-phy-lib.c
+ create mode 100644 drivers/net/phy/mediatek/mtk.h
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -14428,7 +14428,9 @@ M: SkyLake Huang <SkyLake.Huang@mediatek
+ S: Maintained
+ F: drivers/net/phy/mediatek/mtk-ge-soc.c
++F: drivers/net/phy/mediatek/mtk-phy-lib.c
+ F: drivers/net/phy/mediatek/mtk-ge.c
++F: drivers/net/phy/mediatek/mtk.h
+ F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c
+
+ MEDIATEK I2C CONTROLLER DRIVER
+--- a/drivers/net/phy/mediatek/Kconfig
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -1,4 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0-only
++config MTK_NET_PHYLIB
++ tristate
++
+ config MEDIATEK_GE_PHY
+ tristate "MediaTek Gigabit Ethernet PHYs"
+ help
+@@ -13,6 +16,7 @@ config MEDIATEK_GE_SOC_PHY
+ tristate "MediaTek SoC Ethernet PHYs"
+ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
+ depends on NVMEM_MTK_EFUSE
++ select MTK_NET_PHYLIB
+ help
+ Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+
+--- a/drivers/net/phy/mediatek/Makefile
++++ b/drivers/net/phy/mediatek/Makefile
+@@ -1,3 +1,4 @@
+ # SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o
+ obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
+ obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -8,6 +8,8 @@
+ #include <linux/phy.h>
+ #include <linux/regmap.h>
+
++#include "mtk.h"
++
+ #define MTK_GPHY_ID_MT7981 0x03a29461
+ #define MTK_GPHY_ID_MT7988 0x03a29481
+
+@@ -210,41 +212,6 @@
+ #define MTK_PHY_DA_TX_R50_PAIR_D 0x540
+
+ /* Registers on MDIO_MMD_VEND2 */
+-#define MTK_PHY_LED0_ON_CTRL 0x24
+-#define MTK_PHY_LED1_ON_CTRL 0x26
+-#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
+-#define MTK_PHY_LED_ON_LINK1000 BIT(0)
+-#define MTK_PHY_LED_ON_LINK100 BIT(1)
+-#define MTK_PHY_LED_ON_LINK10 BIT(2)
+-#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
+- MTK_PHY_LED_ON_LINK100 |\
+- MTK_PHY_LED_ON_LINK1000)
+-#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
+-#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
+-#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
+-#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
+-#define MTK_PHY_LED_ON_POLARITY BIT(14)
+-#define MTK_PHY_LED_ON_ENABLE BIT(15)
+-
+-#define MTK_PHY_LED0_BLINK_CTRL 0x25
+-#define MTK_PHY_LED1_BLINK_CTRL 0x27
+-#define MTK_PHY_LED_BLINK_1000TX BIT(0)
+-#define MTK_PHY_LED_BLINK_1000RX BIT(1)
+-#define MTK_PHY_LED_BLINK_100TX BIT(2)
+-#define MTK_PHY_LED_BLINK_100RX BIT(3)
+-#define MTK_PHY_LED_BLINK_10TX BIT(4)
+-#define MTK_PHY_LED_BLINK_10RX BIT(5)
+-#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
+- MTK_PHY_LED_BLINK_100RX |\
+- MTK_PHY_LED_BLINK_1000RX)
+-#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
+- MTK_PHY_LED_BLINK_100TX |\
+- MTK_PHY_LED_BLINK_1000TX)
+-#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
+-#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
+-#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
+-#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
+-
+ #define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
+
+ #define MTK_PHY_RG_BG_RASEL 0x115
+@@ -299,14 +266,6 @@ enum CAL_MODE {
+ SW_M
+ };
+
+-#define MTK_PHY_LED_STATE_FORCE_ON 0
+-#define MTK_PHY_LED_STATE_FORCE_BLINK 1
+-#define MTK_PHY_LED_STATE_NETDEV 2
+-
+-struct mtk_socphy_priv {
+- unsigned long led_state;
+-};
+-
+ struct mtk_socphy_shared {
+ u32 boottrap;
+ struct mtk_socphy_priv priv[4];
+@@ -1172,76 +1131,23 @@ static int mt798x_phy_config_init(struct
+ return mt798x_phy_calibration(phydev);
+ }
+
+-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+- bool on)
+-{
+- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+- struct mtk_socphy_priv *priv = phydev->priv;
+- bool changed;
+-
+- if (on)
+- changed = !test_and_set_bit(bit_on, &priv->led_state);
+- else
+- changed = !!test_and_clear_bit(bit_on, &priv->led_state);
+-
+- changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
+- (index ? 16 : 0), &priv->led_state);
+- if (changed)
+- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_ON_CTRL :
+- MTK_PHY_LED0_ON_CTRL,
+- MTK_PHY_LED_ON_MASK,
+- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+- else
+- return 0;
+-}
+-
+-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+- bool blinking)
+-{
+- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+- (index ? 16 : 0);
+- struct mtk_socphy_priv *priv = phydev->priv;
+- bool changed;
+-
+- if (blinking)
+- changed = !test_and_set_bit(bit_blink, &priv->led_state);
+- else
+- changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
+-
+- changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
+- (index ? 16 : 0), &priv->led_state);
+- if (changed)
+- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_BLINK_CTRL :
+- MTK_PHY_LED0_BLINK_CTRL,
+- blinking ?
+- MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+- else
+- return 0;
+-}
+-
+ static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+ {
+ bool blinking = false;
+- int err = 0;
+-
+- if (index > 1)
+- return -EINVAL;
++ int err;
+
+- if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+- blinking = true;
+- *delay_on = 50;
+- *delay_off = 50;
+- }
++ err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
++ if (err < 0)
++ return err;
+
+- err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
++ err = mtk_phy_hw_led_blink_set(phydev, index, blinking);
+ if (err)
+ return err;
+
+- return mt798x_phy_hw_led_on_set(phydev, index, false);
++ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
++ false);
+ }
+
+ static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
+@@ -1249,11 +1155,12 @@ static int mt798x_phy_led_brightness_set
+ {
+ int err;
+
+- err = mt798x_phy_hw_led_blink_set(phydev, index, false);
++ err = mtk_phy_hw_led_blink_set(phydev, index, false);
+ if (err)
+ return err;
+
+- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
++ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
++ (value != LED_OFF));
+ }
+
+ static const unsigned long supported_triggers =
+@@ -1269,155 +1176,26 @@ static const unsigned long supported_tri
+ static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+ {
+- if (index > 1)
+- return -EINVAL;
+-
+- /* All combinations of the supported triggers are allowed */
+- if (rules & ~supported_triggers)
+- return -EOPNOTSUPP;
+-
+- return 0;
+-};
++ return mtk_phy_led_hw_is_supported(phydev, index, rules,
++ supported_triggers);
++}
+
+ static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules)
+ {
+- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+- (index ? 16 : 0);
+- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+- struct mtk_socphy_priv *priv = phydev->priv;
+- int on, blink;
+-
+- if (index > 1)
+- return -EINVAL;
+-
+- on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+- index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
+-
+- if (on < 0)
+- return -EIO;
+-
+- blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+- index ? MTK_PHY_LED1_BLINK_CTRL :
+- MTK_PHY_LED0_BLINK_CTRL);
+- if (blink < 0)
+- return -EIO;
+-
+- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
+- MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
+- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
+- set_bit(bit_netdev, &priv->led_state);
+- else
+- clear_bit(bit_netdev, &priv->led_state);
+-
+- if (on & MTK_PHY_LED_ON_FORCE_ON)
+- set_bit(bit_on, &priv->led_state);
+- else
+- clear_bit(bit_on, &priv->led_state);
+-
+- if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
+- set_bit(bit_blink, &priv->led_state);
+- else
+- clear_bit(bit_blink, &priv->led_state);
+-
+- if (!rules)
+- return 0;
+-
+- if (on & MTK_PHY_LED_ON_LINK)
+- *rules |= BIT(TRIGGER_NETDEV_LINK);
+-
+- if (on & MTK_PHY_LED_ON_LINK10)
+- *rules |= BIT(TRIGGER_NETDEV_LINK_10);
+-
+- if (on & MTK_PHY_LED_ON_LINK100)
+- *rules |= BIT(TRIGGER_NETDEV_LINK_100);
+-
+- if (on & MTK_PHY_LED_ON_LINK1000)
+- *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+-
+- if (on & MTK_PHY_LED_ON_FDX)
+- *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+-
+- if (on & MTK_PHY_LED_ON_HDX)
+- *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
+-
+- if (blink & MTK_PHY_LED_BLINK_RX)
+- *rules |= BIT(TRIGGER_NETDEV_RX);
+-
+- if (blink & MTK_PHY_LED_BLINK_TX)
+- *rules |= BIT(TRIGGER_NETDEV_TX);
+-
+- return 0;
++ return mtk_phy_led_hw_ctrl_get(phydev, index, rules,
++ MTK_GPHY_LED_ON_SET,
++ MTK_GPHY_LED_RX_BLINK_SET,
++ MTK_GPHY_LED_TX_BLINK_SET);
+ };
+
+ static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+ {
+- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+- struct mtk_socphy_priv *priv = phydev->priv;
+- u16 on = 0, blink = 0;
+- int ret;
+-
+- if (index > 1)
+- return -EINVAL;
+-
+- if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+- on |= MTK_PHY_LED_ON_FDX;
+-
+- if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
+- on |= MTK_PHY_LED_ON_HDX;
+-
+- if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
+- on |= MTK_PHY_LED_ON_LINK10;
+-
+- if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+- on |= MTK_PHY_LED_ON_LINK100;
+-
+- if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+- on |= MTK_PHY_LED_ON_LINK1000;
+-
+- if (rules & BIT(TRIGGER_NETDEV_RX)) {
+- blink |= (on & MTK_PHY_LED_ON_LINK) ?
+- (((on & MTK_PHY_LED_ON_LINK10) ?
+- MTK_PHY_LED_BLINK_10RX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK100) ?
+- MTK_PHY_LED_BLINK_100RX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK1000) ?
+- MTK_PHY_LED_BLINK_1000RX : 0)) :
+- MTK_PHY_LED_BLINK_RX;
+- }
+-
+- if (rules & BIT(TRIGGER_NETDEV_TX)) {
+- blink |= (on & MTK_PHY_LED_ON_LINK) ?
+- (((on & MTK_PHY_LED_ON_LINK10) ?
+- MTK_PHY_LED_BLINK_10TX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK100) ?
+- MTK_PHY_LED_BLINK_100TX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK1000) ?
+- MTK_PHY_LED_BLINK_1000TX : 0)) :
+- MTK_PHY_LED_BLINK_TX;
+- }
+-
+- if (blink || on)
+- set_bit(bit_netdev, &priv->led_state);
+- else
+- clear_bit(bit_netdev, &priv->led_state);
+-
+- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_ON_CTRL :
+- MTK_PHY_LED0_ON_CTRL,
+- MTK_PHY_LED_ON_FDX |
+- MTK_PHY_LED_ON_HDX |
+- MTK_PHY_LED_ON_LINK,
+- on);
+-
+- if (ret)
+- return ret;
+-
+- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+- MTK_PHY_LED1_BLINK_CTRL :
+- MTK_PHY_LED0_BLINK_CTRL, blink);
++ return mtk_phy_led_hw_ctrl_set(phydev, index, rules,
++ MTK_GPHY_LED_ON_SET,
++ MTK_GPHY_LED_RX_BLINK_SET,
++ MTK_GPHY_LED_TX_BLINK_SET);
+ };
+
+ static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
+@@ -1492,14 +1270,6 @@ static int mt7988_phy_probe_shared(struc
+ return 0;
+ }
+
+-static void mt798x_phy_leds_state_init(struct phy_device *phydev)
+-{
+- int i;
+-
+- for (i = 0; i < 2; ++i)
+- mt798x_phy_led_hw_control_get(phydev, i, NULL);
+-}
+-
+ static int mt7988_phy_probe(struct phy_device *phydev)
+ {
+ struct mtk_socphy_shared *shared;
+@@ -1525,7 +1295,7 @@ static int mt7988_phy_probe(struct phy_d
+
+ phydev->priv = priv;
+
+- mt798x_phy_leds_state_init(phydev);
++ mtk_phy_leds_state_init(phydev);
+
+ err = mt7988_phy_fix_leds_polarities(phydev);
+ if (err)
+@@ -1552,7 +1322,7 @@ static int mt7981_phy_probe(struct phy_d
+
+ phydev->priv = priv;
+
+- mt798x_phy_leds_state_init(phydev);
++ mtk_phy_leds_state_init(phydev);
+
+ return mt798x_phy_calibration(phydev);
+ }
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -0,0 +1,254 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <linux/phy.h>
++#include <linux/module.h>
++
++#include <linux/netdevice.h>
++
++#include "mtk.h"
++
++int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++ unsigned long rules,
++ unsigned long supported_triggers)
++{
++ if (index > 1)
++ return -EINVAL;
++
++ /* All combinations of the supported triggers are allowed */
++ if (rules & ~supported_triggers)
++ return -EOPNOTSUPP;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
++
++int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
++ unsigned long *rules, u16 on_set,
++ u16 rx_blink_set, u16 tx_blink_set)
++{
++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++ (index ? 16 : 0);
++ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ int on, blink;
++
++ if (index > 1)
++ return -EINVAL;
++
++ on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
++
++ if (on < 0)
++ return -EIO;
++
++ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++ index ? MTK_PHY_LED1_BLINK_CTRL :
++ MTK_PHY_LED0_BLINK_CTRL);
++ if (blink < 0)
++ return -EIO;
++
++ if ((on & (on_set | MTK_PHY_LED_ON_FDX |
++ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
++ (blink & (rx_blink_set | tx_blink_set)))
++ set_bit(bit_netdev, &priv->led_state);
++ else
++ clear_bit(bit_netdev, &priv->led_state);
++
++ if (on & MTK_PHY_LED_ON_FORCE_ON)
++ set_bit(bit_on, &priv->led_state);
++ else
++ clear_bit(bit_on, &priv->led_state);
++
++ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
++ set_bit(bit_blink, &priv->led_state);
++ else
++ clear_bit(bit_blink, &priv->led_state);
++
++ if (!rules)
++ return 0;
++
++ if (on & on_set)
++ *rules |= BIT(TRIGGER_NETDEV_LINK);
++
++ if (on & MTK_PHY_LED_ON_LINK10)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
++
++ if (on & MTK_PHY_LED_ON_LINK100)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++ if (on & MTK_PHY_LED_ON_LINK1000)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++ if (on & MTK_PHY_LED_ON_LINK2500)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
++
++ if (on & MTK_PHY_LED_ON_FDX)
++ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
++
++ if (on & MTK_PHY_LED_ON_HDX)
++ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
++
++ if (blink & rx_blink_set)
++ *rules |= BIT(TRIGGER_NETDEV_RX);
++
++ if (blink & tx_blink_set)
++ *rules |= BIT(TRIGGER_NETDEV_TX);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
++
++int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
++ unsigned long rules, u16 on_set,
++ u16 rx_blink_set, u16 tx_blink_set)
++{
++ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ u16 on = 0, blink = 0;
++ int ret;
++
++ if (index > 1)
++ return -EINVAL;
++
++ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
++ on |= MTK_PHY_LED_ON_FDX;
++
++ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
++ on |= MTK_PHY_LED_ON_HDX;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK10;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK100;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK1000;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK2500;
++
++ if (rules & BIT(TRIGGER_NETDEV_RX)) {
++ blink |= (on & on_set) ?
++ (((on & MTK_PHY_LED_ON_LINK10) ?
++ MTK_PHY_LED_BLINK_10RX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK100) ?
++ MTK_PHY_LED_BLINK_100RX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK1000) ?
++ MTK_PHY_LED_BLINK_1000RX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK2500) ?
++ MTK_PHY_LED_BLINK_2500RX : 0)) :
++ rx_blink_set;
++ }
++
++ if (rules & BIT(TRIGGER_NETDEV_TX)) {
++ blink |= (on & on_set) ?
++ (((on & MTK_PHY_LED_ON_LINK10) ?
++ MTK_PHY_LED_BLINK_10TX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK100) ?
++ MTK_PHY_LED_BLINK_100TX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK1000) ?
++ MTK_PHY_LED_BLINK_1000TX : 0) |
++ ((on & MTK_PHY_LED_ON_LINK2500) ?
++ MTK_PHY_LED_BLINK_2500TX : 0)) :
++ tx_blink_set;
++ }
++
++ if (blink || on)
++ set_bit(bit_netdev, &priv->led_state);
++ else
++ clear_bit(bit_netdev, &priv->led_state);
++
++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++ MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
++ on);
++
++ if (ret)
++ return ret;
++
++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_BLINK_CTRL :
++ MTK_PHY_LED0_BLINK_CTRL, blink);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
++
++int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
++ unsigned long *delay_off, bool *blinking)
++{
++ if (index > 1)
++ return -EINVAL;
++
++ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
++ *blinking = true;
++ *delay_on = 50;
++ *delay_off = 50;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
++
++int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
++ u16 led_on_mask, bool on)
++{
++ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ bool changed;
++
++ if (on)
++ changed = !test_and_set_bit(bit_on, &priv->led_state);
++ else
++ changed = !!test_and_clear_bit(bit_on, &priv->led_state);
++
++ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
++ (index ? 16 : 0), &priv->led_state);
++ if (changed)
++ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_ON_CTRL :
++ MTK_PHY_LED0_ON_CTRL,
++ led_on_mask,
++ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
++ else
++ return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
++
++int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking)
++{
++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++ (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ bool changed;
++
++ if (blinking)
++ changed = !test_and_set_bit(bit_blink, &priv->led_state);
++ else
++ changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
++
++ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
++ (index ? 16 : 0), &priv->led_state);
++ if (changed)
++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_BLINK_CTRL :
++ MTK_PHY_LED0_BLINK_CTRL,
++ blinking ?
++ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
++ else
++ return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
++
++void mtk_phy_leds_state_init(struct phy_device *phydev)
++{
++ int i;
++
++ for (i = 0; i < 2; ++i)
++ phydev->drv->led_hw_control_get(phydev, i, NULL);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
++
++MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -0,0 +1,86 @@
++/* SPDX-License-Identifier: GPL-2.0
++ *
++ * Common definition for Mediatek Ethernet PHYs
++ * Copyright (c) 2024 MediaTek Inc.
++ */
++
++#ifndef _MTK_EPHY_H_
++#define _MTK_EPHY_H_
++
++#define MTK_EXT_PAGE_ACCESS 0x1f
++
++/* Registers on MDIO_MMD_VEND2 */
++#define MTK_PHY_LED0_ON_CTRL 0x24
++#define MTK_PHY_LED1_ON_CTRL 0x26
++#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0)
++#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0)
++#define MTK_PHY_LED_ON_LINK1000 BIT(0)
++#define MTK_PHY_LED_ON_LINK100 BIT(1)
++#define MTK_PHY_LED_ON_LINK10 BIT(2)
++#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
++#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
++#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
++#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
++#define MTK_PHY_LED_ON_LINK2500 BIT(7)
++#define MTK_PHY_LED_ON_POLARITY BIT(14)
++#define MTK_PHY_LED_ON_ENABLE BIT(15)
++
++#define MTK_PHY_LED0_BLINK_CTRL 0x25
++#define MTK_PHY_LED1_BLINK_CTRL 0x27
++#define MTK_PHY_LED_BLINK_1000TX BIT(0)
++#define MTK_PHY_LED_BLINK_1000RX BIT(1)
++#define MTK_PHY_LED_BLINK_100TX BIT(2)
++#define MTK_PHY_LED_BLINK_100RX BIT(3)
++#define MTK_PHY_LED_BLINK_10TX BIT(4)
++#define MTK_PHY_LED_BLINK_10RX BIT(5)
++#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
++#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
++#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
++#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
++#define MTK_PHY_LED_BLINK_2500TX BIT(10)
++#define MTK_PHY_LED_BLINK_2500RX BIT(11)
++
++#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \
++ MTK_PHY_LED_ON_LINK100 | \
++ MTK_PHY_LED_ON_LINK10)
++#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
++ MTK_PHY_LED_BLINK_100RX | \
++ MTK_PHY_LED_BLINK_10RX)
++#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
++ MTK_PHY_LED_BLINK_100RX | \
++ MTK_PHY_LED_BLINK_10RX)
++
++#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \
++ MTK_GPHY_LED_ON_SET)
++#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
++ MTK_GPHY_LED_RX_BLINK_SET)
++#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
++ MTK_GPHY_LED_TX_BLINK_SET)
++
++#define MTK_PHY_LED_STATE_FORCE_ON 0
++#define MTK_PHY_LED_STATE_FORCE_BLINK 1
++#define MTK_PHY_LED_STATE_NETDEV 2
++
++struct mtk_socphy_priv {
++ unsigned long led_state;
++};
++
++int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++ unsigned long rules,
++ unsigned long supported_triggers);
++int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
++ unsigned long rules, u16 on_set,
++ u16 rx_blink_set, u16 tx_blink_set);
++int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
++ unsigned long *rules, u16 on_set,
++ u16 rx_blink_set, u16 tx_blink_set);
++int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
++ unsigned long *delay_off, bool *blinking);
++int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
++ u16 led_on_mask, bool on);
++int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
++ bool blinking);
++void mtk_phy_leds_state_init(struct phy_device *phydev);
++
++#endif /* _MTK_EPHY_H_ */
--- /dev/null
+From 3efd0595fc7aaae300f5d9f4f0ae86f432c8d2c7 Mon Sep 17 00:00:00 2001
+Date: Sat, 9 Nov 2024 00:34:53 +0800
+Subject: [PATCH 06/20] net: phy: mediatek: Improve readability of
+ mtk-phy-lib.c's mtk_phy_led_hw_ctrl_set()
+
+This patch removes parens around TRIGGER_NETDEV_RX/TRIGGER_NETDEV_TX in
+mtk_phy_led_hw_ctrl_set(), which improves readability.
+
+---
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 44 ++++++++++++++------------
+ 1 file changed, 24 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -129,29 +129,33 @@ int mtk_phy_led_hw_ctrl_set(struct phy_d
+ on |= MTK_PHY_LED_ON_LINK2500;
+
+ if (rules & BIT(TRIGGER_NETDEV_RX)) {
+- blink |= (on & on_set) ?
+- (((on & MTK_PHY_LED_ON_LINK10) ?
+- MTK_PHY_LED_BLINK_10RX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK100) ?
+- MTK_PHY_LED_BLINK_100RX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK1000) ?
+- MTK_PHY_LED_BLINK_1000RX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK2500) ?
+- MTK_PHY_LED_BLINK_2500RX : 0)) :
+- rx_blink_set;
++ if (on & on_set) {
++ if (on & MTK_PHY_LED_ON_LINK10)
++ blink |= MTK_PHY_LED_BLINK_10RX;
++ if (on & MTK_PHY_LED_ON_LINK100)
++ blink |= MTK_PHY_LED_BLINK_100RX;
++ if (on & MTK_PHY_LED_ON_LINK1000)
++ blink |= MTK_PHY_LED_BLINK_1000RX;
++ if (on & MTK_PHY_LED_ON_LINK2500)
++ blink |= MTK_PHY_LED_BLINK_2500RX;
++ } else {
++ blink |= rx_blink_set;
++ }
+ }
+
+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
+- blink |= (on & on_set) ?
+- (((on & MTK_PHY_LED_ON_LINK10) ?
+- MTK_PHY_LED_BLINK_10TX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK100) ?
+- MTK_PHY_LED_BLINK_100TX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK1000) ?
+- MTK_PHY_LED_BLINK_1000TX : 0) |
+- ((on & MTK_PHY_LED_ON_LINK2500) ?
+- MTK_PHY_LED_BLINK_2500TX : 0)) :
+- tx_blink_set;
++ if (on & on_set) {
++ if (on & MTK_PHY_LED_ON_LINK10)
++ blink |= MTK_PHY_LED_BLINK_10TX;
++ if (on & MTK_PHY_LED_ON_LINK100)
++ blink |= MTK_PHY_LED_BLINK_100TX;
++ if (on & MTK_PHY_LED_ON_LINK1000)
++ blink |= MTK_PHY_LED_BLINK_1000TX;
++ if (on & MTK_PHY_LED_ON_LINK2500)
++ blink |= MTK_PHY_LED_BLINK_2500TX;
++ } else {
++ blink |= tx_blink_set;
++ }
+ }
+
+ if (blink || on)
--- /dev/null
+From 50a97d716105a5f35aaecca0bdfe8e23cba0e87f Mon Sep 17 00:00:00 2001
+Date: Sat, 9 Nov 2024 00:34:54 +0800
+Subject: [PATCH 07/20] net: phy: mediatek: Integrate read/write page helper
+ functions
+
+This patch integrates read/write page helper functions as MTK phy lib.
+They are basically the same in mtk-ge.c & mtk-ge-soc.c.
+
+---
+ drivers/net/phy/mediatek/Kconfig | 1 +
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 18 ++++--------------
+ drivers/net/phy/mediatek/mtk-ge.c | 20 ++++++--------------
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 12 ++++++++++++
+ drivers/net/phy/mediatek/mtk.h | 3 +++
+ 5 files changed, 26 insertions(+), 28 deletions(-)
+
+--- a/drivers/net/phy/mediatek/Kconfig
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -4,6 +4,7 @@ config MTK_NET_PHYLIB
+
+ config MEDIATEK_GE_PHY
+ tristate "MediaTek Gigabit Ethernet PHYs"
++ select MTK_NET_PHYLIB
+ help
+ Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -271,16 +271,6 @@ struct mtk_socphy_shared {
+ struct mtk_socphy_priv priv[4];
+ };
+
+-static int mtk_socphy_read_page(struct phy_device *phydev)
+-{
+- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_socphy_write_page(struct phy_device *phydev, int page)
+-{
+- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+ /* One calibration cycle consists of:
+ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
+ * until AD_CAL_COMP is ready to output calibration result.
+@@ -1337,8 +1327,8 @@ static struct phy_driver mtk_socphy_driv
+ .probe = mt7981_phy_probe,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+- .read_page = mtk_socphy_read_page,
+- .write_page = mtk_socphy_write_page,
++ .read_page = mtk_phy_read_page,
++ .write_page = mtk_phy_write_page,
+ .led_blink_set = mt798x_phy_led_blink_set,
+ .led_brightness_set = mt798x_phy_led_brightness_set,
+ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+@@ -1354,8 +1344,8 @@ static struct phy_driver mtk_socphy_driv
+ .probe = mt7988_phy_probe,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+- .read_page = mtk_socphy_read_page,
+- .write_page = mtk_socphy_write_page,
++ .read_page = mtk_phy_read_page,
++ .write_page = mtk_phy_write_page,
+ .led_blink_set = mt798x_phy_led_blink_set,
+ .led_brightness_set = mt798x_phy_led_brightness_set,
+ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -3,6 +3,8 @@
+ #include <linux/module.h>
+ #include <linux/phy.h>
+
++#include "mtk.h"
++
+ #define MTK_EXT_PAGE_ACCESS 0x1f
+ #define MTK_PHY_PAGE_STANDARD 0x0000
+ #define MTK_PHY_PAGE_EXTENDED 0x0001
+@@ -11,16 +13,6 @@
+ #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
+ #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+
+-static int mtk_gephy_read_page(struct phy_device *phydev)
+-{
+- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_gephy_write_page(struct phy_device *phydev, int page)
+-{
+- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+ static void mtk_gephy_config_init(struct phy_device *phydev)
+ {
+ /* Enable HW auto downshift */
+@@ -77,8 +69,8 @@ static struct phy_driver mtk_gephy_drive
+ .handle_interrupt = genphy_handle_interrupt_no_ack,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+- .read_page = mtk_gephy_read_page,
+- .write_page = mtk_gephy_write_page,
++ .read_page = mtk_phy_read_page,
++ .write_page = mtk_phy_write_page,
+ },
+ {
+ PHY_ID_MATCH_EXACT(0x03a29441),
+@@ -91,8 +83,8 @@ static struct phy_driver mtk_gephy_drive
+ .handle_interrupt = genphy_handle_interrupt_no_ack,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+- .read_page = mtk_gephy_read_page,
+- .write_page = mtk_gephy_write_page,
++ .read_page = mtk_phy_read_page,
++ .write_page = mtk_phy_write_page,
+ },
+ };
+
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -6,6 +6,18 @@
+
+ #include "mtk.h"
+
++int mtk_phy_read_page(struct phy_device *phydev)
++{
++ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_read_page);
++
++int mtk_phy_write_page(struct phy_device *phydev, int page)
++{
++ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_write_page);
++
+ int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules,
+ unsigned long supported_triggers)
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -66,6 +66,9 @@ struct mtk_socphy_priv {
+ unsigned long led_state;
+ };
+
++int mtk_phy_read_page(struct phy_device *phydev);
++int mtk_phy_write_page(struct phy_device *phydev, int page);
++
+ int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules,
+ unsigned long supported_triggers);
--- /dev/null
+From e6579df175d5b1baa605c82f8e759542262637cf Mon Sep 17 00:00:00 2001
+Date: Sat, 9 Nov 2024 00:34:55 +0800
+Subject: [PATCH 08/20] net: phy: mediatek: add MT7530 & MT7531's PHY ID macros
+
+This patch adds MT7530 & MT7531's PHY ID macros in mtk-ge.c so that
+it follows the same rule of mtk-ge-soc.c.
+
+---
+ drivers/net/phy/mediatek/mtk-ge.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -5,6 +5,9 @@
+
+ #include "mtk.h"
+
++#define MTK_GPHY_ID_MT7530 0x03a29412
++#define MTK_GPHY_ID_MT7531 0x03a29441
++
+ #define MTK_EXT_PAGE_ACCESS 0x1f
+ #define MTK_PHY_PAGE_STANDARD 0x0000
+ #define MTK_PHY_PAGE_EXTENDED 0x0001
+@@ -59,7 +62,7 @@ static int mt7531_phy_config_init(struct
+
+ static struct phy_driver mtk_gephy_driver[] = {
+ {
+- PHY_ID_MATCH_EXACT(0x03a29412),
++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
+ .name = "MediaTek MT7530 PHY",
+ .config_init = mt7530_phy_config_init,
+ /* Interrupts are handled by the switch, not the PHY
+@@ -73,7 +76,7 @@ static struct phy_driver mtk_gephy_drive
+ .write_page = mtk_phy_write_page,
+ },
+ {
+- PHY_ID_MATCH_EXACT(0x03a29441),
++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531),
+ .name = "MediaTek MT7531 PHY",
+ .config_init = mt7531_phy_config_init,
+ /* Interrupts are handled by the switch, not the PHY
+@@ -91,8 +94,8 @@ static struct phy_driver mtk_gephy_drive
+ module_phy_driver(mtk_gephy_driver);
+
+ static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
+- { PHY_ID_MATCH_EXACT(0x03a29441) },
+- { PHY_ID_MATCH_EXACT(0x03a29412) },
++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) },
++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) },
+ { }
+ };
+
--- /dev/null
+From e127f7380aaf2cd1614961d826a4af7ab297d37f Mon Sep 17 00:00:00 2001
+Date: Sun, 12 Jan 2025 15:14:50 +0100
+Subject: [PATCH 09/20] net: phy: Constify struct mdio_device_id
+
+'struct mdio_device_id' is not modified in these drivers.
+
+Constifying these structures moves some data to a read-only section, so
+increase overall security.
+
+On a x86_64, with allmodconfig, as an example:
+Before:
+======
+ text data bss dec hex filename
+ 27014 12792 0 39806 9b7e drivers/net/phy/broadcom.o
+
+After:
+=====
+ text data bss dec hex filename
+ 27206 12600 0 39806 9b7e drivers/net/phy/broadcom.o
+
+Link: https://patch.msgid.link/403c381b7d9156b67ad68ffc44b8eee70c5e86a9.1736691226.git.christophe.jaillet@wanadoo.fr
+---
+ drivers/net/phy/adin.c | 2 +-
+ drivers/net/phy/adin1100.c | 2 +-
+ drivers/net/phy/air_en8811h.c | 2 +-
+ drivers/net/phy/amd.c | 2 +-
+ drivers/net/phy/aquantia/aquantia_main.c | 2 +-
+ drivers/net/phy/ax88796b.c | 2 +-
+ drivers/net/phy/bcm-cygnus.c | 2 +-
+ drivers/net/phy/bcm54140.c | 2 +-
+ drivers/net/phy/bcm63xx.c | 2 +-
+ drivers/net/phy/bcm7xxx.c | 2 +-
+ drivers/net/phy/bcm84881.c | 2 +-
+ drivers/net/phy/broadcom.c | 2 +-
+ drivers/net/phy/cicada.c | 2 +-
+ drivers/net/phy/cortina.c | 2 +-
+ drivers/net/phy/davicom.c | 2 +-
+ drivers/net/phy/dp83640.c | 2 +-
+ drivers/net/phy/dp83822.c | 2 +-
+ drivers/net/phy/dp83848.c | 2 +-
+ drivers/net/phy/dp83867.c | 2 +-
+ drivers/net/phy/dp83869.c | 2 +-
+ drivers/net/phy/dp83tc811.c | 2 +-
+ drivers/net/phy/dp83td510.c | 2 +-
+ drivers/net/phy/dp83tg720.c | 2 +-
+ drivers/net/phy/et1011c.c | 2 +-
+ drivers/net/phy/icplus.c | 2 +-
+ drivers/net/phy/intel-xway.c | 2 +-
+ drivers/net/phy/lxt.c | 2 +-
+ drivers/net/phy/marvell-88q2xxx.c | 2 +-
+ drivers/net/phy/marvell-88x2222.c | 2 +-
+ drivers/net/phy/marvell.c | 2 +-
+ drivers/net/phy/marvell10g.c | 2 +-
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 2 +-
+ drivers/net/phy/mediatek/mtk-ge.c | 2 +-
+ drivers/net/phy/meson-gxl.c | 2 +-
+ drivers/net/phy/micrel.c | 2 +-
+ drivers/net/phy/microchip.c | 2 +-
+ drivers/net/phy/microchip_t1.c | 2 +-
+ drivers/net/phy/microchip_t1s.c | 2 +-
+ drivers/net/phy/mscc/mscc_main.c | 2 +-
+ drivers/net/phy/mxl-gpy.c | 2 +-
+ drivers/net/phy/national.c | 2 +-
+ drivers/net/phy/ncn26000.c | 2 +-
+ drivers/net/phy/nxp-c45-tja11xx.c | 2 +-
+ drivers/net/phy/nxp-cbtx.c | 2 +-
+ drivers/net/phy/nxp-tja11xx.c | 2 +-
+ drivers/net/phy/qcom/at803x.c | 2 +-
+ drivers/net/phy/qcom/qca807x.c | 2 +-
+ drivers/net/phy/qcom/qca808x.c | 2 +-
+ drivers/net/phy/qcom/qca83xx.c | 2 +-
+ drivers/net/phy/qsemi.c | 2 +-
+ drivers/net/phy/rockchip.c | 2 +-
+ drivers/net/phy/smsc.c | 2 +-
+ drivers/net/phy/ste10Xp.c | 2 +-
+ drivers/net/phy/teranetics.c | 2 +-
+ drivers/net/phy/uPD60620.c | 2 +-
+ drivers/net/phy/vitesse.c | 2 +-
+ 56 files changed, 56 insertions(+), 56 deletions(-)
+
+--- a/drivers/net/phy/adin.c
++++ b/drivers/net/phy/adin.c
+@@ -1040,7 +1040,7 @@ static struct phy_driver adin_driver[] =
+
+ module_phy_driver(adin_driver);
+
+-static struct mdio_device_id __maybe_unused adin_tbl[] = {
++static const struct mdio_device_id __maybe_unused adin_tbl[] = {
+ { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1200) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1300) },
+ { }
+--- a/drivers/net/phy/adin1100.c
++++ b/drivers/net/phy/adin1100.c
+@@ -340,7 +340,7 @@ static struct phy_driver adin_driver[] =
+
+ module_phy_driver(adin_driver);
+
+-static struct mdio_device_id __maybe_unused adin_tbl[] = {
++static const struct mdio_device_id __maybe_unused adin_tbl[] = {
+ { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1100) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1110) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_ADIN2111) },
+--- a/drivers/net/phy/air_en8811h.c
++++ b/drivers/net/phy/air_en8811h.c
+@@ -1075,7 +1075,7 @@ static struct phy_driver en8811h_driver[
+
+ module_phy_driver(en8811h_driver);
+
+-static struct mdio_device_id __maybe_unused en8811h_tbl[] = {
++static const struct mdio_device_id __maybe_unused en8811h_tbl[] = {
+ { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) },
+ { }
+ };
+--- a/drivers/net/phy/amd.c
++++ b/drivers/net/phy/amd.c
+@@ -111,7 +111,7 @@ static struct phy_driver am79c_drivers[]
+
+ module_phy_driver(am79c_drivers);
+
+-static struct mdio_device_id __maybe_unused amd_tbl[] = {
++static const struct mdio_device_id __maybe_unused amd_tbl[] = {
+ { PHY_ID_AC101L, 0xfffffff0 },
+ { PHY_ID_AM79C874, 0xfffffff0 },
+ { }
+--- a/drivers/net/phy/aquantia/aquantia_main.c
++++ b/drivers/net/phy/aquantia/aquantia_main.c
+@@ -1096,7 +1096,7 @@ static struct phy_driver aqr_driver[] =
+
+ module_phy_driver(aqr_driver);
+
+-static struct mdio_device_id __maybe_unused aqr_tbl[] = {
++static const struct mdio_device_id __maybe_unused aqr_tbl[] = {
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) },
+--- a/drivers/net/phy/ax88796b.c
++++ b/drivers/net/phy/ax88796b.c
+@@ -121,7 +121,7 @@ static struct phy_driver asix_driver[] =
+
+ module_phy_driver(asix_driver);
+
+-static struct mdio_device_id __maybe_unused asix_tbl[] = {
++static const struct mdio_device_id __maybe_unused asix_tbl[] = {
+ { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A) },
+ { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C) },
+ { PHY_ID_ASIX_AX88796B, 0xfffffff0 },
+--- a/drivers/net/phy/bcm-cygnus.c
++++ b/drivers/net/phy/bcm-cygnus.c
+@@ -278,7 +278,7 @@ static struct phy_driver bcm_cygnus_phy_
+ }
+ };
+
+-static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = {
++static const struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = {
+ { PHY_ID_BCM_CYGNUS, 0xfffffff0, },
+ { PHY_ID_BCM_OMEGA, 0xfffffff0, },
+ { }
+--- a/drivers/net/phy/bcm54140.c
++++ b/drivers/net/phy/bcm54140.c
+@@ -883,7 +883,7 @@ static struct phy_driver bcm54140_driver
+ };
+ module_phy_driver(bcm54140_drivers);
+
+-static struct mdio_device_id __maybe_unused bcm54140_tbl[] = {
++static const struct mdio_device_id __maybe_unused bcm54140_tbl[] = {
+ { PHY_ID_BCM54140, BCM54140_PHY_ID_MASK },
+ { }
+ };
+--- a/drivers/net/phy/bcm63xx.c
++++ b/drivers/net/phy/bcm63xx.c
+@@ -93,7 +93,7 @@ static struct phy_driver bcm63xx_driver[
+
+ module_phy_driver(bcm63xx_driver);
+
+-static struct mdio_device_id __maybe_unused bcm63xx_tbl[] = {
++static const struct mdio_device_id __maybe_unused bcm63xx_tbl[] = {
+ { 0x00406000, 0xfffffc00 },
+ { 0x002bdc00, 0xfffffc00 },
+ { }
+--- a/drivers/net/phy/bcm7xxx.c
++++ b/drivers/net/phy/bcm7xxx.c
+@@ -929,7 +929,7 @@ static struct phy_driver bcm7xxx_driver[
+ BCM7XXX_16NM_EPHY(PHY_ID_BCM7712, "Broadcom BCM7712"),
+ };
+
+-static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
++static const struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
+ { PHY_ID_BCM72113, 0xfffffff0 },
+ { PHY_ID_BCM72116, 0xfffffff0, },
+ { PHY_ID_BCM72165, 0xfffffff0, },
+--- a/drivers/net/phy/bcm84881.c
++++ b/drivers/net/phy/bcm84881.c
+@@ -252,7 +252,7 @@ static struct phy_driver bcm84881_driver
+ module_phy_driver(bcm84881_drivers);
+
+ /* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */
+-static struct mdio_device_id __maybe_unused bcm84881_tbl[] = {
++static const struct mdio_device_id __maybe_unused bcm84881_tbl[] = {
+ { 0xae025150, 0xfffffff0 },
+ { },
+ };
+--- a/drivers/net/phy/broadcom.c
++++ b/drivers/net/phy/broadcom.c
+@@ -1717,7 +1717,7 @@ static struct phy_driver broadcom_driver
+
+ module_phy_driver(broadcom_drivers);
+
+-static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
++static const struct mdio_device_id __maybe_unused broadcom_tbl[] = {
+ { PHY_ID_BCM5411, 0xfffffff0 },
+ { PHY_ID_BCM5421, 0xfffffff0 },
+ { PHY_ID_BCM54210E, 0xfffffff0 },
+--- a/drivers/net/phy/cicada.c
++++ b/drivers/net/phy/cicada.c
+@@ -145,7 +145,7 @@ static struct phy_driver cis820x_driver[
+
+ module_phy_driver(cis820x_driver);
+
+-static struct mdio_device_id __maybe_unused cicada_tbl[] = {
++static const struct mdio_device_id __maybe_unused cicada_tbl[] = {
+ { 0x000fc410, 0x000ffff0 },
+ { 0x000fc440, 0x000fffc0 },
+ { }
+--- a/drivers/net/phy/cortina.c
++++ b/drivers/net/phy/cortina.c
+@@ -87,7 +87,7 @@ static struct phy_driver cortina_driver[
+
+ module_phy_driver(cortina_driver);
+
+-static struct mdio_device_id __maybe_unused cortina_tbl[] = {
++static const struct mdio_device_id __maybe_unused cortina_tbl[] = {
+ { PHY_ID_CS4340, 0xffffffff},
+ {},
+ };
+--- a/drivers/net/phy/davicom.c
++++ b/drivers/net/phy/davicom.c
+@@ -209,7 +209,7 @@ static struct phy_driver dm91xx_driver[]
+
+ module_phy_driver(dm91xx_driver);
+
+-static struct mdio_device_id __maybe_unused davicom_tbl[] = {
++static const struct mdio_device_id __maybe_unused davicom_tbl[] = {
+ { 0x0181b880, 0x0ffffff0 },
+ { 0x0181b8b0, 0x0ffffff0 },
+ { 0x0181b8a0, 0x0ffffff0 },
+--- a/drivers/net/phy/dp83640.c
++++ b/drivers/net/phy/dp83640.c
+@@ -1548,7 +1548,7 @@ MODULE_LICENSE("GPL");
+ module_init(dp83640_init);
+ module_exit(dp83640_exit);
+
+-static struct mdio_device_id __maybe_unused dp83640_tbl[] = {
++static const struct mdio_device_id __maybe_unused dp83640_tbl[] = {
+ { DP83640_PHY_ID, 0xfffffff0 },
+ { }
+ };
+--- a/drivers/net/phy/dp83822.c
++++ b/drivers/net/phy/dp83822.c
+@@ -825,7 +825,7 @@ static struct phy_driver dp83822_driver[
+ };
+ module_phy_driver(dp83822_driver);
+
+-static struct mdio_device_id __maybe_unused dp83822_tbl[] = {
++static const struct mdio_device_id __maybe_unused dp83822_tbl[] = {
+ { DP83822_PHY_ID, 0xfffffff0 },
+ { DP83825I_PHY_ID, 0xfffffff0 },
+ { DP83826C_PHY_ID, 0xfffffff0 },
+--- a/drivers/net/phy/dp83848.c
++++ b/drivers/net/phy/dp83848.c
+@@ -123,7 +123,7 @@ static int dp83848_config_init(struct ph
+ return 0;
+ }
+
+-static struct mdio_device_id __maybe_unused dp83848_tbl[] = {
++static const struct mdio_device_id __maybe_unused dp83848_tbl[] = {
+ { TI_DP83848C_PHY_ID, 0xfffffff0 },
+ { NS_DP83848C_PHY_ID, 0xfffffff0 },
+ { TI_DP83620_PHY_ID, 0xfffffff0 },
+--- a/drivers/net/phy/dp83867.c
++++ b/drivers/net/phy/dp83867.c
+@@ -1210,7 +1210,7 @@ static struct phy_driver dp83867_driver[
+ };
+ module_phy_driver(dp83867_driver);
+
+-static struct mdio_device_id __maybe_unused dp83867_tbl[] = {
++static const struct mdio_device_id __maybe_unused dp83867_tbl[] = {
+ { DP83867_PHY_ID, 0xfffffff0 },
+ { }
+ };
+--- a/drivers/net/phy/dp83869.c
++++ b/drivers/net/phy/dp83869.c
+@@ -928,7 +928,7 @@ static struct phy_driver dp83869_driver[
+ };
+ module_phy_driver(dp83869_driver);
+
+-static struct mdio_device_id __maybe_unused dp83869_tbl[] = {
++static const struct mdio_device_id __maybe_unused dp83869_tbl[] = {
+ { PHY_ID_MATCH_MODEL(DP83869_PHY_ID) },
+ { PHY_ID_MATCH_MODEL(DP83561_PHY_ID) },
+ { }
+--- a/drivers/net/phy/dp83tc811.c
++++ b/drivers/net/phy/dp83tc811.c
+@@ -403,7 +403,7 @@ static struct phy_driver dp83811_driver[
+ };
+ module_phy_driver(dp83811_driver);
+
+-static struct mdio_device_id __maybe_unused dp83811_tbl[] = {
++static const struct mdio_device_id __maybe_unused dp83811_tbl[] = {
+ { DP83TC811_PHY_ID, 0xfffffff0 },
+ { },
+ };
+--- a/drivers/net/phy/dp83td510.c
++++ b/drivers/net/phy/dp83td510.c
+@@ -605,7 +605,7 @@ static struct phy_driver dp83td510_drive
+ } };
+ module_phy_driver(dp83td510_driver);
+
+-static struct mdio_device_id __maybe_unused dp83td510_tbl[] = {
++static const struct mdio_device_id __maybe_unused dp83td510_tbl[] = {
+ { PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID) },
+ { }
+ };
+--- a/drivers/net/phy/dp83tg720.c
++++ b/drivers/net/phy/dp83tg720.c
+@@ -361,7 +361,7 @@ static struct phy_driver dp83tg720_drive
+ } };
+ module_phy_driver(dp83tg720_driver);
+
+-static struct mdio_device_id __maybe_unused dp83tg720_tbl[] = {
++static const struct mdio_device_id __maybe_unused dp83tg720_tbl[] = {
+ { PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID) },
+ { }
+ };
+--- a/drivers/net/phy/et1011c.c
++++ b/drivers/net/phy/et1011c.c
+@@ -94,7 +94,7 @@ static struct phy_driver et1011c_driver[
+
+ module_phy_driver(et1011c_driver);
+
+-static struct mdio_device_id __maybe_unused et1011c_tbl[] = {
++static const struct mdio_device_id __maybe_unused et1011c_tbl[] = {
+ { 0x0282f014, 0xfffffff0 },
+ { }
+ };
+--- a/drivers/net/phy/icplus.c
++++ b/drivers/net/phy/icplus.c
+@@ -624,7 +624,7 @@ static struct phy_driver icplus_driver[]
+
+ module_phy_driver(icplus_driver);
+
+-static struct mdio_device_id __maybe_unused icplus_tbl[] = {
++static const struct mdio_device_id __maybe_unused icplus_tbl[] = {
+ { PHY_ID_MATCH_MODEL(IP175C_PHY_ID) },
+ { PHY_ID_MATCH_MODEL(IP1001_PHY_ID) },
+ { PHY_ID_MATCH_EXACT(IP101A_PHY_ID) },
+--- a/drivers/net/phy/intel-xway.c
++++ b/drivers/net/phy/intel-xway.c
+@@ -456,7 +456,7 @@ static struct phy_driver xway_gphy[] = {
+ };
+ module_phy_driver(xway_gphy);
+
+-static struct mdio_device_id __maybe_unused xway_gphy_tbl[] = {
++static const struct mdio_device_id __maybe_unused xway_gphy_tbl[] = {
+ { PHY_ID_PHY11G_1_3, 0xffffffff },
+ { PHY_ID_PHY22F_1_3, 0xffffffff },
+ { PHY_ID_PHY11G_1_4, 0xffffffff },
+--- a/drivers/net/phy/lxt.c
++++ b/drivers/net/phy/lxt.c
+@@ -348,7 +348,7 @@ static struct phy_driver lxt97x_driver[]
+
+ module_phy_driver(lxt97x_driver);
+
+-static struct mdio_device_id __maybe_unused lxt_tbl[] = {
++static const struct mdio_device_id __maybe_unused lxt_tbl[] = {
+ { 0x78100000, 0xfffffff0 },
+ { 0x001378e0, 0xfffffff0 },
+ { 0x00137a10, 0xfffffff0 },
+--- a/drivers/net/phy/marvell-88q2xxx.c
++++ b/drivers/net/phy/marvell-88q2xxx.c
+@@ -940,7 +940,7 @@ static struct phy_driver mv88q2xxx_drive
+
+ module_phy_driver(mv88q2xxx_driver);
+
+-static struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = {
++static const struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = {
+ { MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88Q2220, MARVELL_PHY_ID_MASK },
+ { /*sentinel*/ }
+--- a/drivers/net/phy/marvell-88x2222.c
++++ b/drivers/net/phy/marvell-88x2222.c
+@@ -613,7 +613,7 @@ static struct phy_driver mv2222_drivers[
+ };
+ module_phy_driver(mv2222_drivers);
+
+-static struct mdio_device_id __maybe_unused mv2222_tbl[] = {
++static const struct mdio_device_id __maybe_unused mv2222_tbl[] = {
+ { MARVELL_PHY_ID_88X2222, MARVELL_PHY_ID_MASK },
+ { }
+ };
+--- a/drivers/net/phy/marvell.c
++++ b/drivers/net/phy/marvell.c
+@@ -4133,7 +4133,7 @@ static struct phy_driver marvell_drivers
+
+ module_phy_driver(marvell_drivers);
+
+-static struct mdio_device_id __maybe_unused marvell_tbl[] = {
++static const struct mdio_device_id __maybe_unused marvell_tbl[] = {
+ { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E3082, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
+--- a/drivers/net/phy/marvell10g.c
++++ b/drivers/net/phy/marvell10g.c
+@@ -1484,7 +1484,7 @@ static struct phy_driver mv3310_drivers[
+
+ module_phy_driver(mv3310_drivers);
+
+-static struct mdio_device_id __maybe_unused mv3310_tbl[] = {
++static const struct mdio_device_id __maybe_unused mv3310_tbl[] = {
+ { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK },
+ { },
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -1356,7 +1356,7 @@ static struct phy_driver mtk_socphy_driv
+
+ module_phy_driver(mtk_socphy_driver);
+
+-static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
++static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
+ { }
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -93,7 +93,7 @@ static struct phy_driver mtk_gephy_drive
+
+ module_phy_driver(mtk_gephy_driver);
+
+-static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
++static const struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) },
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) },
+ { }
+--- a/drivers/net/phy/meson-gxl.c
++++ b/drivers/net/phy/meson-gxl.c
+@@ -221,7 +221,7 @@ static struct phy_driver meson_gxl_phy[]
+ },
+ };
+
+-static struct mdio_device_id __maybe_unused meson_gxl_tbl[] = {
++static const struct mdio_device_id __maybe_unused meson_gxl_tbl[] = {
+ { PHY_ID_MATCH_VENDOR(0x01814400) },
+ { PHY_ID_MATCH_VENDOR(0x01803301) },
+ { }
+--- a/drivers/net/phy/micrel.c
++++ b/drivers/net/phy/micrel.c
+@@ -5691,7 +5691,7 @@ MODULE_DESCRIPTION("Micrel PHY driver");
+ MODULE_AUTHOR("David J. Choi");
+ MODULE_LICENSE("GPL");
+
+-static struct mdio_device_id __maybe_unused micrel_tbl[] = {
++static const struct mdio_device_id __maybe_unused micrel_tbl[] = {
+ { PHY_ID_KSZ9021, 0x000ffffe },
+ { PHY_ID_KSZ9031, MICREL_PHY_ID_MASK },
+ { PHY_ID_KSZ9131, MICREL_PHY_ID_MASK },
+--- a/drivers/net/phy/microchip.c
++++ b/drivers/net/phy/microchip.c
+@@ -508,7 +508,7 @@ static struct phy_driver microchip_phy_d
+
+ module_phy_driver(microchip_phy_driver);
+
+-static struct mdio_device_id __maybe_unused microchip_tbl[] = {
++static const struct mdio_device_id __maybe_unused microchip_tbl[] = {
+ { 0x0007c132, 0xfffffff2 },
+ { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX) },
+ { }
+--- a/drivers/net/phy/microchip_t1.c
++++ b/drivers/net/phy/microchip_t1.c
+@@ -1886,7 +1886,7 @@ static struct phy_driver microchip_t1_ph
+
+ module_phy_driver(microchip_t1_phy_driver);
+
+-static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
++static const struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
+ { PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_LAN887X) },
+--- a/drivers/net/phy/microchip_t1s.c
++++ b/drivers/net/phy/microchip_t1s.c
+@@ -323,7 +323,7 @@ static struct phy_driver microchip_t1s_d
+
+ module_phy_driver(microchip_t1s_driver);
+
+-static struct mdio_device_id __maybe_unused tbl[] = {
++static const struct mdio_device_id __maybe_unused tbl[] = {
+ { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1) },
+ { PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0) },
+ { }
+--- a/drivers/net/phy/mscc/mscc_main.c
++++ b/drivers/net/phy/mscc/mscc_main.c
+@@ -2700,7 +2700,7 @@ static struct phy_driver vsc85xx_driver[
+
+ module_phy_driver(vsc85xx_driver);
+
+-static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
++static const struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
+ { PHY_ID_MATCH_VENDOR(PHY_VENDOR_MSCC) },
+ { }
+ };
+--- a/drivers/net/phy/mxl-gpy.c
++++ b/drivers/net/phy/mxl-gpy.c
+@@ -1047,7 +1047,7 @@ static struct phy_driver gpy_drivers[] =
+ };
+ module_phy_driver(gpy_drivers);
+
+-static struct mdio_device_id __maybe_unused gpy_tbl[] = {
++static const struct mdio_device_id __maybe_unused gpy_tbl[] = {
+ {PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)},
+ {PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK},
+ {PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)},
+--- a/drivers/net/phy/national.c
++++ b/drivers/net/phy/national.c
+@@ -173,7 +173,7 @@ MODULE_DESCRIPTION("NatSemi PHY driver")
+ MODULE_AUTHOR("Stuart Menefy");
+ MODULE_LICENSE("GPL");
+
+-static struct mdio_device_id __maybe_unused ns_tbl[] = {
++static const struct mdio_device_id __maybe_unused ns_tbl[] = {
+ { DP83865_PHY_ID, 0xfffffff0 },
+ { }
+ };
+--- a/drivers/net/phy/ncn26000.c
++++ b/drivers/net/phy/ncn26000.c
+@@ -159,7 +159,7 @@ static struct phy_driver ncn26000_driver
+
+ module_phy_driver(ncn26000_driver);
+
+-static struct mdio_device_id __maybe_unused ncn26000_tbl[] = {
++static const struct mdio_device_id __maybe_unused ncn26000_tbl[] = {
+ { PHY_ID_MATCH_MODEL(PHY_ID_NCN26000) },
+ { }
+ };
+--- a/drivers/net/phy/nxp-c45-tja11xx.c
++++ b/drivers/net/phy/nxp-c45-tja11xx.c
+@@ -2102,7 +2102,7 @@ static struct phy_driver nxp_c45_driver[
+
+ module_phy_driver(nxp_c45_driver);
+
+-static struct mdio_device_id __maybe_unused nxp_c45_tbl[] = {
++static const struct mdio_device_id __maybe_unused nxp_c45_tbl[] = {
+ { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120) },
+ { /*sentinel*/ },
+--- a/drivers/net/phy/nxp-cbtx.c
++++ b/drivers/net/phy/nxp-cbtx.c
+@@ -215,7 +215,7 @@ static struct phy_driver cbtx_driver[] =
+
+ module_phy_driver(cbtx_driver);
+
+-static struct mdio_device_id __maybe_unused cbtx_tbl[] = {
++static const struct mdio_device_id __maybe_unused cbtx_tbl[] = {
+ { PHY_ID_MATCH_MODEL(PHY_ID_CBTX_SJA1110) },
+ { },
+ };
+--- a/drivers/net/phy/nxp-tja11xx.c
++++ b/drivers/net/phy/nxp-tja11xx.c
+@@ -888,7 +888,7 @@ static struct phy_driver tja11xx_driver[
+
+ module_phy_driver(tja11xx_driver);
+
+-static struct mdio_device_id __maybe_unused tja11xx_tbl[] = {
++static const struct mdio_device_id __maybe_unused tja11xx_tbl[] = {
+ { PHY_ID_MATCH_MODEL(PHY_ID_TJA1100) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_TJA1101) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_TJA1102) },
+--- a/drivers/net/phy/qcom/at803x.c
++++ b/drivers/net/phy/qcom/at803x.c
+@@ -1098,7 +1098,7 @@ static struct phy_driver at803x_driver[]
+
+ module_phy_driver(at803x_driver);
+
+-static struct mdio_device_id __maybe_unused atheros_tbl[] = {
++static const struct mdio_device_id __maybe_unused atheros_tbl[] = {
+ { ATH8030_PHY_ID, AT8030_PHY_ID_MASK },
+ { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) },
+ { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
+--- a/drivers/net/phy/qcom/qca807x.c
++++ b/drivers/net/phy/qcom/qca807x.c
+@@ -828,7 +828,7 @@ static struct phy_driver qca807x_drivers
+ };
+ module_phy_driver(qca807x_drivers);
+
+-static struct mdio_device_id __maybe_unused qca807x_tbl[] = {
++static const struct mdio_device_id __maybe_unused qca807x_tbl[] = {
+ { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) },
+ { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) },
+ { }
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -655,7 +655,7 @@ static struct phy_driver qca808x_driver[
+
+ module_phy_driver(qca808x_driver);
+
+-static struct mdio_device_id __maybe_unused qca808x_tbl[] = {
++static const struct mdio_device_id __maybe_unused qca808x_tbl[] = {
+ { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
+ { }
+ };
+--- a/drivers/net/phy/qcom/qca83xx.c
++++ b/drivers/net/phy/qcom/qca83xx.c
+@@ -261,7 +261,7 @@ static struct phy_driver qca83xx_driver[
+
+ module_phy_driver(qca83xx_driver);
+
+-static struct mdio_device_id __maybe_unused qca83xx_tbl[] = {
++static const struct mdio_device_id __maybe_unused qca83xx_tbl[] = {
+ { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
+ { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
+ { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
+--- a/drivers/net/phy/qsemi.c
++++ b/drivers/net/phy/qsemi.c
+@@ -155,7 +155,7 @@ static struct phy_driver qs6612_driver[]
+
+ module_phy_driver(qs6612_driver);
+
+-static struct mdio_device_id __maybe_unused qs6612_tbl[] = {
++static const struct mdio_device_id __maybe_unused qs6612_tbl[] = {
+ { 0x00181440, 0xfffffff0 },
+ { }
+ };
+--- a/drivers/net/phy/rockchip.c
++++ b/drivers/net/phy/rockchip.c
+@@ -188,7 +188,7 @@ static struct phy_driver rockchip_phy_dr
+
+ module_phy_driver(rockchip_phy_driver);
+
+-static struct mdio_device_id __maybe_unused rockchip_phy_tbl[] = {
++static const struct mdio_device_id __maybe_unused rockchip_phy_tbl[] = {
+ { INTERNAL_EPHY_ID, 0xfffffff0 },
+ { }
+ };
+--- a/drivers/net/phy/smsc.c
++++ b/drivers/net/phy/smsc.c
+@@ -837,7 +837,7 @@ MODULE_DESCRIPTION("SMSC PHY driver");
+ MODULE_AUTHOR("Herbert Valerio Riedel");
+ MODULE_LICENSE("GPL");
+
+-static struct mdio_device_id __maybe_unused smsc_tbl[] = {
++static const struct mdio_device_id __maybe_unused smsc_tbl[] = {
+ { 0x0007c0a0, 0xfffffff0 },
+ { 0x0007c0b0, 0xfffffff0 },
+ { 0x0007c0c0, 0xfffffff0 },
+--- a/drivers/net/phy/ste10Xp.c
++++ b/drivers/net/phy/ste10Xp.c
+@@ -124,7 +124,7 @@ static struct phy_driver ste10xp_pdriver
+
+ module_phy_driver(ste10xp_pdriver);
+
+-static struct mdio_device_id __maybe_unused ste10Xp_tbl[] = {
++static const struct mdio_device_id __maybe_unused ste10Xp_tbl[] = {
+ { STE101P_PHY_ID, 0xfffffff0 },
+ { STE100P_PHY_ID, 0xffffffff },
+ { }
+--- a/drivers/net/phy/teranetics.c
++++ b/drivers/net/phy/teranetics.c
+@@ -87,7 +87,7 @@ static struct phy_driver teranetics_driv
+
+ module_phy_driver(teranetics_driver);
+
+-static struct mdio_device_id __maybe_unused teranetics_tbl[] = {
++static const struct mdio_device_id __maybe_unused teranetics_tbl[] = {
+ { PHY_ID_TN2020, 0xffffffff },
+ { }
+ };
+--- a/drivers/net/phy/uPD60620.c
++++ b/drivers/net/phy/uPD60620.c
+@@ -90,7 +90,7 @@ static struct phy_driver upd60620_driver
+
+ module_phy_driver(upd60620_driver);
+
+-static struct mdio_device_id __maybe_unused upd60620_tbl[] = {
++static const struct mdio_device_id __maybe_unused upd60620_tbl[] = {
+ { UPD60620_PHY_ID, 0xfffffffe },
+ { }
+ };
+--- a/drivers/net/phy/vitesse.c
++++ b/drivers/net/phy/vitesse.c
+@@ -674,7 +674,7 @@ static struct phy_driver vsc82xx_driver[
+
+ module_phy_driver(vsc82xx_driver);
+
+-static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
++static const struct mdio_device_id __maybe_unused vitesse_tbl[] = {
+ { PHY_ID_VSC8234, 0x000ffff0 },
+ { PHY_ID_VSC8244, 0x000fffc0 },
+ { PHY_ID_VSC8572, 0x000ffff0 },
--- /dev/null
+From 7e06c3dbfa5f1e39eba92eb79d854fab2a7ad5fe Mon Sep 17 00:00:00 2001
+Date: Thu, 13 Feb 2025 16:05:49 +0800
+Subject: [PATCH 10/20] net: phy: mediatek: Change to more meaningful macros
+
+Replace magic number with more meaningful macros in mtk-ge.c.
+Also, move some common macros into mtk-phy-lib.c.
+
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 1 -
+ drivers/net/phy/mediatek/mtk-ge.c | 71 +++++++++++++++++++++------
+ drivers/net/phy/mediatek/mtk.h | 2 +
+ 3 files changed, 57 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -24,7 +24,6 @@
+ #define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
+
+ #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+
+ #define ANALOG_INTERNAL_OPERATION_MAX_US 20
+ #define TXRESERVE_MIN 0
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -8,18 +8,38 @@
+ #define MTK_GPHY_ID_MT7530 0x03a29412
+ #define MTK_GPHY_ID_MT7531 0x03a29441
+
+-#define MTK_EXT_PAGE_ACCESS 0x1f
+-#define MTK_PHY_PAGE_STANDARD 0x0000
+-#define MTK_PHY_PAGE_EXTENDED 0x0001
+-#define MTK_PHY_PAGE_EXTENDED_2 0x0002
+-#define MTK_PHY_PAGE_EXTENDED_3 0x0003
+-#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
++#define MTK_PHY_PAGE_EXTENDED_1 0x0001
++#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
++#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
++
++#define MTK_PHY_PAGE_EXTENDED_2 0x0002
++#define MTK_PHY_PAGE_EXTENDED_3 0x0003
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11
++
++#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
++
++/* Registers on MDIO_MMD_VEND1 */
++#define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13
++#define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14
++#define MTK_TX_DELAY_PAIR_B_MASK GENMASK(10, 8)
++#define MTK_TX_DELAY_PAIR_D_MASK GENMASK(2, 0)
++
++#define MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL 0xa6
++#define MTK_MCC_NEARECHO_OFFSET_MASK GENMASK(15, 8)
++
++#define MTK_PHY_RXADC_CTRL_RG7 0xc6
++#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123 0x123
++#define MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK GENMASK(15, 8)
++#define MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK GENMASK(7, 0)
+
+ static void mtk_gephy_config_init(struct phy_device *phydev)
+ {
+ /* Enable HW auto downshift */
+- phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
++ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
++ MTK_PHY_AUX_CTRL_AND_STATUS,
++ 0, MTK_PHY_ENABLE_DOWNSHIFT);
+
+ /* Increase SlvDPSready time */
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+@@ -29,10 +49,20 @@ static void mtk_gephy_config_init(struct
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ /* Adjust 100_mse_threshold */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
+-
+- /* Disable mcc */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123,
++ MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK |
++ MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK,
++ 0xff) |
++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
++ 0xff));
++
++ /* If echo time is narrower than 0x3, it will be regarded as noise */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL,
++ MTK_MCC_NEARECHO_OFFSET_MASK,
++ FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3));
+ }
+
+ static int mt7530_phy_config_init(struct phy_device *phydev)
+@@ -40,7 +70,8 @@ static int mt7530_phy_config_init(struct
+ mtk_gephy_config_init(phydev);
+
+ /* Increase post_update_timer */
+- phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
++ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3,
++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11, 0x4b);
+
+ return 0;
+ }
+@@ -51,11 +82,19 @@ static int mt7531_phy_config_init(struct
+
+ /* PHY link down power saving enable */
+ phy_set_bits(phydev, 0x17, BIT(4));
+- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
++ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK,
++ FIELD_PREP(MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3));
+
+ /* Set TX Pair delay selection */
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_GBE_MODE_TX_DELAY_SEL,
++ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
++ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
++ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TEST_MODE_TX_DELAY_SEL,
++ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
++ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
++ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
+
+ return 0;
+ }
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -9,6 +9,8 @@
+ #define _MTK_EPHY_H_
+
+ #define MTK_EXT_PAGE_ACCESS 0x1f
++#define MTK_PHY_PAGE_STANDARD 0x0000
++#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+
+ /* Registers on MDIO_MMD_VEND2 */
+ #define MTK_PHY_LED0_ON_CTRL 0x24
--- /dev/null
+From 6e7370079669b0d55c9464bb7c3fb8fb7368b912 Mon Sep 17 00:00:00 2001
+Date: Thu, 13 Feb 2025 16:05:50 +0800
+Subject: [PATCH 11/20] net: phy: mediatek: Add token ring access helper
+ functions in mtk-phy-lib
+
+This patch adds TR(token ring) manipulations and adds correct
+macro names for those magic numbers. TR is a way to access
+proprietary registers on page 52b5. Use these helper functions
+so we can see which fields we're going to modify/set/clear.
+
+TR functions with __* prefix mean that the operations inside
+aren't wrapped by page select/restore functions.
+
+This patch doesn't really change registers' settings but just
+enhances readability and maintainability.
+
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 231 +++++++++++++++++--------
+ drivers/net/phy/mediatek/mtk-ge.c | 11 +-
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 63 +++++++
+ drivers/net/phy/mediatek/mtk.h | 5 +
+ 4 files changed, 230 insertions(+), 80 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -25,6 +25,90 @@
+
+ #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
+
++/* Registers on Token Ring debug nodes */
++/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */
++/* NormMseLoThresh */
++#define NORMAL_MSE_LO_THRESH_MASK GENMASK(15, 8)
++
++/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
++/* RemAckCntLimitCtrl */
++#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK GENMASK(2, 1)
++
++/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */
++/* VcoSlicerThreshBitsHigh */
++#define VCO_SLICER_THRESH_HIGH_MASK GENMASK(23, 0)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */
++/* DfeTailEnableVgaThresh1000 */
++#define DFE_TAIL_EANBLE_VGA_TRHESH_1000 GENMASK(5, 1)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */
++/* MrvlTrFix100Kp */
++#define MRVL_TR_FIX_100KP_MASK GENMASK(22, 20)
++/* MrvlTrFix100Kf */
++#define MRVL_TR_FIX_100KF_MASK GENMASK(19, 17)
++/* MrvlTrFix1000Kp */
++#define MRVL_TR_FIX_1000KP_MASK GENMASK(16, 14)
++/* MrvlTrFix1000Kf */
++#define MRVL_TR_FIX_1000KF_MASK GENMASK(13, 11)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */
++/* VgaDecRate */
++#define VGA_DECIMATION_RATE_MASK GENMASK(8, 5)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
++/* SlvDSPreadyTime */
++#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15)
++/* MasDSPreadyTime */
++#define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
++/* ResetSyncOffset */
++#define RESET_SYNC_OFFSET_MASK GENMASK(11, 8)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */
++/* FfeUpdGainForceVal */
++#define FFE_UPDATE_GAIN_FORCE_VAL_MASK GENMASK(9, 7)
++/* FfeUpdGainForce */
++#define FFE_UPDATE_GAIN_FORCE BIT(6)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
++/* SS: Steady-state, KP: Proportional Gain */
++/* SSTrKp100 */
++#define SS_TR_KP100_MASK GENMASK(21, 19)
++/* SSTrKf100 */
++#define SS_TR_KF100_MASK GENMASK(18, 16)
++/* SSTrKp1000Mas */
++#define SS_TR_KP1000_MASTER_MASK GENMASK(15, 13)
++/* SSTrKf1000Mas */
++#define SS_TR_KF1000_MASTER_MASK GENMASK(12, 10)
++/* SSTrKp1000Slv */
++#define SS_TR_KP1000_SLAVE_MASK GENMASK(9, 7)
++/* SSTrKf1000Slv */
++#define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
++/* RegEEE_st2TrKf1000 */
++#define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */
++/* RegEEE_slv_waketr_timer_tar */
++#define SLAVE_WAKETR_TIMER_MASK GENMASK(20, 11)
++/* RegEEE_slv_remtx_timer_tar */
++#define SLAVE_REMTX_TIMER_MASK GENMASK(10, 1)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */
++/* RegEEE_slv_wake_int_timer_tar */
++#define SLAVE_WAKEINT_TIMER_MASK GENMASK(10, 1)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */
++/* RegEEE_trfreeze_timer2 */
++#define TR_FREEZE_TIMER2_MASK GENMASK(9, 0)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */
++/* RegEEE100Stg1_tar */
++#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0)
++
+ #define ANALOG_INTERNAL_OPERATION_MAX_US 20
+ #define TXRESERVE_MIN 0
+ #define TXRESERVE_MAX 7
+@@ -700,40 +784,41 @@ restore:
+ static void mt798x_phy_common_finetune(struct phy_device *phydev)
+ {
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
+- __phy_write(phydev, 0x11, 0xc71);
+- __phy_write(phydev, 0x12, 0xc);
+- __phy_write(phydev, 0x10, 0x8fae);
++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x17,
++ SLAVE_DSP_READY_TIME_MASK | MASTER_DSP_READY_TIME_MASK,
++ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) |
++ FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18));
+
+ /* EnabRandUpdTrig = 1 */
+ __phy_write(phydev, 0x11, 0x2f00);
+ __phy_write(phydev, 0x12, 0xe);
+ __phy_write(phydev, 0x10, 0x8fb0);
+
+- /* NormMseLoThresh = 85 */
+- __phy_write(phydev, 0x11, 0x55a0);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x83aa);
+-
+- /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
+- __phy_write(phydev, 0x11, 0x240);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x9680);
++ __mtk_tr_modify(phydev, 0x0, 0x7, 0x15,
++ NORMAL_MSE_LO_THRESH_MASK,
++ FIELD_PREP(NORMAL_MSE_LO_THRESH_MASK, 0x55));
++
++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x0,
++ FFE_UPDATE_GAIN_FORCE_VAL_MASK,
++ FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) |
++ FFE_UPDATE_GAIN_FORCE);
+
+ /* TrFreeze = 0 (mt7988 default) */
+ __phy_write(phydev, 0x11, 0x0);
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x9686);
+
+- /* SSTrKp100 = 5 */
+- /* SSTrKf100 = 6 */
+- /* SSTrKp1000Mas = 5 */
+- /* SSTrKf1000Mas = 6 */
+- /* SSTrKp1000Slv = 5 */
+- /* SSTrKf1000Slv = 6 */
+- __phy_write(phydev, 0x11, 0xbaef);
+- __phy_write(phydev, 0x12, 0x2e);
+- __phy_write(phydev, 0x10, 0x968c);
++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x6,
++ SS_TR_KP100_MASK | SS_TR_KF100_MASK |
++ SS_TR_KP1000_MASTER_MASK | SS_TR_KF1000_MASTER_MASK |
++ SS_TR_KP1000_SLAVE_MASK | SS_TR_KF1000_SLAVE_MASK,
++ FIELD_PREP(SS_TR_KP100_MASK, 0x5) |
++ FIELD_PREP(SS_TR_KF100_MASK, 0x6) |
++ FIELD_PREP(SS_TR_KP1000_MASTER_MASK, 0x5) |
++ FIELD_PREP(SS_TR_KF1000_MASTER_MASK, 0x6) |
++ FIELD_PREP(SS_TR_KP1000_SLAVE_MASK, 0x5) |
++ FIELD_PREP(SS_TR_KF1000_SLAVE_MASK, 0x6));
++
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+ }
+
+@@ -756,27 +841,29 @@ static void mt7981_phy_finetune(struct p
+ }
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- /* ResetSyncOffset = 6 */
+- __phy_write(phydev, 0x11, 0x600);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x8fc0);
+-
+- /* VgaDecRate = 1 */
+- __phy_write(phydev, 0x11, 0x4c2a);
+- __phy_write(phydev, 0x12, 0x3e);
+- __phy_write(phydev, 0x10, 0x8fa4);
++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
++ RESET_SYNC_OFFSET_MASK,
++ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x6));
++
++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x12,
++ VGA_DECIMATION_RATE_MASK,
++ FIELD_PREP(VGA_DECIMATION_RATE_MASK, 0x1));
+
+ /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
+ * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
+ */
+- __phy_write(phydev, 0x11, 0xd10a);
+- __phy_write(phydev, 0x12, 0x34);
+- __phy_write(phydev, 0x10, 0x8f82);
++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
++ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
++ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
++ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x3) |
++ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x2) |
++ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x3) |
++ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x2));
+
+ /* VcoSlicerThreshBitsHigh */
+- __phy_write(phydev, 0x11, 0x5555);
+- __phy_write(phydev, 0x12, 0x55);
+- __phy_write(phydev, 0x10, 0x8ec0);
++ __mtk_tr_modify(phydev, 0x1, 0xd, 0x20,
++ VCO_SLICER_THRESH_HIGH_MASK,
++ FIELD_PREP(VCO_SLICER_THRESH_HIGH_MASK, 0x555555));
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
+@@ -828,25 +915,23 @@ static void mt7988_phy_finetune(struct p
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- /* ResetSyncOffset = 5 */
+- __phy_write(phydev, 0x11, 0x500);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x8fc0);
++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
++ RESET_SYNC_OFFSET_MASK,
++ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x5));
+
+ /* VgaDecRate is 1 at default on mt7988 */
+
+- /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
+- * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
+- */
+- __phy_write(phydev, 0x11, 0xb90a);
+- __phy_write(phydev, 0x12, 0x6f);
+- __phy_write(phydev, 0x10, 0x8f82);
+-
+- /* RemAckCntLimitCtrl = 1 */
+- __phy_write(phydev, 0x11, 0xfbba);
+- __phy_write(phydev, 0x12, 0xc3);
+- __phy_write(phydev, 0x10, 0x87f8);
+-
++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
++ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
++ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
++ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x6) |
++ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x7) |
++ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x6) |
++ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x7));
++
++ __mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
++ REMOTE_ACK_COUNT_LIMIT_CTRL_MASK,
++ FIELD_PREP(REMOTE_ACK_COUNT_LIMIT_CTRL_MASK, 0x1));
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+@@ -927,40 +1012,36 @@ static void mt798x_phy_eee(struct phy_de
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x9690);
+
+- /* REG_EEE_st2TrKf1000 = 2 */
+- __phy_write(phydev, 0x11, 0x114f);
+- __phy_write(phydev, 0x12, 0x2);
+- __phy_write(phydev, 0x10, 0x969a);
+-
+- /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
+- __phy_write(phydev, 0x11, 0x3028);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x969e);
+-
+- /* RegEEE_slv_wake_int_timer_tar = 8 */
+- __phy_write(phydev, 0x11, 0x5010);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x96a0);
+-
+- /* RegEEE_trfreeze_timer2 = 586 */
+- __phy_write(phydev, 0x11, 0x24a);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x96a8);
+-
+- /* RegEEE100Stg1_tar = 16 */
+- __phy_write(phydev, 0x11, 0x3210);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x96b8);
++ __mtk_tr_modify(phydev, 0x2, 0xd, 0xd,
++ EEE1000_STAGE2_TR_KF_MASK,
++ FIELD_PREP(EEE1000_STAGE2_TR_KF_MASK, 0x2));
++
++ __mtk_tr_modify(phydev, 0x2, 0xd, 0xf,
++ SLAVE_WAKETR_TIMER_MASK | SLAVE_REMTX_TIMER_MASK,
++ FIELD_PREP(SLAVE_WAKETR_TIMER_MASK, 0x6) |
++ FIELD_PREP(SLAVE_REMTX_TIMER_MASK, 0x14));
++
++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x10,
++ SLAVE_WAKEINT_TIMER_MASK,
++ FIELD_PREP(SLAVE_WAKEINT_TIMER_MASK, 0x8));
++
++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x14,
++ TR_FREEZE_TIMER2_MASK,
++ FIELD_PREP(TR_FREEZE_TIMER2_MASK, 0x24a));
++
++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x1c,
++ EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
++ FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
++ 0x10));
+
+ /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
+ __phy_write(phydev, 0x11, 0x1463);
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x96ca);
+
+- /* DfeTailEnableVgaThresh1000 = 27 */
+- __phy_write(phydev, 0x11, 0x36);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x8f80);
++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x0,
++ DFE_TAIL_EANBLE_VGA_TRHESH_1000,
++ FIELD_PREP(DFE_TAIL_EANBLE_VGA_TRHESH_1000, 0x1b));
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -18,6 +18,10 @@
+
+ #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
+
++/* Registers on Token Ring debug nodes */
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
++#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15)
++
+ /* Registers on MDIO_MMD_VEND1 */
+ #define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13
+ #define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14
+@@ -42,11 +46,8 @@ static void mtk_gephy_config_init(struct
+ 0, MTK_PHY_ENABLE_DOWNSHIFT);
+
+ /* Increase SlvDPSready time */
+- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- __phy_write(phydev, 0x10, 0xafae);
+- __phy_write(phydev, 0x12, 0x2f);
+- __phy_write(phydev, 0x10, 0x8fae);
+- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++ mtk_tr_modify(phydev, 0x1, 0xf, 0x17, SLAVE_DSP_READY_TIME_MASK,
++ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x5e));
+
+ /* Adjust 100_mse_threshold */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -6,6 +6,69 @@
+
+ #include "mtk.h"
+
++/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is
++ * mtk_tr* functions: wrapped by page switching operations
++ * __mtk_tr* functions: no page switching operations
++ */
++
++static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr,
++ u8 node_addr, u8 data_addr)
++{
++ u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */
++
++ if (read)
++ tr_cmd |= BIT(13);
++
++ tr_cmd |= (((ch_addr & 0x3) << 11) |
++ ((node_addr & 0xf) << 7) |
++ ((data_addr & 0x3f) << 1));
++ dev_dbg(&phydev->mdio.dev, "tr_cmd: 0x%x\n", tr_cmd);
++ __phy_write(phydev, 0x10, tr_cmd);
++}
++
++static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u16 *tr_high, u16 *tr_low)
++{
++ __mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr);
++ *tr_low = __phy_read(phydev, 0x11);
++ *tr_high = __phy_read(phydev, 0x12);
++ dev_dbg(&phydev->mdio.dev, "tr_high read: 0x%x, tr_low read: 0x%x\n",
++ *tr_high, *tr_low);
++}
++
++static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u32 tr_data)
++{
++ __phy_write(phydev, 0x11, tr_data & 0xffff);
++ __phy_write(phydev, 0x12, tr_data >> 16);
++ dev_dbg(&phydev->mdio.dev, "tr_high write: 0x%x, tr_low write: 0x%x\n",
++ tr_data >> 16, tr_data & 0xffff);
++ __mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr);
++}
++
++void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u32 mask, u32 set)
++{
++ u32 tr_data;
++ u16 tr_high;
++ u16 tr_low;
++
++ __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low);
++ tr_data = (tr_high << 16) | tr_low;
++ tr_data = (tr_data & ~mask) | set;
++ __mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data);
++}
++EXPORT_SYMBOL_GPL(__mtk_tr_modify);
++
++void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u32 mask, u32 set)
++{
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set);
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++}
++EXPORT_SYMBOL_GPL(mtk_tr_modify);
++
+ int mtk_phy_read_page(struct phy_device *phydev)
+ {
+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -68,6 +68,11 @@ struct mtk_socphy_priv {
+ unsigned long led_state;
+ };
+
++void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u32 mask, u32 set);
++void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u32 mask, u32 set);
++
+ int mtk_phy_read_page(struct phy_device *phydev);
+ int mtk_phy_write_page(struct phy_device *phydev, int page);
+
--- /dev/null
+From c7e2fb3421ef5ebbb4c91f44bd735ab10edd755a Mon Sep 17 00:00:00 2001
+Date: Thu, 13 Feb 2025 16:05:51 +0800
+Subject: [PATCH 12/20] net: phy: mediatek: Add token ring set bit operation
+ support
+
+Previously in mtk-ge-soc.c, we set some register bits via token
+ring, which were implemented in three __phy_write().
+Now we can do the same thing via __mtk_tr_set_bits() helper.
+
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 10 ++++++----
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 7 +++++++
+ drivers/net/phy/mediatek/mtk.h | 2 ++
+ 3 files changed, 15 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -62,6 +62,10 @@
+ /* MasDSPreadyTime */
+ #define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7)
+
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */
++/* EnabRandUpdTrig */
++#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER BIT(8)
++
+ /* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
+ /* ResetSyncOffset */
+ #define RESET_SYNC_OFFSET_MASK GENMASK(11, 8)
+@@ -789,10 +793,8 @@ static void mt798x_phy_common_finetune(s
+ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) |
+ FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18));
+
+- /* EnabRandUpdTrig = 1 */
+- __phy_write(phydev, 0x11, 0x2f00);
+- __phy_write(phydev, 0x12, 0xe);
+- __phy_write(phydev, 0x10, 0x8fb0);
++ __mtk_tr_set_bits(phydev, 0x1, 0xf, 0x18,
++ ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER);
+
+ __mtk_tr_modify(phydev, 0x0, 0x7, 0x15,
+ NORMAL_MSE_LO_THRESH_MASK,
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -69,6 +69,13 @@ void mtk_tr_modify(struct phy_device *ph
+ }
+ EXPORT_SYMBOL_GPL(mtk_tr_modify);
+
++void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u32 set)
++{
++ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set);
++}
++EXPORT_SYMBOL_GPL(__mtk_tr_set_bits);
++
+ int mtk_phy_read_page(struct phy_device *phydev)
+ {
+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -72,6 +72,8 @@ void __mtk_tr_modify(struct phy_device *
+ u8 data_addr, u32 mask, u32 set);
+ void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 mask, u32 set);
++void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u32 set);
+
+ int mtk_phy_read_page(struct phy_device *phydev);
+ int mtk_phy_write_page(struct phy_device *phydev, int page);
--- /dev/null
+From 7851c73a416b15aff6f9ada9c88affc5f48ff011 Mon Sep 17 00:00:00 2001
+Date: Thu, 13 Feb 2025 16:05:52 +0800
+Subject: [PATCH 13/20] net: phy: mediatek: Add token ring clear bit operation
+ support
+
+Similar to __mtk_tr_set_bits() support. Previously in mtk-ge-soc.c,
+we clear some register bits via token ring, which were also implemented
+in three __phy_write(). Now we can do the same thing via
+__mtk_tr_clr_bits() helper.
+
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 30 +++++++++++++++-----------
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 7 ++++++
+ drivers/net/phy/mediatek/mtk.h | 2 ++
+ 3 files changed, 27 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -76,6 +76,10 @@
+ /* FfeUpdGainForce */
+ #define FFE_UPDATE_GAIN_FORCE BIT(6)
+
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */
++/* TrFreeze */
++#define TR_FREEZE_MASK GENMASK(11, 0)
++
+ /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
+ /* SS: Steady-state, KP: Proportional Gain */
+ /* SSTrKp100 */
+@@ -91,6 +95,11 @@
+ /* SSTrKf1000Slv */
+ #define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4)
+
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */
++/* clear this bit if wanna select from AFE */
++/* Regsigdet_sel_1000 */
++#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE BIT(4)
++
+ /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
+ /* RegEEE_st2TrKf1000 */
+ #define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11)
+@@ -113,6 +122,10 @@
+ /* RegEEE100Stg1_tar */
+ #define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0)
+
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */
++/* REGEEE_wake_slv_tr_wait_dfesigdet_en */
++#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN BIT(11)
++
+ #define ANALOG_INTERNAL_OPERATION_MAX_US 20
+ #define TXRESERVE_MIN 0
+ #define TXRESERVE_MAX 7
+@@ -805,10 +818,7 @@ static void mt798x_phy_common_finetune(s
+ FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) |
+ FFE_UPDATE_GAIN_FORCE);
+
+- /* TrFreeze = 0 (mt7988 default) */
+- __phy_write(phydev, 0x11, 0x0);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x9686);
++ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x3, TR_FREEZE_MASK);
+
+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x6,
+ SS_TR_KP100_MASK | SS_TR_KF100_MASK |
+@@ -1009,10 +1019,8 @@ static void mt798x_phy_eee(struct phy_de
+ MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- /* Regsigdet_sel_1000 = 0 */
+- __phy_write(phydev, 0x11, 0xb);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x9690);
++ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x8,
++ EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE);
+
+ __mtk_tr_modify(phydev, 0x2, 0xd, 0xd,
+ EEE1000_STAGE2_TR_KF_MASK,
+@@ -1036,10 +1044,8 @@ static void mt798x_phy_eee(struct phy_de
+ FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
+ 0x10));
+
+- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
+- __phy_write(phydev, 0x11, 0x1463);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x96ca);
++ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x25,
++ WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN);
+
+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x0,
+ DFE_TAIL_EANBLE_VGA_TRHESH_1000,
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -76,6 +76,13 @@ void __mtk_tr_set_bits(struct phy_device
+ }
+ EXPORT_SYMBOL_GPL(__mtk_tr_set_bits);
+
++void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u32 clr)
++{
++ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0);
++}
++EXPORT_SYMBOL_GPL(__mtk_tr_clr_bits);
++
+ int mtk_phy_read_page(struct phy_device *phydev)
+ {
+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -74,6 +74,8 @@ void mtk_tr_modify(struct phy_device *ph
+ u8 data_addr, u32 mask, u32 set);
+ void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 set);
++void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++ u8 data_addr, u32 clr);
+
+ int mtk_phy_read_page(struct phy_device *phydev);
+ int mtk_phy_write_page(struct phy_device *phydev, int page);
--- /dev/null
+From bae8c61522c4d5a5250a24dcb57d120ea593fab1 Mon Sep 17 00:00:00 2001
+Date: Thu, 13 Feb 2025 16:05:53 +0800
+Subject: [PATCH 14/20] net: phy: mediatek: Move some macros to phy-lib for
+ later use
+
+Move some macros to phy-lib because MediaTek's 2.5G built-in
+ethernet PHY will also use them.
+
+---
+ drivers/net/phy/mediatek/mtk-ge.c | 4 ----
+ drivers/net/phy/mediatek/mtk.h | 4 ++++
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -8,10 +8,6 @@
+ #define MTK_GPHY_ID_MT7530 0x03a29412
+ #define MTK_GPHY_ID_MT7531 0x03a29441
+
+-#define MTK_PHY_PAGE_EXTENDED_1 0x0001
+-#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
+-#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
+-
+ #define MTK_PHY_PAGE_EXTENDED_2 0x0002
+ #define MTK_PHY_PAGE_EXTENDED_3 0x0003
+ #define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -8,7 +8,11 @@
+ #ifndef _MTK_EPHY_H_
+ #define _MTK_EPHY_H_
+
++#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
++#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
++
+ #define MTK_EXT_PAGE_ACCESS 0x1f
++#define MTK_PHY_PAGE_EXTENDED_1 0x0001
+ #define MTK_PHY_PAGE_STANDARD 0x0000
+ #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+
--- /dev/null
+From e5566162af8b9690e096d2e6089e4ed955a0d13d Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Apr 2025 12:04:03 +0200
+Subject: [PATCH] net: phy: mediatek: permit to compile test GE SOC PHY driver
+
+When commit 462a3daad679 ("net: phy: mediatek: fix compile-test
+dependencies") fixed the dependency, it should have also introduced
+an or on COMPILE_TEST to permit this driver to be compile-tested even if
+NVMEM_MTK_EFUSE wasn't selected. The driver makes use of NVMEM API that
+are always compiled (return error) so the driver can actually be
+compiled even without that config.
+
+Fix and simplify the dependency condition of this kernel config.
+
+Fixes: 462a3daad679 ("net: phy: mediatek: fix compile-test dependencies")
+---
+ drivers/net/phy/mediatek/Kconfig | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/phy/mediatek/Kconfig
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -15,8 +15,7 @@ config MEDIATEK_GE_PHY
+
+ config MEDIATEK_GE_SOC_PHY
+ tristate "MediaTek SoC Ethernet PHYs"
+- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
+- depends on NVMEM_MTK_EFUSE
++ depends on (ARM64 && ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST
+ select MTK_NET_PHYLIB
+ help
+ Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
--- /dev/null
+From 4590c8bc10951feee3e439bf7fff1b458c2e6fad Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Apr 2025 12:04:04 +0200
+Subject: [PATCH 17/20] net: phy: mediatek: add Airoha PHY ID to SoC driver
+
+Airoha AN7581 SoC ship with a Switch based on the MT753x Switch embedded
+in other SoC like the MT7581 and the MT7988. Similar to these they
+require configuring some pin to enable LED PHYs.
+
+Add support for the PHY ID for the Airoha embedded Switch and define a
+simple probe function to toggle these pins. Also fill the LED functions
+and add dedicated function to define LED polarity.
+
+---
+ drivers/net/phy/mediatek/Kconfig | 4 +-
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 62 +++++++++++++++++++++++++++
+ 2 files changed, 65 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/mediatek/Kconfig
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -15,7 +15,9 @@ config MEDIATEK_GE_PHY
+
+ config MEDIATEK_GE_SOC_PHY
+ tristate "MediaTek SoC Ethernet PHYs"
+- depends on (ARM64 && ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST
++ depends on ARM64 || COMPILE_TEST
++ depends on ARCH_AIROHA || (ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || \
++ COMPILE_TEST
+ select MTK_NET_PHYLIB
+ help
+ Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -10,8 +10,11 @@
+
+ #include "mtk.h"
+
++#define MTK_PHY_MAX_LEDS 2
++
+ #define MTK_GPHY_ID_MT7981 0x03a29461
+ #define MTK_GPHY_ID_MT7988 0x03a29481
++#define MTK_GPHY_ID_AN7581 0x03a294c1
+
+ #define MTK_EXT_PAGE_ACCESS 0x1f
+ #define MTK_PHY_PAGE_STANDARD 0x0000
+@@ -1405,6 +1408,53 @@ static int mt7981_phy_probe(struct phy_d
+ return mt798x_phy_calibration(phydev);
+ }
+
++static int an7581_phy_probe(struct phy_device *phydev)
++{
++ struct mtk_socphy_priv *priv;
++ struct pinctrl *pinctrl;
++
++ /* Toggle pinctrl to enable PHY LED */
++ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
++ if (IS_ERR(pinctrl))
++ dev_err(&phydev->mdio.bus->dev,
++ "Failed to setup PHY LED pinctrl\n");
++
++ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ phydev->priv = priv;
++
++ return 0;
++}
++
++static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,
++ unsigned long modes)
++{
++ u32 mode;
++ u16 val;
++
++ if (index >= MTK_PHY_MAX_LEDS)
++ return -EINVAL;
++
++ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
++ switch (mode) {
++ case PHY_LED_ACTIVE_LOW:
++ val = MTK_PHY_LED_ON_POLARITY;
++ break;
++ case PHY_LED_ACTIVE_HIGH:
++ val = 0;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++ MTK_PHY_LED_ON_POLARITY, val);
++}
++
+ static struct phy_driver mtk_socphy_driver[] = {
+ {
+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
+@@ -1440,6 +1490,17 @@ static struct phy_driver mtk_socphy_driv
+ .led_hw_control_set = mt798x_phy_led_hw_control_set,
+ .led_hw_control_get = mt798x_phy_led_hw_control_get,
+ },
++ {
++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581),
++ .name = "Airoha AN7581 PHY",
++ .probe = an7581_phy_probe,
++ .led_blink_set = mt798x_phy_led_blink_set,
++ .led_brightness_set = mt798x_phy_led_brightness_set,
++ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
++ .led_hw_control_set = mt798x_phy_led_hw_control_set,
++ .led_hw_control_get = mt798x_phy_led_hw_control_get,
++ .led_polarity_set = an7581_phy_led_polarity_set,
++ },
+ };
+
+ module_phy_driver(mtk_socphy_driver);
+@@ -1447,6 +1508,7 @@ module_phy_driver(mtk_socphy_driver);
+ static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581) },
+ { }
+ };
+
--- /dev/null
+From 34501d047ac0a6cbb13285ba9d15f75c1deb7da7 Mon Sep 17 00:00:00 2001
+Date: Tue, 15 Apr 2025 12:53:05 +0200
+Subject: [PATCH 18/20] net: phy: mediatek: init val in .phy_led_polarity_set
+ for AN7581
+
+Fix smatch warning for uninitialised val in .phy_led_polarity_set for
+AN7581 driver.
+
+Correctly init to 0 to set polarity high by default.
+
+Fixes: 6a325aed130b ("net: phy: mediatek: add Airoha PHY ID to SoC driver")
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -1431,8 +1431,8 @@ static int an7581_phy_probe(struct phy_d
+ static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,
+ unsigned long modes)
+ {
++ u16 val = 0;
+ u32 mode;
+- u16 val;
+
+ if (index >= MTK_PHY_MAX_LEDS)
+ return -EINVAL;
+@@ -1443,7 +1443,6 @@ static int an7581_phy_led_polarity_set(s
+ val = MTK_PHY_LED_ON_POLARITY;
+ break;
+ case PHY_LED_ACTIVE_HIGH:
+- val = 0;
+ break;
+ default:
+ return -EINVAL;
+++ /dev/null
-From 277f96c1f3f71d6e1d3bcf650d7cd84c1442210f Mon Sep 17 00:00:00 2001
-Date: Thu, 17 Oct 2024 11:22:11 +0800
-Subject: [PATCH 01/20] net: phy: mediatek-ge-soc: Fix coding style
-
-This patch fixes spelling errors, re-arrange vars with
-reverse Xmas tree and remove unnecessary parens in
-mediatek-ge-soc.c.
-
----
- drivers/net/phy/mediatek-ge-soc.c | 36 ++++++++++++++++---------------
- 1 file changed, 19 insertions(+), 17 deletions(-)
-
---- a/drivers/net/phy/mediatek-ge-soc.c
-+++ b/drivers/net/phy/mediatek-ge-soc.c
-@@ -408,16 +408,17 @@ static int tx_offset_cal_efuse(struct ph
-
- static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
- {
-- int i;
-- int bias[16] = {};
-- const int vals_9461[16] = { 7, 1, 4, 7,
-- 7, 1, 4, 7,
-- 7, 1, 4, 7,
-- 7, 1, 4, 7 };
- const int vals_9481[16] = { 10, 6, 6, 10,
- 10, 6, 6, 10,
- 10, 6, 6, 10,
- 10, 6, 6, 10 };
-+ const int vals_9461[16] = { 7, 1, 4, 7,
-+ 7, 1, 4, 7,
-+ 7, 1, 4, 7,
-+ 7, 1, 4, 7 };
-+ int bias[16] = {};
-+ int i;
-+
- switch (phydev->drv->phy_id) {
- case MTK_GPHY_ID_MT7981:
- /* We add some calibration to efuse values
-@@ -1069,10 +1070,10 @@ static int start_cal(struct phy_device *
-
- static int mt798x_phy_calibration(struct phy_device *phydev)
- {
-+ struct nvmem_cell *cell;
- int ret = 0;
-- u32 *buf;
- size_t len;
-- struct nvmem_cell *cell;
-+ u32 *buf;
-
- cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
- if (IS_ERR(cell)) {
-@@ -1210,14 +1211,15 @@ static int mt798x_phy_led_brightness_set
- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
- }
-
--static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-- BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-- BIT(TRIGGER_NETDEV_LINK) |
-- BIT(TRIGGER_NETDEV_LINK_10) |
-- BIT(TRIGGER_NETDEV_LINK_100) |
-- BIT(TRIGGER_NETDEV_LINK_1000) |
-- BIT(TRIGGER_NETDEV_RX) |
-- BIT(TRIGGER_NETDEV_TX));
-+static const unsigned long supported_triggers =
-+ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-+ BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX);
-
- static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules)
-@@ -1415,7 +1417,7 @@ static int mt7988_phy_probe_shared(struc
- * LED_C and LED_D respectively. At the same time those pins are used to
- * bootstrap configuration of the reference clock source (LED_A),
- * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
-- * In practise this is done using a LED and a resistor pulling the pin
-+ * In practice this is done using a LED and a resistor pulling the pin
- * either to GND or to VIO.
- * The detected value at boot time is accessible at run-time using the
- * TPBANK0 register located in the gpio base of the pinctrl, in order
--- /dev/null
+From 952d7325362ffbefa6ce5619fb4e53c2159ec7a7 Mon Sep 17 00:00:00 2001
+Date: Mon, 17 Feb 2025 17:40:21 +0800
+Subject: [PATCH] net: ethernet: mediatek: add EEE support
+
+Add EEE support to MediaTek SoC Ethernet. The register fields are
+similar to the ones in MT7531, except that the LPI threshold is in
+milliseconds.
+
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 64 +++++++++++++++++++++
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 11 ++++
+ 2 files changed, 75 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -782,6 +782,7 @@ static void mtk_mac_link_up(struct phyli
+
+ mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
+ mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 |
++ MAC_MCR_EEE100M | MAC_MCR_EEE1G |
+ MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC |
+ MAC_MCR_FORCE_RX_FC);
+
+@@ -807,6 +808,15 @@ static void mtk_mac_link_up(struct phyli
+ if (rx_pause)
+ mcr |= MAC_MCR_FORCE_RX_FC;
+
++ if (mode == MLO_AN_PHY && phy && mac->tx_lpi_enabled && phy_init_eee(phy, false) >= 0) {
++ mcr |= MAC_MCR_EEE100M | MAC_MCR_EEE1G;
++ mtk_w32(mac->hw,
++ FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) |
++ FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36) |
++ FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, mac->txidle_thd_ms),
++ MTK_MAC_EEECR(mac->id));
++ }
++
+ mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK;
+ mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
+ }
+@@ -4506,6 +4516,61 @@ static int mtk_set_pauseparam(struct net
+ return phylink_ethtool_set_pauseparam(mac->phylink, pause);
+ }
+
++static int mtk_get_eee(struct net_device *dev, struct ethtool_keee *eee)
++{
++ struct mtk_mac *mac = netdev_priv(dev);
++ u32 reg;
++ int ret;
++
++ ret = phylink_ethtool_get_eee(mac->phylink, eee);
++ if (ret)
++ return ret;
++
++ reg = mtk_r32(mac->hw, MTK_MAC_EEECR(mac->id));
++ eee->tx_lpi_enabled = mac->tx_lpi_enabled;
++ eee->tx_lpi_timer = FIELD_GET(MAC_EEE_LPI_TXIDLE_THD, reg) * 1000;
++
++ return 0;
++}
++
++static int mtk_set_eee(struct net_device *dev, struct ethtool_keee *eee)
++{
++ struct mtk_mac *mac = netdev_priv(dev);
++ u32 txidle_thd_ms, reg;
++ int ret;
++
++ /* Tx idle timer in ms */
++ txidle_thd_ms = DIV_ROUND_UP(eee->tx_lpi_timer, 1000);
++ if (!FIELD_FIT(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms))
++ return -EINVAL;
++
++ reg = FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms);
++
++ /* PHY Wake-up time, this field does not have a reset value, so use the
++ * reset value from MT7531 (36us for 100BaseT and 17us for 1000BaseT).
++ */
++ reg |= FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) |
++ FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36);
++
++ if (!txidle_thd_ms)
++ /* Force LPI Mode without a delay */
++ reg |= MAC_EEE_LPI_MODE;
++
++ ret = phylink_ethtool_set_eee(mac->phylink, eee);
++ if (ret)
++ return ret;
++
++ mac->tx_lpi_enabled = eee->tx_lpi_enabled;
++ mac->txidle_thd_ms = txidle_thd_ms;
++ mtk_w32(mac->hw, reg, MTK_MAC_EEECR(mac->id));
++ if (eee->eee_enabled && eee->eee_active && eee->tx_lpi_enabled)
++ mtk_m32(mac->hw, 0, MAC_MCR_EEE100M | MAC_MCR_EEE1G, MTK_MAC_MCR(mac->id));
++ else
++ mtk_m32(mac->hw, MAC_MCR_EEE100M | MAC_MCR_EEE1G, 0, MTK_MAC_MCR(mac->id));
++
++ return 0;
++}
++
+ static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
+ struct net_device *sb_dev)
+ {
+@@ -4538,6 +4603,8 @@ static const struct ethtool_ops mtk_etht
+ .set_pauseparam = mtk_set_pauseparam,
+ .get_rxnfc = mtk_get_rxnfc,
+ .set_rxnfc = mtk_set_rxnfc,
++ .get_eee = mtk_get_eee,
++ .set_eee = mtk_set_eee,
+ };
+
+ static const struct net_device_ops mtk_netdev_ops = {
+@@ -4598,6 +4665,8 @@ static int mtk_add_mac(struct mtk_eth *e
+ }
+ mac = netdev_priv(eth->netdev[id]);
+ eth->mac[id] = mac;
++ mac->tx_lpi_enabled = true;
++ mac->txidle_thd_ms = 1;
+ mac->id = id;
+ mac->hw = eth;
+ mac->of_node = np;
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -461,6 +461,8 @@
+ #define MAC_MCR_RX_FIFO_CLR_DIS BIT(12)
+ #define MAC_MCR_BACKOFF_EN BIT(9)
+ #define MAC_MCR_BACKPR_EN BIT(8)
++#define MAC_MCR_EEE1G BIT(7)
++#define MAC_MCR_EEE100M BIT(6)
+ #define MAC_MCR_FORCE_RX_FC BIT(5)
+ #define MAC_MCR_FORCE_TX_FC BIT(4)
+ #define MAC_MCR_SPEED_1000 BIT(3)
+@@ -469,6 +471,15 @@
+ #define MAC_MCR_FORCE_LINK BIT(0)
+ #define MAC_MCR_FORCE_LINK_DOWN (MAC_MCR_FORCE_MODE)
+
++/* Mac EEE control registers */
++#define MTK_MAC_EEECR(x) (0x10104 + (x * 0x100))
++#define MAC_EEE_WAKEUP_TIME_1000 GENMASK(31, 24)
++#define MAC_EEE_WAKEUP_TIME_100 GENMASK(23, 16)
++#define MAC_EEE_LPI_TXIDLE_THD GENMASK(15, 8)
++#define MAC_EEE_CKG_TXIDLE BIT(3)
++#define MAC_EEE_CKG_RXLPI BIT(2)
++#define MAC_EEE_LPI_MODE BIT(0)
++
+ /* Mac status registers */
+ #define MTK_MAC_MSR(x) (0x10108 + (x * 0x100))
+ #define MAC_MSR_EEE1G BIT(7)
+@@ -1316,6 +1327,8 @@ struct mtk_mac {
+ int id;
+ phy_interface_t interface;
+ u8 ppe_idx;
++ bool tx_lpi_enabled;
++ u8 txidle_thd_ms;
+ int speed;
+ struct device_node *of_node;
+ struct phylink *phylink;
+++ /dev/null
-From c0dc1b412f9d840c51c5ee8927bf066e15a59550 Mon Sep 17 00:00:00 2001
-Date: Thu, 17 Oct 2024 11:22:12 +0800
-Subject: [PATCH 02/20] net: phy: mediatek-ge-soc: Shrink line wrapping to 80
- characters
-
-This patch shrinks line wrapping to 80 chars. Also, in
-tx_amp_fill_result(), use FIELD_PREP() to prettify code.
-
----
- drivers/net/phy/mediatek-ge-soc.c | 125 +++++++++++++++++++++---------
- 1 file changed, 88 insertions(+), 37 deletions(-)
-
---- a/drivers/net/phy/mediatek-ge-soc.c
-+++ b/drivers/net/phy/mediatek-ge-soc.c
-@@ -342,7 +342,8 @@ static int cal_cycle(struct phy_device *
- ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
- MTK_PHY_RG_AD_CAL_CLK, reg_val,
- reg_val & MTK_PHY_DA_CAL_CLK, 500,
-- ANALOG_INTERNAL_OPERATION_MAX_US, false);
-+ ANALOG_INTERNAL_OPERATION_MAX_US,
-+ false);
- if (ret) {
- phydev_err(phydev, "Calibration cycle timeout\n");
- return ret;
-@@ -441,40 +442,72 @@ static int tx_amp_fill_result(struct phy
- }
-
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-- MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10);
-+ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+ buf[0] + bias[0]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-- MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]);
-+ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+ buf[0] + bias[1]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-- MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10);
-+ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+ buf[0] + bias[2]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-- MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]);
-+ MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+ buf[0] + bias[3]));
-
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-- MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+ buf[1] + bias[4]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-- MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]);
-+ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+ buf[1] + bias[5]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-- MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+ buf[1] + bias[6]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-- MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]);
-+ MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+ buf[1] + bias[7]));
-
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-- MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+ buf[2] + bias[8]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-- MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]);
-+ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+ buf[2] + bias[9]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-- MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+ buf[2] + bias[10]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-- MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]);
-+ MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+ buf[2] + bias[11]));
-
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-- MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+ buf[3] + bias[12]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-- MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]);
-+ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+ buf[3] + bias[13]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-- MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+ buf[3] + bias[14]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-- MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]);
-+ MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+ buf[3] + bias[15]));
-
- return 0;
- }
-@@ -663,7 +696,8 @@ static int tx_vcm_cal_sw(struct phy_devi
- goto restore;
-
- /* We calibrate TX-VCM in different logic. Check upper index and then
-- * lower index. If this calibration is valid, apply lower index's result.
-+ * lower index. If this calibration is valid, apply lower index's
-+ * result.
- */
- ret = upper_ret - lower_ret;
- if (ret == 1) {
-@@ -692,7 +726,8 @@ static int tx_vcm_cal_sw(struct phy_devi
- } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
- lower_ret == 0) {
- ret = 0;
-- phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n",
-+ phydev_warn(phydev,
-+ "TX-VCM SW cal result at high margin 0x%x\n",
- upper_idx);
- } else {
- ret = -EINVAL;
-@@ -796,7 +831,8 @@ static void mt7981_phy_finetune(struct p
-
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
-+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+ MTK_PHY_LPF_X_AVERAGE_MASK,
- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
-
- /* rg_tr_lpf_cnt_val = 512 */
-@@ -865,7 +901,8 @@ static void mt7988_phy_finetune(struct p
-
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
-+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+ MTK_PHY_LPF_X_AVERAGE_MASK,
- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
-
- /* rg_tr_lpf_cnt_val = 1023 */
-@@ -977,7 +1014,8 @@ static void mt798x_phy_eee(struct phy_de
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
-- __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
-+ __phy_modify(phydev, MTK_PHY_LPI_REG_14,
-+ MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
- FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
-
- __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
-@@ -987,7 +1025,8 @@ static void mt798x_phy_eee(struct phy_de
- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
- MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff));
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ 0xff));
- }
-
- static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
-@@ -1147,7 +1186,8 @@ static int mt798x_phy_hw_led_on_set(stru
- (index ? 16 : 0), &priv->led_state);
- if (changed)
- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED1_ON_CTRL :
-+ MTK_PHY_LED0_ON_CTRL,
- MTK_PHY_LED_ON_MASK,
- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
- else
-@@ -1157,7 +1197,8 @@ static int mt798x_phy_hw_led_on_set(stru
- static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
- bool blinking)
- {
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
- bool changed;
-
-@@ -1170,8 +1211,10 @@ static int mt798x_phy_hw_led_blink_set(s
- (index ? 16 : 0), &priv->led_state);
- if (changed)
- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL,
-- blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL,
-+ blinking ?
-+ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
- else
- return 0;
- }
-@@ -1237,7 +1280,8 @@ static int mt798x_phy_led_hw_is_supporte
- static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
- unsigned long *rules)
- {
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
-@@ -1258,8 +1302,8 @@ static int mt798x_phy_led_hw_control_get
- if (blink < 0)
- return -EIO;
-
-- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX |
-- MTK_PHY_LED_ON_LINKDOWN)) ||
-+ if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-+ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
- set_bit(bit_netdev, &priv->led_state);
- else
-@@ -1333,17 +1377,23 @@ static int mt798x_phy_led_hw_control_set
-
- if (rules & BIT(TRIGGER_NETDEV_RX)) {
- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) :
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000RX : 0)) :
- MTK_PHY_LED_BLINK_RX;
- }
-
- if (rules & BIT(TRIGGER_NETDEV_TX)) {
- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) :
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000TX : 0)) :
- MTK_PHY_LED_BLINK_TX;
- }
-
-@@ -1400,7 +1450,8 @@ static int mt7988_phy_fix_leds_polaritie
- /* Only now setup pinctrl to avoid bogus blinking */
- pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
- if (IS_ERR(pinctrl))
-- dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n");
-+ dev_err(&phydev->mdio.bus->dev,
-+ "Failed to setup PHY LED pinctrl\n");
-
- return 0;
- }
+++ /dev/null
-From bcbbfb4f62c4ba35783cc617997a2e92d91e3940 Mon Sep 17 00:00:00 2001
-Date: Thu, 17 Oct 2024 11:22:13 +0800
-Subject: [PATCH 03/20] net: phy: mediatek-ge-soc: Propagate error code
- correctly in cal_cycle()
-
-This patch propagates error code correctly in cal_cycle()
-and improve with FIELD_GET().
-
----
- drivers/net/phy/mediatek-ge-soc.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/net/phy/mediatek-ge-soc.c
-+++ b/drivers/net/phy/mediatek-ge-soc.c
-@@ -110,7 +110,7 @@
- #define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
-
- #define MTK_PHY_RG_AD_CAL_COMP 0x17a
--#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8)
-+#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8)
-
- #define MTK_PHY_RG_AD_CAL_CLK 0x17b
- #define MTK_PHY_DA_CAL_CLK BIT(0)
-@@ -351,8 +351,10 @@ static int cal_cycle(struct phy_device *
-
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
- MTK_PHY_DA_CALIN_FLAG);
-- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >>
-- MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
-+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
-+ if (ret < 0)
-+ return ret;
-+ ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
- phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
-
- return ret;
+++ /dev/null
-From e062f073dc0df4fcd338043cb0b69b6bcd31e4af Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 00:34:51 +0800
-Subject: [PATCH 04/20] net: phy: mediatek: Re-organize MediaTek ethernet phy
- drivers
-
-Re-organize MediaTek ethernet phy driver files and get ready to integrate
-some common functions and add new 2.5G phy driver.
-mtk-ge.c: MT7530 Gphy on MT7621 & MT7531 Gphy
-mtk-ge-soc.c: Built-in Gphy on MT7981 & Built-in switch Gphy on MT7988
-mtk-2p5ge.c: Planned for built-in 2.5G phy on MT7988
-
----
- MAINTAINERS | 4 ++--
- drivers/net/phy/Kconfig | 17 +-------------
- drivers/net/phy/Makefile | 3 +--
- drivers/net/phy/mediatek/Kconfig | 22 +++++++++++++++++++
- drivers/net/phy/mediatek/Makefile | 3 +++
- .../mtk-ge-soc.c} | 0
- .../phy/{mediatek-ge.c => mediatek/mtk-ge.c} | 0
- 7 files changed, 29 insertions(+), 20 deletions(-)
- create mode 100644 drivers/net/phy/mediatek/Kconfig
- create mode 100644 drivers/net/phy/mediatek/Makefile
- rename drivers/net/phy/{mediatek-ge-soc.c => mediatek/mtk-ge-soc.c} (100%)
- rename drivers/net/phy/{mediatek-ge.c => mediatek/mtk-ge.c} (100%)
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
- S: Maintained
--F: drivers/net/phy/mediatek-ge-soc.c
--F: drivers/net/phy/mediatek-ge.c
-+F: drivers/net/phy/mediatek/mtk-ge-soc.c
-+F: drivers/net/phy/mediatek/mtk-ge.c
- F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c
-
- MEDIATEK I2C CONTROLLER DRIVER
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -266,22 +266,7 @@ config MAXLINEAR_GPHY
- Support for the Maxlinear GPY115, GPY211, GPY212, GPY215,
- GPY241, GPY245 PHYs.
-
--config MEDIATEK_GE_PHY
-- tristate "MediaTek Gigabit Ethernet PHYs"
-- help
-- Supports the MediaTek Gigabit Ethernet PHYs.
--
--config MEDIATEK_GE_SOC_PHY
-- tristate "MediaTek SoC Ethernet PHYs"
-- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
-- depends on NVMEM_MTK_EFUSE
-- help
-- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
--
-- Include support for built-in Ethernet PHYs which are present in
-- the MT7981 and MT7988 SoCs. These PHYs need calibration data
-- present in the SoCs efuse and will dynamically calibrate VCM
-- (common-mode voltage) during startup.
-+source "drivers/net/phy/mediatek/Kconfig"
-
- config MICREL_PHY
- tristate "Micrel PHYs"
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -74,8 +74,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o
- obj-$(CONFIG_MARVELL_88Q2XXX_PHY) += marvell-88q2xxx.o
- obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o
- obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o
--obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
--obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o
-+obj-y += mediatek/
- obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
- obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
- obj-$(CONFIG_MICREL_PHY) += micrel.o
---- /dev/null
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -0,0 +1,22 @@
-+# SPDX-License-Identifier: GPL-2.0-only
-+config MEDIATEK_GE_PHY
-+ tristate "MediaTek Gigabit Ethernet PHYs"
-+ help
-+ Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
-+
-+ Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531.
-+ You may find mt7530 inside mt7621. This driver shares some
-+ common operations with MediaTek SoC built-in Gigabit
-+ Ethernet PHYs.
-+
-+config MEDIATEK_GE_SOC_PHY
-+ tristate "MediaTek SoC Ethernet PHYs"
-+ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
-+ depends on NVMEM_MTK_EFUSE
-+ help
-+ Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
-+
-+ Include support for built-in Ethernet PHYs which are present in
-+ the MT7981 and MT7988 SoCs. These PHYs need calibration data
-+ present in the SoCs efuse and will dynamically calibrate VCM
-+ (common-mode voltage) during startup.
---- /dev/null
-+++ b/drivers/net/phy/mediatek/Makefile
-@@ -0,0 +1,3 @@
-+# SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
-+obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
---- a/drivers/net/phy/mediatek-ge-soc.c
-+++ /dev/null
-@@ -1,1610 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--#include <linux/bitfield.h>
--#include <linux/bitmap.h>
--#include <linux/mfd/syscon.h>
--#include <linux/module.h>
--#include <linux/nvmem-consumer.h>
--#include <linux/pinctrl/consumer.h>
--#include <linux/phy.h>
--#include <linux/regmap.h>
--
--#define MTK_GPHY_ID_MT7981 0x03a29461
--#define MTK_GPHY_ID_MT7988 0x03a29481
--
--#define MTK_EXT_PAGE_ACCESS 0x1f
--#define MTK_PHY_PAGE_STANDARD 0x0000
--#define MTK_PHY_PAGE_EXTENDED_3 0x0003
--
--#define MTK_PHY_LPI_REG_14 0x14
--#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0)
--
--#define MTK_PHY_LPI_REG_1c 0x1c
--#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
--
--#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
--
--#define ANALOG_INTERNAL_OPERATION_MAX_US 20
--#define TXRESERVE_MIN 0
--#define TXRESERVE_MAX 7
--
--#define MTK_PHY_ANARG_RG 0x10
--#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8)
--
--/* Registers on MDIO_MMD_VEND1 */
--#define MTK_PHY_TXVLD_DA_RG 0x12
--#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10)
--#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16
--#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10)
--#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17
--#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18
--#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19
--#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20
--#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21
--#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22
--#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0)
--
--#define MTK_PHY_RXADC_CTRL_RG7 0xc6
--#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
--
--#define MTK_PHY_RXADC_CTRL_RG9 0xc8
--#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12)
--#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8)
--#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4)
--#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0)
--
--#define MTK_PHY_LDO_OUTPUT_V 0xd7
--
--#define MTK_PHY_RG_ANA_CAL_RG0 0xdb
--#define MTK_PHY_RG_CAL_CKINV BIT(12)
--#define MTK_PHY_RG_ANA_CALEN BIT(8)
--#define MTK_PHY_RG_ZCALEN_A BIT(0)
--
--#define MTK_PHY_RG_ANA_CAL_RG1 0xdc
--#define MTK_PHY_RG_ZCALEN_B BIT(12)
--#define MTK_PHY_RG_ZCALEN_C BIT(8)
--#define MTK_PHY_RG_ZCALEN_D BIT(4)
--#define MTK_PHY_RG_TXVOS_CALEN BIT(0)
--
--#define MTK_PHY_RG_ANA_CAL_RG5 0xe0
--#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8)
--
--#define MTK_PHY_RG_TX_FILTER 0xfe
--
--#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120
--#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8)
--#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0)
--
--#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122
--#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0)
--
--#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144
--#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5)
--
--#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172
--#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8)
--#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0)
--
--#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173
--#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8)
--#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
--
--#define MTK_PHY_RG_AD_CAL_COMP 0x17a
--#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8)
--
--#define MTK_PHY_RG_AD_CAL_CLK 0x17b
--#define MTK_PHY_DA_CAL_CLK BIT(0)
--
--#define MTK_PHY_RG_AD_CALIN 0x17c
--#define MTK_PHY_DA_CALIN_FLAG BIT(0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d
--#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e
--#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f
--#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180
--#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181
--#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182
--#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183
--#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184
--#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DEV1E_REG19b 0x19b
--#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8)
--
--#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a
--#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b
--#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c
--#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d
--#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e
--#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f
--#define MTK_PHY_RG_LP_IIR2_K4_L 0x230
--#define MTK_PHY_RG_LP_IIR2_K4_U 0x231
--#define MTK_PHY_RG_LP_IIR2_K5_L 0x232
--#define MTK_PHY_RG_LP_IIR2_K5_U 0x233
--
--#define MTK_PHY_RG_DEV1E_REG234 0x234
--#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0)
--#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4)
--#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12)
--
--#define MTK_PHY_RG_LPF_CNT_VAL 0x235
--
--#define MTK_PHY_RG_DEV1E_REG238 0x238
--#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0)
--#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12)
--
--#define MTK_PHY_RG_DEV1E_REG239 0x239
--#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0)
--#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12)
--
--#define MTK_PHY_RG_DEV1E_REG27C 0x27c
--#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8)
--#define MTK_PHY_RG_DEV1E_REG27D 0x27d
--#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0)
--
--#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7
--#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0)
--#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8)
--
--#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1
--#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0)
--#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8)
--#define MTK_PHY_LPI_TR_READY BIT(9)
--#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10)
--
--#define MTK_PHY_RG_DEV1E_REG323 0x323
--#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0)
--#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4)
--
--#define MTK_PHY_RG_DEV1E_REG324 0x324
--#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0)
--#define MTK_PHY_SMI_DET_MAX_EN BIT(8)
--
--#define MTK_PHY_RG_DEV1E_REG326 0x326
--#define MTK_PHY_LPI_MODE_SD_ON BIT(0)
--#define MTK_PHY_RESET_RANDUPD_CNT BIT(1)
--#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2)
--#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4)
--#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5)
--
--#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502
--#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503
--
--#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d
--#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e
--#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f
--#define MTK_PHY_DA_TX_R50_PAIR_D 0x540
--
--/* Registers on MDIO_MMD_VEND2 */
--#define MTK_PHY_LED0_ON_CTRL 0x24
--#define MTK_PHY_LED1_ON_CTRL 0x26
--#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
--#define MTK_PHY_LED_ON_LINK1000 BIT(0)
--#define MTK_PHY_LED_ON_LINK100 BIT(1)
--#define MTK_PHY_LED_ON_LINK10 BIT(2)
--#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
-- MTK_PHY_LED_ON_LINK100 |\
-- MTK_PHY_LED_ON_LINK1000)
--#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
--#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
--#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
--#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
--#define MTK_PHY_LED_ON_POLARITY BIT(14)
--#define MTK_PHY_LED_ON_ENABLE BIT(15)
--
--#define MTK_PHY_LED0_BLINK_CTRL 0x25
--#define MTK_PHY_LED1_BLINK_CTRL 0x27
--#define MTK_PHY_LED_BLINK_1000TX BIT(0)
--#define MTK_PHY_LED_BLINK_1000RX BIT(1)
--#define MTK_PHY_LED_BLINK_100TX BIT(2)
--#define MTK_PHY_LED_BLINK_100RX BIT(3)
--#define MTK_PHY_LED_BLINK_10TX BIT(4)
--#define MTK_PHY_LED_BLINK_10RX BIT(5)
--#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
-- MTK_PHY_LED_BLINK_100RX |\
-- MTK_PHY_LED_BLINK_1000RX)
--#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
-- MTK_PHY_LED_BLINK_100TX |\
-- MTK_PHY_LED_BLINK_1000TX)
--#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
--#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
--#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
--#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
--
--#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
--
--#define MTK_PHY_RG_BG_RASEL 0x115
--#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0)
--
--/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
--#define RG_GPIO_MISC_TPBANK0 0x6f0
--#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8)
--
--/* These macro privides efuse parsing for internal phy. */
--#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0))
--#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0))
--#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0))
--#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0))
--#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0))
--
--#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0))
--#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0))
--#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0))
--#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0))
--#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0))
--
--#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0))
--#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0))
--
--#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0))
--#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0))
--
--enum {
-- NO_PAIR,
-- PAIR_A,
-- PAIR_B,
-- PAIR_C,
-- PAIR_D,
--};
--
--enum calibration_mode {
-- EFUSE_K,
-- SW_K
--};
--
--enum CAL_ITEM {
-- REXT,
-- TX_OFFSET,
-- TX_AMP,
-- TX_R50,
-- TX_VCM
--};
--
--enum CAL_MODE {
-- EFUSE_M,
-- SW_M
--};
--
--#define MTK_PHY_LED_STATE_FORCE_ON 0
--#define MTK_PHY_LED_STATE_FORCE_BLINK 1
--#define MTK_PHY_LED_STATE_NETDEV 2
--
--struct mtk_socphy_priv {
-- unsigned long led_state;
--};
--
--struct mtk_socphy_shared {
-- u32 boottrap;
-- struct mtk_socphy_priv priv[4];
--};
--
--static int mtk_socphy_read_page(struct phy_device *phydev)
--{
-- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_socphy_write_page(struct phy_device *phydev, int page)
--{
-- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
--/* One calibration cycle consists of:
-- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
-- * until AD_CAL_COMP is ready to output calibration result.
-- * 2.Wait until DA_CAL_CLK is available.
-- * 3.Fetch AD_CAL_COMP_OUT.
-- */
--static int cal_cycle(struct phy_device *phydev, int devad,
-- u32 regnum, u16 mask, u16 cal_val)
--{
-- int reg_val;
-- int ret;
--
-- phy_modify_mmd(phydev, devad, regnum,
-- mask, cal_val);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-- MTK_PHY_DA_CALIN_FLAG);
--
-- ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_AD_CAL_CLK, reg_val,
-- reg_val & MTK_PHY_DA_CAL_CLK, 500,
-- ANALOG_INTERNAL_OPERATION_MAX_US,
-- false);
-- if (ret) {
-- phydev_err(phydev, "Calibration cycle timeout\n");
-- return ret;
-- }
--
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-- MTK_PHY_DA_CALIN_FLAG);
-- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
-- if (ret < 0)
-- return ret;
-- ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
-- phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
--
-- return ret;
--}
--
--static int rext_fill_result(struct phy_device *phydev, u16 *buf)
--{
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
-- MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
-- MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
--
-- return 0;
--}
--
--static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
--{
-- u16 rext_cal_val[2];
--
-- rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
-- rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
-- rext_fill_result(phydev, rext_cal_val);
--
-- return 0;
--}
--
--static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
--{
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-- MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-- MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-- MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-- MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
--
-- return 0;
--}
--
--static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
--{
-- u16 tx_offset_cal_val[4];
--
-- tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
-- tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
-- tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
-- tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
--
-- tx_offset_fill_result(phydev, tx_offset_cal_val);
--
-- return 0;
--}
--
--static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
--{
-- const int vals_9481[16] = { 10, 6, 6, 10,
-- 10, 6, 6, 10,
-- 10, 6, 6, 10,
-- 10, 6, 6, 10 };
-- const int vals_9461[16] = { 7, 1, 4, 7,
-- 7, 1, 4, 7,
-- 7, 1, 4, 7,
-- 7, 1, 4, 7 };
-- int bias[16] = {};
-- int i;
--
-- switch (phydev->drv->phy_id) {
-- case MTK_GPHY_ID_MT7981:
-- /* We add some calibration to efuse values
-- * due to board level influence.
-- * GBE: +7, TBT: +1, HBT: +4, TST: +7
-- */
-- memcpy(bias, (const void *)vals_9461, sizeof(bias));
-- break;
-- case MTK_GPHY_ID_MT7988:
-- memcpy(bias, (const void *)vals_9481, sizeof(bias));
-- break;
-- }
--
-- /* Prevent overflow */
-- for (i = 0; i < 12; i++) {
-- if (buf[i >> 2] + bias[i] > 63) {
-- buf[i >> 2] = 63;
-- bias[i] = 0;
-- }
-- }
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-- MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-- buf[0] + bias[0]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-- MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-- buf[0] + bias[1]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-- MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-- buf[0] + bias[2]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-- MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-- buf[0] + bias[3]));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-- MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-- buf[1] + bias[4]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-- MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-- buf[1] + bias[5]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-- MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-- buf[1] + bias[6]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-- MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-- buf[1] + bias[7]));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-- MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-- buf[2] + bias[8]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-- MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-- buf[2] + bias[9]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-- MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-- buf[2] + bias[10]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-- MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-- buf[2] + bias[11]));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-- MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-- buf[3] + bias[12]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-- MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-- buf[3] + bias[13]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-- MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-- buf[3] + bias[14]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-- MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-- buf[3] + bias[15]));
--
-- return 0;
--}
--
--static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
--{
-- u16 tx_amp_cal_val[4];
--
-- tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
-- tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
-- tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
-- tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
-- tx_amp_fill_result(phydev, tx_amp_cal_val);
--
-- return 0;
--}
--
--static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
-- u8 txg_calen_x)
--{
-- int bias = 0;
-- u16 reg, val;
--
-- if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
-- bias = -1;
--
-- val = clamp_val(bias + tx_r50_cal_val, 0, 63);
--
-- switch (txg_calen_x) {
-- case PAIR_A:
-- reg = MTK_PHY_DA_TX_R50_PAIR_A;
-- break;
-- case PAIR_B:
-- reg = MTK_PHY_DA_TX_R50_PAIR_B;
-- break;
-- case PAIR_C:
-- reg = MTK_PHY_DA_TX_R50_PAIR_C;
-- break;
-- case PAIR_D:
-- reg = MTK_PHY_DA_TX_R50_PAIR_D;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
--
-- return 0;
--}
--
--static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
-- u8 txg_calen_x)
--{
-- u16 tx_r50_cal_val;
--
-- switch (txg_calen_x) {
-- case PAIR_A:
-- tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
-- break;
-- case PAIR_B:
-- tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
-- break;
-- case PAIR_C:
-- tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
-- break;
-- case PAIR_D:
-- tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
-- break;
-- default:
-- return -EINVAL;
-- }
-- tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
--
-- return 0;
--}
--
--static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
--{
-- u8 lower_idx, upper_idx, txreserve_val;
-- u8 lower_ret, upper_ret;
-- int ret;
--
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_ANA_CALEN);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_CAL_CKINV);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_TXVOS_CALEN);
--
-- switch (rg_txreserve_x) {
-- case PAIR_A:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN0_A,
-- MTK_PHY_DASN_DAC_IN0_A_MASK);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN1_A,
-- MTK_PHY_DASN_DAC_IN1_A_MASK);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_ZCALEN_A);
-- break;
-- case PAIR_B:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN0_B,
-- MTK_PHY_DASN_DAC_IN0_B_MASK);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN1_B,
-- MTK_PHY_DASN_DAC_IN1_B_MASK);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_ZCALEN_B);
-- break;
-- case PAIR_C:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN0_C,
-- MTK_PHY_DASN_DAC_IN0_C_MASK);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN1_C,
-- MTK_PHY_DASN_DAC_IN1_C_MASK);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_ZCALEN_C);
-- break;
-- case PAIR_D:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN0_D,
-- MTK_PHY_DASN_DAC_IN0_D_MASK);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN1_D,
-- MTK_PHY_DASN_DAC_IN1_D_MASK);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_ZCALEN_D);
-- break;
-- default:
-- ret = -EINVAL;
-- goto restore;
-- }
--
-- lower_idx = TXRESERVE_MIN;
-- upper_idx = TXRESERVE_MAX;
--
-- phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
-- while ((upper_idx - lower_idx) > 1) {
-- txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
-- ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- txreserve_val << 12 | txreserve_val << 8 |
-- txreserve_val << 4 | txreserve_val);
-- if (ret == 1) {
-- upper_idx = txreserve_val;
-- upper_ret = ret;
-- } else if (ret == 0) {
-- lower_idx = txreserve_val;
-- lower_ret = ret;
-- } else {
-- goto restore;
-- }
-- }
--
-- if (lower_idx == TXRESERVE_MIN) {
-- lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- lower_idx << 12 | lower_idx << 8 |
-- lower_idx << 4 | lower_idx);
-- ret = lower_ret;
-- } else if (upper_idx == TXRESERVE_MAX) {
-- upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- upper_idx << 12 | upper_idx << 8 |
-- upper_idx << 4 | upper_idx);
-- ret = upper_ret;
-- }
-- if (ret < 0)
-- goto restore;
--
-- /* We calibrate TX-VCM in different logic. Check upper index and then
-- * lower index. If this calibration is valid, apply lower index's
-- * result.
-- */
-- ret = upper_ret - lower_ret;
-- if (ret == 1) {
-- ret = 0;
-- /* Make sure we use upper_idx in our calibration system */
-- cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- upper_idx << 12 | upper_idx << 8 |
-- upper_idx << 4 | upper_idx);
-- phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
-- } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
-- lower_ret == 1) {
-- ret = 0;
-- cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- lower_idx << 12 | lower_idx << 8 |
-- lower_idx << 4 | lower_idx);
-- phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
-- lower_idx);
-- } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
-- lower_ret == 0) {
-- ret = 0;
-- phydev_warn(phydev,
-- "TX-VCM SW cal result at high margin 0x%x\n",
-- upper_idx);
-- } else {
-- ret = -EINVAL;
-- }
--
--restore:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_ANA_CALEN);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_TXVOS_CALEN);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_ZCALEN_A);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
-- MTK_PHY_RG_ZCALEN_D);
--
-- return ret;
--}
--
--static void mt798x_phy_common_finetune(struct phy_device *phydev)
--{
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
-- __phy_write(phydev, 0x11, 0xc71);
-- __phy_write(phydev, 0x12, 0xc);
-- __phy_write(phydev, 0x10, 0x8fae);
--
-- /* EnabRandUpdTrig = 1 */
-- __phy_write(phydev, 0x11, 0x2f00);
-- __phy_write(phydev, 0x12, 0xe);
-- __phy_write(phydev, 0x10, 0x8fb0);
--
-- /* NormMseLoThresh = 85 */
-- __phy_write(phydev, 0x11, 0x55a0);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x83aa);
--
-- /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
-- __phy_write(phydev, 0x11, 0x240);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9680);
--
-- /* TrFreeze = 0 (mt7988 default) */
-- __phy_write(phydev, 0x11, 0x0);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9686);
--
-- /* SSTrKp100 = 5 */
-- /* SSTrKf100 = 6 */
-- /* SSTrKp1000Mas = 5 */
-- /* SSTrKf1000Mas = 6 */
-- /* SSTrKp1000Slv = 5 */
-- /* SSTrKf1000Slv = 6 */
-- __phy_write(phydev, 0x11, 0xbaef);
-- __phy_write(phydev, 0x12, 0x2e);
-- __phy_write(phydev, 0x10, 0x968c);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--}
--
--static void mt7981_phy_finetune(struct phy_device *phydev)
--{
-- u16 val[8] = { 0x01ce, 0x01c1,
-- 0x020f, 0x0202,
-- 0x03d0, 0x03c0,
-- 0x0013, 0x0005 };
-- int i, k;
--
-- /* 100M eye finetune:
-- * Keep middle level of TX MLT3 shapper as default.
-- * Only change TX MLT3 overshoot level here.
-- */
-- for (k = 0, i = 1; i < 12; i++) {
-- if (i % 3 == 0)
-- continue;
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
-- }
--
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* ResetSyncOffset = 6 */
-- __phy_write(phydev, 0x11, 0x600);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8fc0);
--
-- /* VgaDecRate = 1 */
-- __phy_write(phydev, 0x11, 0x4c2a);
-- __phy_write(phydev, 0x12, 0x3e);
-- __phy_write(phydev, 0x10, 0x8fa4);
--
-- /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
-- * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
-- */
-- __phy_write(phydev, 0x11, 0xd10a);
-- __phy_write(phydev, 0x12, 0x34);
-- __phy_write(phydev, 0x10, 0x8f82);
--
-- /* VcoSlicerThreshBitsHigh */
-- __phy_write(phydev, 0x11, 0x5555);
-- __phy_write(phydev, 0x12, 0x55);
-- __phy_write(phydev, 0x10, 0x8ec0);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-- MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-- MTK_PHY_LPF_X_AVERAGE_MASK,
-- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
--
-- /* rg_tr_lpf_cnt_val = 512 */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
--
-- /* IIR2 related */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
--
-- /* FFE peaking */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
-- MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
-- MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
--
-- /* Disable LDO pump */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
-- /* Adjust LDO output voltage */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
--}
--
--static void mt7988_phy_finetune(struct phy_device *phydev)
--{
-- u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
-- 0x020d, 0x0206, 0x0384, 0x03d0,
-- 0x03c6, 0x030a, 0x0011, 0x0005 };
-- int i;
--
-- /* Set default MLT3 shaper first */
-- for (i = 0; i < 12; i++)
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
--
-- /* TCT finetune */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
--
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* ResetSyncOffset = 5 */
-- __phy_write(phydev, 0x11, 0x500);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8fc0);
--
-- /* VgaDecRate is 1 at default on mt7988 */
--
-- /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
-- * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
-- */
-- __phy_write(phydev, 0x11, 0xb90a);
-- __phy_write(phydev, 0x12, 0x6f);
-- __phy_write(phydev, 0x10, 0x8f82);
--
-- /* RemAckCntLimitCtrl = 1 */
-- __phy_write(phydev, 0x11, 0xfbba);
-- __phy_write(phydev, 0x12, 0xc3);
-- __phy_write(phydev, 0x10, 0x87f8);
--
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-- MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-- MTK_PHY_LPF_X_AVERAGE_MASK,
-- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
--
-- /* rg_tr_lpf_cnt_val = 1023 */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
--}
--
--static void mt798x_phy_eee(struct phy_device *phydev)
--{
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
-- MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
-- MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
-- FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-- MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- 0xff));
--
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_TESTMUX_ADC_CTRL,
-- MTK_PHY_RG_TXEN_DIG_MASK);
--
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
--
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
-- MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
-- MTK_PHY_LPI_SLV_SEND_TX_EN,
-- FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
--
-- /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
-- MTK_PHY_LPI_TXPCS_LOC_RCV);
--
-- /* This also fixes some IoT issues, such as CH340 */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
-- MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
-- FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
-- FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
-- MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-- FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-- 0x33) |
-- MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
-- MTK_PHY_LPI_VCO_EEE_STG0_EN);
--
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
-- MTK_PHY_EEE_WAKE_MAS_INT_DC |
-- MTK_PHY_EEE_WAKE_SLV_INT_DC);
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
-- MTK_PHY_SMI_DETCNT_MAX_MASK,
-- FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
-- MTK_PHY_SMI_DET_MAX_EN);
--
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
-- MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
-- MTK_PHY_TREC_UPDATE_ENAB_CLR |
-- MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
-- MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
--
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* Regsigdet_sel_1000 = 0 */
-- __phy_write(phydev, 0x11, 0xb);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9690);
--
-- /* REG_EEE_st2TrKf1000 = 2 */
-- __phy_write(phydev, 0x11, 0x114f);
-- __phy_write(phydev, 0x12, 0x2);
-- __phy_write(phydev, 0x10, 0x969a);
--
-- /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
-- __phy_write(phydev, 0x11, 0x3028);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x969e);
--
-- /* RegEEE_slv_wake_int_timer_tar = 8 */
-- __phy_write(phydev, 0x11, 0x5010);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96a0);
--
-- /* RegEEE_trfreeze_timer2 = 586 */
-- __phy_write(phydev, 0x11, 0x24a);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96a8);
--
-- /* RegEEE100Stg1_tar = 16 */
-- __phy_write(phydev, 0x11, 0x3210);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96b8);
--
-- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
-- __phy_write(phydev, 0x11, 0x1463);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96ca);
--
-- /* DfeTailEnableVgaThresh1000 = 27 */
-- __phy_write(phydev, 0x11, 0x36);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8f80);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
-- __phy_modify(phydev, MTK_PHY_LPI_REG_14,
-- MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
--
-- __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
-- FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-- MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- 0xff));
--}
--
--static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
-- u8 start_pair, u8 end_pair)
--{
-- u8 pair_n;
-- int ret;
--
-- for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-- /* TX_OFFSET & TX_AMP have no SW calibration. */
-- switch (cal_item) {
-- case TX_VCM:
-- ret = tx_vcm_cal_sw(phydev, pair_n);
-- break;
-- default:
-- return -EINVAL;
-- }
-- if (ret)
-- return ret;
-- }
-- return 0;
--}
--
--static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
-- u8 start_pair, u8 end_pair, u32 *buf)
--{
-- u8 pair_n;
-- int ret;
--
-- for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-- /* TX_VCM has no efuse calibration. */
-- switch (cal_item) {
-- case REXT:
-- ret = rext_cal_efuse(phydev, buf);
-- break;
-- case TX_OFFSET:
-- ret = tx_offset_cal_efuse(phydev, buf);
-- break;
-- case TX_AMP:
-- ret = tx_amp_cal_efuse(phydev, buf);
-- break;
-- case TX_R50:
-- ret = tx_r50_cal_efuse(phydev, buf, pair_n);
-- break;
-- default:
-- return -EINVAL;
-- }
-- if (ret)
-- return ret;
-- }
--
-- return 0;
--}
--
--static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
-- enum CAL_MODE cal_mode, u8 start_pair,
-- u8 end_pair, u32 *buf)
--{
-- int ret;
--
-- switch (cal_mode) {
-- case EFUSE_M:
-- ret = cal_efuse(phydev, cal_item, start_pair,
-- end_pair, buf);
-- break;
-- case SW_M:
-- ret = cal_sw(phydev, cal_item, start_pair, end_pair);
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- if (ret) {
-- phydev_err(phydev, "cal %d failed\n", cal_item);
-- return -EIO;
-- }
--
-- return 0;
--}
--
--static int mt798x_phy_calibration(struct phy_device *phydev)
--{
-- struct nvmem_cell *cell;
-- int ret = 0;
-- size_t len;
-- u32 *buf;
--
-- cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
-- if (IS_ERR(cell)) {
-- if (PTR_ERR(cell) == -EPROBE_DEFER)
-- return PTR_ERR(cell);
-- return 0;
-- }
--
-- buf = (u32 *)nvmem_cell_read(cell, &len);
-- if (IS_ERR(buf))
-- return PTR_ERR(buf);
-- nvmem_cell_put(cell);
--
-- if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
-- phydev_err(phydev, "invalid efuse data\n");
-- ret = -EINVAL;
-- goto out;
-- }
--
-- ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-- if (ret)
-- goto out;
-- ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-- if (ret)
-- goto out;
-- ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-- if (ret)
-- goto out;
-- ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
-- if (ret)
-- goto out;
-- ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
-- if (ret)
-- goto out;
--
--out:
-- kfree(buf);
-- return ret;
--}
--
--static int mt798x_phy_config_init(struct phy_device *phydev)
--{
-- switch (phydev->drv->phy_id) {
-- case MTK_GPHY_ID_MT7981:
-- mt7981_phy_finetune(phydev);
-- break;
-- case MTK_GPHY_ID_MT7988:
-- mt7988_phy_finetune(phydev);
-- break;
-- }
--
-- mt798x_phy_common_finetune(phydev);
-- mt798x_phy_eee(phydev);
--
-- return mt798x_phy_calibration(phydev);
--}
--
--static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-- bool on)
--{
-- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- bool changed;
--
-- if (on)
-- changed = !test_and_set_bit(bit_on, &priv->led_state);
-- else
-- changed = !!test_and_clear_bit(bit_on, &priv->led_state);
--
-- changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-- (index ? 16 : 0), &priv->led_state);
-- if (changed)
-- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL :
-- MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_MASK,
-- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-- else
-- return 0;
--}
--
--static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-- bool blinking)
--{
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-- (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- bool changed;
--
-- if (blinking)
-- changed = !test_and_set_bit(bit_blink, &priv->led_state);
-- else
-- changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
--
-- changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-- (index ? 16 : 0), &priv->led_state);
-- if (changed)
-- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL,
-- blinking ?
-- MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-- else
-- return 0;
--}
--
--static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
-- unsigned long *delay_on,
-- unsigned long *delay_off)
--{
-- bool blinking = false;
-- int err = 0;
--
-- if (index > 1)
-- return -EINVAL;
--
-- if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-- blinking = true;
-- *delay_on = 50;
-- *delay_off = 50;
-- }
--
-- err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
-- if (err)
-- return err;
--
-- return mt798x_phy_hw_led_on_set(phydev, index, false);
--}
--
--static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
-- u8 index, enum led_brightness value)
--{
-- int err;
--
-- err = mt798x_phy_hw_led_blink_set(phydev, index, false);
-- if (err)
-- return err;
--
-- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
--}
--
--static const unsigned long supported_triggers =
-- BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-- BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-- BIT(TRIGGER_NETDEV_LINK) |
-- BIT(TRIGGER_NETDEV_LINK_10) |
-- BIT(TRIGGER_NETDEV_LINK_100) |
-- BIT(TRIGGER_NETDEV_LINK_1000) |
-- BIT(TRIGGER_NETDEV_RX) |
-- BIT(TRIGGER_NETDEV_TX);
--
--static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- if (index > 1)
-- return -EINVAL;
--
-- /* All combinations of the supported triggers are allowed */
-- if (rules & ~supported_triggers)
-- return -EOPNOTSUPP;
--
-- return 0;
--};
--
--static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-- unsigned long *rules)
--{
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-- (index ? 16 : 0);
-- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- int on, blink;
--
-- if (index > 1)
-- return -EINVAL;
--
-- on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
--
-- if (on < 0)
-- return -EIO;
--
-- blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- index ? MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL);
-- if (blink < 0)
-- return -EIO;
--
-- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-- MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
-- set_bit(bit_netdev, &priv->led_state);
-- else
-- clear_bit(bit_netdev, &priv->led_state);
--
-- if (on & MTK_PHY_LED_ON_FORCE_ON)
-- set_bit(bit_on, &priv->led_state);
-- else
-- clear_bit(bit_on, &priv->led_state);
--
-- if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-- set_bit(bit_blink, &priv->led_state);
-- else
-- clear_bit(bit_blink, &priv->led_state);
--
-- if (!rules)
-- return 0;
--
-- if (on & MTK_PHY_LED_ON_LINK)
-- *rules |= BIT(TRIGGER_NETDEV_LINK);
--
-- if (on & MTK_PHY_LED_ON_LINK10)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_10);
--
-- if (on & MTK_PHY_LED_ON_LINK100)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_100);
--
-- if (on & MTK_PHY_LED_ON_LINK1000)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
--
-- if (on & MTK_PHY_LED_ON_FDX)
-- *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
--
-- if (on & MTK_PHY_LED_ON_HDX)
-- *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
--
-- if (blink & MTK_PHY_LED_BLINK_RX)
-- *rules |= BIT(TRIGGER_NETDEV_RX);
--
-- if (blink & MTK_PHY_LED_BLINK_TX)
-- *rules |= BIT(TRIGGER_NETDEV_TX);
--
-- return 0;
--};
--
--static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- u16 on = 0, blink = 0;
-- int ret;
--
-- if (index > 1)
-- return -EINVAL;
--
-- if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-- on |= MTK_PHY_LED_ON_FDX;
--
-- if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-- on |= MTK_PHY_LED_ON_HDX;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK10;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK100;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK1000;
--
-- if (rules & BIT(TRIGGER_NETDEV_RX)) {
-- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000RX : 0)) :
-- MTK_PHY_LED_BLINK_RX;
-- }
--
-- if (rules & BIT(TRIGGER_NETDEV_TX)) {
-- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000TX : 0)) :
-- MTK_PHY_LED_BLINK_TX;
-- }
--
-- if (blink || on)
-- set_bit(bit_netdev, &priv->led_state);
-- else
-- clear_bit(bit_netdev, &priv->led_state);
--
-- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL :
-- MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_FDX |
-- MTK_PHY_LED_ON_HDX |
-- MTK_PHY_LED_ON_LINK,
-- on);
--
-- if (ret)
-- return ret;
--
-- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL, blink);
--};
--
--static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
--{
-- struct mtk_socphy_shared *priv = phydev->shared->priv;
-- u32 polarities;
--
-- if (led_num == 0)
-- polarities = ~(priv->boottrap);
-- else
-- polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
--
-- if (polarities & BIT(phydev->mdio.addr))
-- return true;
--
-- return false;
--}
--
--static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
--{
-- struct pinctrl *pinctrl;
-- int index;
--
-- /* Setup LED polarity according to bootstrap use of LED pins */
-- for (index = 0; index < 2; ++index)
-- phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_POLARITY,
-- mt7988_phy_led_get_polarity(phydev, index) ?
-- MTK_PHY_LED_ON_POLARITY : 0);
--
-- /* Only now setup pinctrl to avoid bogus blinking */
-- pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
-- if (IS_ERR(pinctrl))
-- dev_err(&phydev->mdio.bus->dev,
-- "Failed to setup PHY LED pinctrl\n");
--
-- return 0;
--}
--
--static int mt7988_phy_probe_shared(struct phy_device *phydev)
--{
-- struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
-- struct mtk_socphy_shared *shared = phydev->shared->priv;
-- struct regmap *regmap;
-- u32 reg;
-- int ret;
--
-- /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
-- * LED_C and LED_D respectively. At the same time those pins are used to
-- * bootstrap configuration of the reference clock source (LED_A),
-- * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
-- * In practice this is done using a LED and a resistor pulling the pin
-- * either to GND or to VIO.
-- * The detected value at boot time is accessible at run-time using the
-- * TPBANK0 register located in the gpio base of the pinctrl, in order
-- * to read it here it needs to be referenced by a phandle called
-- * 'mediatek,pio' in the MDIO bus hosting the PHY.
-- * The 4 bits in TPBANK0 are kept as package shared data and are used to
-- * set LED polarity for each of the LED0.
-- */
-- regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
-- if (IS_ERR(regmap))
-- return PTR_ERR(regmap);
--
-- ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®);
-- if (ret)
-- return ret;
--
-- shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
--
-- return 0;
--}
--
--static void mt798x_phy_leds_state_init(struct phy_device *phydev)
--{
-- int i;
--
-- for (i = 0; i < 2; ++i)
-- mt798x_phy_led_hw_control_get(phydev, i, NULL);
--}
--
--static int mt7988_phy_probe(struct phy_device *phydev)
--{
-- struct mtk_socphy_shared *shared;
-- struct mtk_socphy_priv *priv;
-- int err;
--
-- if (phydev->mdio.addr > 3)
-- return -EINVAL;
--
-- err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
-- sizeof(struct mtk_socphy_shared));
-- if (err)
-- return err;
--
-- if (phy_package_probe_once(phydev)) {
-- err = mt7988_phy_probe_shared(phydev);
-- if (err)
-- return err;
-- }
--
-- shared = phydev->shared->priv;
-- priv = &shared->priv[phydev->mdio.addr];
--
-- phydev->priv = priv;
--
-- mt798x_phy_leds_state_init(phydev);
--
-- err = mt7988_phy_fix_leds_polarities(phydev);
-- if (err)
-- return err;
--
-- /* Disable TX power saving at probing to:
-- * 1. Meet common mode compliance test criteria
-- * 2. Make sure that TX-VCM calibration works fine
-- */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
-- MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
--
-- return mt798x_phy_calibration(phydev);
--}
--
--static int mt7981_phy_probe(struct phy_device *phydev)
--{
-- struct mtk_socphy_priv *priv;
--
-- priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
-- GFP_KERNEL);
-- if (!priv)
-- return -ENOMEM;
--
-- phydev->priv = priv;
--
-- mt798x_phy_leds_state_init(phydev);
--
-- return mt798x_phy_calibration(phydev);
--}
--
--static struct phy_driver mtk_socphy_driver[] = {
-- {
-- PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
-- .name = "MediaTek MT7981 PHY",
-- .config_init = mt798x_phy_config_init,
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .probe = mt7981_phy_probe,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = mtk_socphy_read_page,
-- .write_page = mtk_socphy_write_page,
-- .led_blink_set = mt798x_phy_led_blink_set,
-- .led_brightness_set = mt798x_phy_led_brightness_set,
-- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-- .led_hw_control_set = mt798x_phy_led_hw_control_set,
-- .led_hw_control_get = mt798x_phy_led_hw_control_get,
-- },
-- {
-- PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
-- .name = "MediaTek MT7988 PHY",
-- .config_init = mt798x_phy_config_init,
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .probe = mt7988_phy_probe,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = mtk_socphy_read_page,
-- .write_page = mtk_socphy_write_page,
-- .led_blink_set = mt798x_phy_led_blink_set,
-- .led_brightness_set = mt798x_phy_led_brightness_set,
-- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-- .led_hw_control_set = mt798x_phy_led_hw_control_set,
-- .led_hw_control_get = mt798x_phy_led_hw_control_get,
-- },
--};
--
--module_phy_driver(mtk_socphy_driver);
--
--static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
-- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
-- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
-- { }
--};
--
--MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver");
--MODULE_LICENSE("GPL");
--
--MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
---- a/drivers/net/phy/mediatek-ge.c
-+++ /dev/null
-@@ -1,111 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--#include <linux/bitfield.h>
--#include <linux/module.h>
--#include <linux/phy.h>
--
--#define MTK_EXT_PAGE_ACCESS 0x1f
--#define MTK_PHY_PAGE_STANDARD 0x0000
--#define MTK_PHY_PAGE_EXTENDED 0x0001
--#define MTK_PHY_PAGE_EXTENDED_2 0x0002
--#define MTK_PHY_PAGE_EXTENDED_3 0x0003
--#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
--
--static int mtk_gephy_read_page(struct phy_device *phydev)
--{
-- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_gephy_write_page(struct phy_device *phydev, int page)
--{
-- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
--static void mtk_gephy_config_init(struct phy_device *phydev)
--{
-- /* Enable HW auto downshift */
-- phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
--
-- /* Increase SlvDPSready time */
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- __phy_write(phydev, 0x10, 0xafae);
-- __phy_write(phydev, 0x12, 0x2f);
-- __phy_write(phydev, 0x10, 0x8fae);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- /* Adjust 100_mse_threshold */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
--
-- /* Disable mcc */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
--}
--
--static int mt7530_phy_config_init(struct phy_device *phydev)
--{
-- mtk_gephy_config_init(phydev);
--
-- /* Increase post_update_timer */
-- phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
--
-- return 0;
--}
--
--static int mt7531_phy_config_init(struct phy_device *phydev)
--{
-- mtk_gephy_config_init(phydev);
--
-- /* PHY link down power saving enable */
-- phy_set_bits(phydev, 0x17, BIT(4));
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
--
-- /* Set TX Pair delay selection */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
--
-- return 0;
--}
--
--static struct phy_driver mtk_gephy_driver[] = {
-- {
-- PHY_ID_MATCH_EXACT(0x03a29412),
-- .name = "MediaTek MT7530 PHY",
-- .config_init = mt7530_phy_config_init,
-- /* Interrupts are handled by the switch, not the PHY
-- * itself.
-- */
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = mtk_gephy_read_page,
-- .write_page = mtk_gephy_write_page,
-- },
-- {
-- PHY_ID_MATCH_EXACT(0x03a29441),
-- .name = "MediaTek MT7531 PHY",
-- .config_init = mt7531_phy_config_init,
-- /* Interrupts are handled by the switch, not the PHY
-- * itself.
-- */
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = mtk_gephy_read_page,
-- .write_page = mtk_gephy_write_page,
-- },
--};
--
--module_phy_driver(mtk_gephy_driver);
--
--static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
-- { PHY_ID_MATCH_EXACT(0x03a29441) },
-- { PHY_ID_MATCH_EXACT(0x03a29412) },
-- { }
--};
--
--MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
--MODULE_LICENSE("GPL");
--
--MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -0,0 +1,1610 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+#include <linux/bitfield.h>
-+#include <linux/bitmap.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/nvmem-consumer.h>
-+#include <linux/pinctrl/consumer.h>
-+#include <linux/phy.h>
-+#include <linux/regmap.h>
-+
-+#define MTK_GPHY_ID_MT7981 0x03a29461
-+#define MTK_GPHY_ID_MT7988 0x03a29481
-+
-+#define MTK_EXT_PAGE_ACCESS 0x1f
-+#define MTK_PHY_PAGE_STANDARD 0x0000
-+#define MTK_PHY_PAGE_EXTENDED_3 0x0003
-+
-+#define MTK_PHY_LPI_REG_14 0x14
-+#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0)
-+
-+#define MTK_PHY_LPI_REG_1c 0x1c
-+#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
-+
-+#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-+#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-+
-+#define ANALOG_INTERNAL_OPERATION_MAX_US 20
-+#define TXRESERVE_MIN 0
-+#define TXRESERVE_MAX 7
-+
-+#define MTK_PHY_ANARG_RG 0x10
-+#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8)
-+
-+/* Registers on MDIO_MMD_VEND1 */
-+#define MTK_PHY_TXVLD_DA_RG 0x12
-+#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10)
-+#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16
-+#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10)
-+#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17
-+#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18
-+#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19
-+#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20
-+#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21
-+#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22
-+#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_RXADC_CTRL_RG7 0xc6
-+#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
-+
-+#define MTK_PHY_RXADC_CTRL_RG9 0xc8
-+#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12)
-+#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8)
-+#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4)
-+#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0)
-+
-+#define MTK_PHY_LDO_OUTPUT_V 0xd7
-+
-+#define MTK_PHY_RG_ANA_CAL_RG0 0xdb
-+#define MTK_PHY_RG_CAL_CKINV BIT(12)
-+#define MTK_PHY_RG_ANA_CALEN BIT(8)
-+#define MTK_PHY_RG_ZCALEN_A BIT(0)
-+
-+#define MTK_PHY_RG_ANA_CAL_RG1 0xdc
-+#define MTK_PHY_RG_ZCALEN_B BIT(12)
-+#define MTK_PHY_RG_ZCALEN_C BIT(8)
-+#define MTK_PHY_RG_ZCALEN_D BIT(4)
-+#define MTK_PHY_RG_TXVOS_CALEN BIT(0)
-+
-+#define MTK_PHY_RG_ANA_CAL_RG5 0xe0
-+#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8)
-+
-+#define MTK_PHY_RG_TX_FILTER 0xfe
-+
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120
-+#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8)
-+#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0)
-+
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122
-+#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0)
-+
-+#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144
-+#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5)
-+
-+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172
-+#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8)
-+#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0)
-+
-+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173
-+#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8)
-+#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
-+
-+#define MTK_PHY_RG_AD_CAL_COMP 0x17a
-+#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8)
-+
-+#define MTK_PHY_RG_AD_CAL_CLK 0x17b
-+#define MTK_PHY_DA_CAL_CLK BIT(0)
-+
-+#define MTK_PHY_RG_AD_CALIN 0x17c
-+#define MTK_PHY_DA_CALIN_FLAG BIT(0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d
-+#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e
-+#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f
-+#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180
-+#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181
-+#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182
-+#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183
-+#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184
-+#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DEV1E_REG19b 0x19b
-+#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8)
-+
-+#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a
-+#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b
-+#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c
-+#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d
-+#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e
-+#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f
-+#define MTK_PHY_RG_LP_IIR2_K4_L 0x230
-+#define MTK_PHY_RG_LP_IIR2_K4_U 0x231
-+#define MTK_PHY_RG_LP_IIR2_K5_L 0x232
-+#define MTK_PHY_RG_LP_IIR2_K5_U 0x233
-+
-+#define MTK_PHY_RG_DEV1E_REG234 0x234
-+#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0)
-+#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4)
-+#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12)
-+
-+#define MTK_PHY_RG_LPF_CNT_VAL 0x235
-+
-+#define MTK_PHY_RG_DEV1E_REG238 0x238
-+#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0)
-+#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12)
-+
-+#define MTK_PHY_RG_DEV1E_REG239 0x239
-+#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0)
-+#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12)
-+
-+#define MTK_PHY_RG_DEV1E_REG27C 0x27c
-+#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8)
-+#define MTK_PHY_RG_DEV1E_REG27D 0x27d
-+#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0)
-+
-+#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7
-+#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0)
-+#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8)
-+
-+#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1
-+#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0)
-+#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8)
-+#define MTK_PHY_LPI_TR_READY BIT(9)
-+#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10)
-+
-+#define MTK_PHY_RG_DEV1E_REG323 0x323
-+#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0)
-+#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4)
-+
-+#define MTK_PHY_RG_DEV1E_REG324 0x324
-+#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0)
-+#define MTK_PHY_SMI_DET_MAX_EN BIT(8)
-+
-+#define MTK_PHY_RG_DEV1E_REG326 0x326
-+#define MTK_PHY_LPI_MODE_SD_ON BIT(0)
-+#define MTK_PHY_RESET_RANDUPD_CNT BIT(1)
-+#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2)
-+#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4)
-+#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5)
-+
-+#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502
-+#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503
-+
-+#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d
-+#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e
-+#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f
-+#define MTK_PHY_DA_TX_R50_PAIR_D 0x540
-+
-+/* Registers on MDIO_MMD_VEND2 */
-+#define MTK_PHY_LED0_ON_CTRL 0x24
-+#define MTK_PHY_LED1_ON_CTRL 0x26
-+#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
-+#define MTK_PHY_LED_ON_LINK1000 BIT(0)
-+#define MTK_PHY_LED_ON_LINK100 BIT(1)
-+#define MTK_PHY_LED_ON_LINK10 BIT(2)
-+#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
-+ MTK_PHY_LED_ON_LINK100 |\
-+ MTK_PHY_LED_ON_LINK1000)
-+#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
-+#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
-+#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
-+#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
-+#define MTK_PHY_LED_ON_POLARITY BIT(14)
-+#define MTK_PHY_LED_ON_ENABLE BIT(15)
-+
-+#define MTK_PHY_LED0_BLINK_CTRL 0x25
-+#define MTK_PHY_LED1_BLINK_CTRL 0x27
-+#define MTK_PHY_LED_BLINK_1000TX BIT(0)
-+#define MTK_PHY_LED_BLINK_1000RX BIT(1)
-+#define MTK_PHY_LED_BLINK_100TX BIT(2)
-+#define MTK_PHY_LED_BLINK_100RX BIT(3)
-+#define MTK_PHY_LED_BLINK_10TX BIT(4)
-+#define MTK_PHY_LED_BLINK_10RX BIT(5)
-+#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
-+ MTK_PHY_LED_BLINK_100RX |\
-+ MTK_PHY_LED_BLINK_1000RX)
-+#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
-+ MTK_PHY_LED_BLINK_100TX |\
-+ MTK_PHY_LED_BLINK_1000TX)
-+#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
-+#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
-+#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
-+#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
-+
-+#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
-+
-+#define MTK_PHY_RG_BG_RASEL 0x115
-+#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0)
-+
-+/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
-+#define RG_GPIO_MISC_TPBANK0 0x6f0
-+#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8)
-+
-+/* These macro privides efuse parsing for internal phy. */
-+#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0))
-+#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0))
-+#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0))
-+#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0))
-+#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0))
-+
-+#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0))
-+#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0))
-+#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0))
-+#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0))
-+#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0))
-+
-+#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0))
-+#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0))
-+
-+#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0))
-+#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0))
-+
-+enum {
-+ NO_PAIR,
-+ PAIR_A,
-+ PAIR_B,
-+ PAIR_C,
-+ PAIR_D,
-+};
-+
-+enum calibration_mode {
-+ EFUSE_K,
-+ SW_K
-+};
-+
-+enum CAL_ITEM {
-+ REXT,
-+ TX_OFFSET,
-+ TX_AMP,
-+ TX_R50,
-+ TX_VCM
-+};
-+
-+enum CAL_MODE {
-+ EFUSE_M,
-+ SW_M
-+};
-+
-+#define MTK_PHY_LED_STATE_FORCE_ON 0
-+#define MTK_PHY_LED_STATE_FORCE_BLINK 1
-+#define MTK_PHY_LED_STATE_NETDEV 2
-+
-+struct mtk_socphy_priv {
-+ unsigned long led_state;
-+};
-+
-+struct mtk_socphy_shared {
-+ u32 boottrap;
-+ struct mtk_socphy_priv priv[4];
-+};
-+
-+static int mtk_socphy_read_page(struct phy_device *phydev)
-+{
-+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-+}
-+
-+static int mtk_socphy_write_page(struct phy_device *phydev, int page)
-+{
-+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-+}
-+
-+/* One calibration cycle consists of:
-+ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
-+ * until AD_CAL_COMP is ready to output calibration result.
-+ * 2.Wait until DA_CAL_CLK is available.
-+ * 3.Fetch AD_CAL_COMP_OUT.
-+ */
-+static int cal_cycle(struct phy_device *phydev, int devad,
-+ u32 regnum, u16 mask, u16 cal_val)
-+{
-+ int reg_val;
-+ int ret;
-+
-+ phy_modify_mmd(phydev, devad, regnum,
-+ mask, cal_val);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-+ MTK_PHY_DA_CALIN_FLAG);
-+
-+ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_AD_CAL_CLK, reg_val,
-+ reg_val & MTK_PHY_DA_CAL_CLK, 500,
-+ ANALOG_INTERNAL_OPERATION_MAX_US,
-+ false);
-+ if (ret) {
-+ phydev_err(phydev, "Calibration cycle timeout\n");
-+ return ret;
-+ }
-+
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-+ MTK_PHY_DA_CALIN_FLAG);
-+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
-+ if (ret < 0)
-+ return ret;
-+ ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
-+ phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
-+
-+ return ret;
-+}
-+
-+static int rext_fill_result(struct phy_device *phydev, u16 *buf)
-+{
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
-+ MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
-+ MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
-+
-+ return 0;
-+}
-+
-+static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
-+{
-+ u16 rext_cal_val[2];
-+
-+ rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
-+ rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
-+ rext_fill_result(phydev, rext_cal_val);
-+
-+ return 0;
-+}
-+
-+static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
-+{
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-+ MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-+ MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-+ MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-+ MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
-+
-+ return 0;
-+}
-+
-+static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
-+{
-+ u16 tx_offset_cal_val[4];
-+
-+ tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
-+ tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
-+ tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
-+ tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
-+
-+ tx_offset_fill_result(phydev, tx_offset_cal_val);
-+
-+ return 0;
-+}
-+
-+static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
-+{
-+ const int vals_9481[16] = { 10, 6, 6, 10,
-+ 10, 6, 6, 10,
-+ 10, 6, 6, 10,
-+ 10, 6, 6, 10 };
-+ const int vals_9461[16] = { 7, 1, 4, 7,
-+ 7, 1, 4, 7,
-+ 7, 1, 4, 7,
-+ 7, 1, 4, 7 };
-+ int bias[16] = {};
-+ int i;
-+
-+ switch (phydev->drv->phy_id) {
-+ case MTK_GPHY_ID_MT7981:
-+ /* We add some calibration to efuse values
-+ * due to board level influence.
-+ * GBE: +7, TBT: +1, HBT: +4, TST: +7
-+ */
-+ memcpy(bias, (const void *)vals_9461, sizeof(bias));
-+ break;
-+ case MTK_GPHY_ID_MT7988:
-+ memcpy(bias, (const void *)vals_9481, sizeof(bias));
-+ break;
-+ }
-+
-+ /* Prevent overflow */
-+ for (i = 0; i < 12; i++) {
-+ if (buf[i >> 2] + bias[i] > 63) {
-+ buf[i >> 2] = 63;
-+ bias[i] = 0;
-+ }
-+ }
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-+ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+ buf[0] + bias[0]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-+ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+ buf[0] + bias[1]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-+ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+ buf[0] + bias[2]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-+ MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+ buf[0] + bias[3]));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-+ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+ buf[1] + bias[4]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-+ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+ buf[1] + bias[5]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-+ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+ buf[1] + bias[6]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-+ MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+ buf[1] + bias[7]));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-+ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+ buf[2] + bias[8]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-+ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+ buf[2] + bias[9]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-+ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+ buf[2] + bias[10]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-+ MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+ buf[2] + bias[11]));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-+ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+ buf[3] + bias[12]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-+ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+ buf[3] + bias[13]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-+ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+ buf[3] + bias[14]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-+ MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+ buf[3] + bias[15]));
-+
-+ return 0;
-+}
-+
-+static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
-+{
-+ u16 tx_amp_cal_val[4];
-+
-+ tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
-+ tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
-+ tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
-+ tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
-+ tx_amp_fill_result(phydev, tx_amp_cal_val);
-+
-+ return 0;
-+}
-+
-+static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
-+ u8 txg_calen_x)
-+{
-+ int bias = 0;
-+ u16 reg, val;
-+
-+ if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
-+ bias = -1;
-+
-+ val = clamp_val(bias + tx_r50_cal_val, 0, 63);
-+
-+ switch (txg_calen_x) {
-+ case PAIR_A:
-+ reg = MTK_PHY_DA_TX_R50_PAIR_A;
-+ break;
-+ case PAIR_B:
-+ reg = MTK_PHY_DA_TX_R50_PAIR_B;
-+ break;
-+ case PAIR_C:
-+ reg = MTK_PHY_DA_TX_R50_PAIR_C;
-+ break;
-+ case PAIR_D:
-+ reg = MTK_PHY_DA_TX_R50_PAIR_D;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
-+
-+ return 0;
-+}
-+
-+static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
-+ u8 txg_calen_x)
-+{
-+ u16 tx_r50_cal_val;
-+
-+ switch (txg_calen_x) {
-+ case PAIR_A:
-+ tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
-+ break;
-+ case PAIR_B:
-+ tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
-+ break;
-+ case PAIR_C:
-+ tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
-+ break;
-+ case PAIR_D:
-+ tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
-+
-+ return 0;
-+}
-+
-+static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
-+{
-+ u8 lower_idx, upper_idx, txreserve_val;
-+ u8 lower_ret, upper_ret;
-+ int ret;
-+
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_ANA_CALEN);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_CAL_CKINV);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_TXVOS_CALEN);
-+
-+ switch (rg_txreserve_x) {
-+ case PAIR_A:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN0_A,
-+ MTK_PHY_DASN_DAC_IN0_A_MASK);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN1_A,
-+ MTK_PHY_DASN_DAC_IN1_A_MASK);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_ZCALEN_A);
-+ break;
-+ case PAIR_B:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN0_B,
-+ MTK_PHY_DASN_DAC_IN0_B_MASK);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN1_B,
-+ MTK_PHY_DASN_DAC_IN1_B_MASK);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_ZCALEN_B);
-+ break;
-+ case PAIR_C:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN0_C,
-+ MTK_PHY_DASN_DAC_IN0_C_MASK);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN1_C,
-+ MTK_PHY_DASN_DAC_IN1_C_MASK);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_ZCALEN_C);
-+ break;
-+ case PAIR_D:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN0_D,
-+ MTK_PHY_DASN_DAC_IN0_D_MASK);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN1_D,
-+ MTK_PHY_DASN_DAC_IN1_D_MASK);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_ZCALEN_D);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ goto restore;
-+ }
-+
-+ lower_idx = TXRESERVE_MIN;
-+ upper_idx = TXRESERVE_MAX;
-+
-+ phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
-+ while ((upper_idx - lower_idx) > 1) {
-+ txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
-+ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ txreserve_val << 12 | txreserve_val << 8 |
-+ txreserve_val << 4 | txreserve_val);
-+ if (ret == 1) {
-+ upper_idx = txreserve_val;
-+ upper_ret = ret;
-+ } else if (ret == 0) {
-+ lower_idx = txreserve_val;
-+ lower_ret = ret;
-+ } else {
-+ goto restore;
-+ }
-+ }
-+
-+ if (lower_idx == TXRESERVE_MIN) {
-+ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ lower_idx << 12 | lower_idx << 8 |
-+ lower_idx << 4 | lower_idx);
-+ ret = lower_ret;
-+ } else if (upper_idx == TXRESERVE_MAX) {
-+ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ upper_idx << 12 | upper_idx << 8 |
-+ upper_idx << 4 | upper_idx);
-+ ret = upper_ret;
-+ }
-+ if (ret < 0)
-+ goto restore;
-+
-+ /* We calibrate TX-VCM in different logic. Check upper index and then
-+ * lower index. If this calibration is valid, apply lower index's
-+ * result.
-+ */
-+ ret = upper_ret - lower_ret;
-+ if (ret == 1) {
-+ ret = 0;
-+ /* Make sure we use upper_idx in our calibration system */
-+ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ upper_idx << 12 | upper_idx << 8 |
-+ upper_idx << 4 | upper_idx);
-+ phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
-+ } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
-+ lower_ret == 1) {
-+ ret = 0;
-+ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ lower_idx << 12 | lower_idx << 8 |
-+ lower_idx << 4 | lower_idx);
-+ phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
-+ lower_idx);
-+ } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
-+ lower_ret == 0) {
-+ ret = 0;
-+ phydev_warn(phydev,
-+ "TX-VCM SW cal result at high margin 0x%x\n",
-+ upper_idx);
-+ } else {
-+ ret = -EINVAL;
-+ }
-+
-+restore:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_ANA_CALEN);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_TXVOS_CALEN);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_ZCALEN_A);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
-+ MTK_PHY_RG_ZCALEN_D);
-+
-+ return ret;
-+}
-+
-+static void mt798x_phy_common_finetune(struct phy_device *phydev)
-+{
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
-+ __phy_write(phydev, 0x11, 0xc71);
-+ __phy_write(phydev, 0x12, 0xc);
-+ __phy_write(phydev, 0x10, 0x8fae);
-+
-+ /* EnabRandUpdTrig = 1 */
-+ __phy_write(phydev, 0x11, 0x2f00);
-+ __phy_write(phydev, 0x12, 0xe);
-+ __phy_write(phydev, 0x10, 0x8fb0);
-+
-+ /* NormMseLoThresh = 85 */
-+ __phy_write(phydev, 0x11, 0x55a0);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x83aa);
-+
-+ /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
-+ __phy_write(phydev, 0x11, 0x240);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x9680);
-+
-+ /* TrFreeze = 0 (mt7988 default) */
-+ __phy_write(phydev, 0x11, 0x0);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x9686);
-+
-+ /* SSTrKp100 = 5 */
-+ /* SSTrKf100 = 6 */
-+ /* SSTrKp1000Mas = 5 */
-+ /* SSTrKf1000Mas = 6 */
-+ /* SSTrKp1000Slv = 5 */
-+ /* SSTrKf1000Slv = 6 */
-+ __phy_write(phydev, 0x11, 0xbaef);
-+ __phy_write(phydev, 0x12, 0x2e);
-+ __phy_write(phydev, 0x10, 0x968c);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+}
-+
-+static void mt7981_phy_finetune(struct phy_device *phydev)
-+{
-+ u16 val[8] = { 0x01ce, 0x01c1,
-+ 0x020f, 0x0202,
-+ 0x03d0, 0x03c0,
-+ 0x0013, 0x0005 };
-+ int i, k;
-+
-+ /* 100M eye finetune:
-+ * Keep middle level of TX MLT3 shapper as default.
-+ * Only change TX MLT3 overshoot level here.
-+ */
-+ for (k = 0, i = 1; i < 12; i++) {
-+ if (i % 3 == 0)
-+ continue;
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
-+ }
-+
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ /* ResetSyncOffset = 6 */
-+ __phy_write(phydev, 0x11, 0x600);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x8fc0);
-+
-+ /* VgaDecRate = 1 */
-+ __phy_write(phydev, 0x11, 0x4c2a);
-+ __phy_write(phydev, 0x12, 0x3e);
-+ __phy_write(phydev, 0x10, 0x8fa4);
-+
-+ /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
-+ * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
-+ */
-+ __phy_write(phydev, 0x11, 0xd10a);
-+ __phy_write(phydev, 0x12, 0x34);
-+ __phy_write(phydev, 0x10, 0x8f82);
-+
-+ /* VcoSlicerThreshBitsHigh */
-+ __phy_write(phydev, 0x11, 0x5555);
-+ __phy_write(phydev, 0x12, 0x55);
-+ __phy_write(phydev, 0x10, 0x8ec0);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+ MTK_PHY_LPF_X_AVERAGE_MASK,
-+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
-+
-+ /* rg_tr_lpf_cnt_val = 512 */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
-+
-+ /* IIR2 related */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
-+
-+ /* FFE peaking */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
-+ MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
-+ MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
-+
-+ /* Disable LDO pump */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
-+ /* Adjust LDO output voltage */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
-+}
-+
-+static void mt7988_phy_finetune(struct phy_device *phydev)
-+{
-+ u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
-+ 0x020d, 0x0206, 0x0384, 0x03d0,
-+ 0x03c6, 0x030a, 0x0011, 0x0005 };
-+ int i;
-+
-+ /* Set default MLT3 shaper first */
-+ for (i = 0; i < 12; i++)
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
-+
-+ /* TCT finetune */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
-+
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ /* ResetSyncOffset = 5 */
-+ __phy_write(phydev, 0x11, 0x500);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x8fc0);
-+
-+ /* VgaDecRate is 1 at default on mt7988 */
-+
-+ /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
-+ * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
-+ */
-+ __phy_write(phydev, 0x11, 0xb90a);
-+ __phy_write(phydev, 0x12, 0x6f);
-+ __phy_write(phydev, 0x10, 0x8f82);
-+
-+ /* RemAckCntLimitCtrl = 1 */
-+ __phy_write(phydev, 0x11, 0xfbba);
-+ __phy_write(phydev, 0x12, 0xc3);
-+ __phy_write(phydev, 0x10, 0x87f8);
-+
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+ MTK_PHY_LPF_X_AVERAGE_MASK,
-+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
-+
-+ /* rg_tr_lpf_cnt_val = 1023 */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
-+}
-+
-+static void mt798x_phy_eee(struct phy_device *phydev)
-+{
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
-+ MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
-+ MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
-+ FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-+ MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ 0xff));
-+
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_TESTMUX_ADC_CTRL,
-+ MTK_PHY_RG_TXEN_DIG_MASK);
-+
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
-+
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
-+ MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
-+ MTK_PHY_LPI_SLV_SEND_TX_EN,
-+ FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
-+
-+ /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
-+ MTK_PHY_LPI_TXPCS_LOC_RCV);
-+
-+ /* This also fixes some IoT issues, such as CH340 */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
-+ MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
-+ FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
-+ FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
-+ MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-+ FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-+ 0x33) |
-+ MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
-+ MTK_PHY_LPI_VCO_EEE_STG0_EN);
-+
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
-+ MTK_PHY_EEE_WAKE_MAS_INT_DC |
-+ MTK_PHY_EEE_WAKE_SLV_INT_DC);
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
-+ MTK_PHY_SMI_DETCNT_MAX_MASK,
-+ FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
-+ MTK_PHY_SMI_DET_MAX_EN);
-+
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
-+ MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
-+ MTK_PHY_TREC_UPDATE_ENAB_CLR |
-+ MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
-+ MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
-+
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ /* Regsigdet_sel_1000 = 0 */
-+ __phy_write(phydev, 0x11, 0xb);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x9690);
-+
-+ /* REG_EEE_st2TrKf1000 = 2 */
-+ __phy_write(phydev, 0x11, 0x114f);
-+ __phy_write(phydev, 0x12, 0x2);
-+ __phy_write(phydev, 0x10, 0x969a);
-+
-+ /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
-+ __phy_write(phydev, 0x11, 0x3028);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x969e);
-+
-+ /* RegEEE_slv_wake_int_timer_tar = 8 */
-+ __phy_write(phydev, 0x11, 0x5010);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x96a0);
-+
-+ /* RegEEE_trfreeze_timer2 = 586 */
-+ __phy_write(phydev, 0x11, 0x24a);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x96a8);
-+
-+ /* RegEEE100Stg1_tar = 16 */
-+ __phy_write(phydev, 0x11, 0x3210);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x96b8);
-+
-+ /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
-+ __phy_write(phydev, 0x11, 0x1463);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x96ca);
-+
-+ /* DfeTailEnableVgaThresh1000 = 27 */
-+ __phy_write(phydev, 0x11, 0x36);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x8f80);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
-+ __phy_modify(phydev, MTK_PHY_LPI_REG_14,
-+ MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
-+
-+ __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
-+ FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-+ MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ 0xff));
-+}
-+
-+static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
-+ u8 start_pair, u8 end_pair)
-+{
-+ u8 pair_n;
-+ int ret;
-+
-+ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-+ /* TX_OFFSET & TX_AMP have no SW calibration. */
-+ switch (cal_item) {
-+ case TX_VCM:
-+ ret = tx_vcm_cal_sw(phydev, pair_n);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ if (ret)
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
-+ u8 start_pair, u8 end_pair, u32 *buf)
-+{
-+ u8 pair_n;
-+ int ret;
-+
-+ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-+ /* TX_VCM has no efuse calibration. */
-+ switch (cal_item) {
-+ case REXT:
-+ ret = rext_cal_efuse(phydev, buf);
-+ break;
-+ case TX_OFFSET:
-+ ret = tx_offset_cal_efuse(phydev, buf);
-+ break;
-+ case TX_AMP:
-+ ret = tx_amp_cal_efuse(phydev, buf);
-+ break;
-+ case TX_R50:
-+ ret = tx_r50_cal_efuse(phydev, buf, pair_n);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
-+ enum CAL_MODE cal_mode, u8 start_pair,
-+ u8 end_pair, u32 *buf)
-+{
-+ int ret;
-+
-+ switch (cal_mode) {
-+ case EFUSE_M:
-+ ret = cal_efuse(phydev, cal_item, start_pair,
-+ end_pair, buf);
-+ break;
-+ case SW_M:
-+ ret = cal_sw(phydev, cal_item, start_pair, end_pair);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ if (ret) {
-+ phydev_err(phydev, "cal %d failed\n", cal_item);
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int mt798x_phy_calibration(struct phy_device *phydev)
-+{
-+ struct nvmem_cell *cell;
-+ int ret = 0;
-+ size_t len;
-+ u32 *buf;
-+
-+ cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
-+ if (IS_ERR(cell)) {
-+ if (PTR_ERR(cell) == -EPROBE_DEFER)
-+ return PTR_ERR(cell);
-+ return 0;
-+ }
-+
-+ buf = (u32 *)nvmem_cell_read(cell, &len);
-+ if (IS_ERR(buf))
-+ return PTR_ERR(buf);
-+ nvmem_cell_put(cell);
-+
-+ if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
-+ phydev_err(phydev, "invalid efuse data\n");
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-+ if (ret)
-+ goto out;
-+ ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-+ if (ret)
-+ goto out;
-+ ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-+ if (ret)
-+ goto out;
-+ ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
-+ if (ret)
-+ goto out;
-+ ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
-+ if (ret)
-+ goto out;
-+
-+out:
-+ kfree(buf);
-+ return ret;
-+}
-+
-+static int mt798x_phy_config_init(struct phy_device *phydev)
-+{
-+ switch (phydev->drv->phy_id) {
-+ case MTK_GPHY_ID_MT7981:
-+ mt7981_phy_finetune(phydev);
-+ break;
-+ case MTK_GPHY_ID_MT7988:
-+ mt7988_phy_finetune(phydev);
-+ break;
-+ }
-+
-+ mt798x_phy_common_finetune(phydev);
-+ mt798x_phy_eee(phydev);
-+
-+ return mt798x_phy_calibration(phydev);
-+}
-+
-+static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-+ bool on)
-+{
-+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (on)
-+ changed = !test_and_set_bit(bit_on, &priv->led_state);
-+ else
-+ changed = !!test_and_clear_bit(bit_on, &priv->led_state);
-+
-+ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-+ (index ? 16 : 0), &priv->led_state);
-+ if (changed)
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL :
-+ MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED_ON_MASK,
-+ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-+ else
-+ return 0;
-+}
-+
-+static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-+ bool blinking)
-+{
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (blinking)
-+ changed = !test_and_set_bit(bit_blink, &priv->led_state);
-+ else
-+ changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
-+
-+ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-+ (index ? 16 : 0), &priv->led_state);
-+ if (changed)
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL,
-+ blinking ?
-+ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-+ else
-+ return 0;
-+}
-+
-+static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ bool blinking = false;
-+ int err = 0;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-+ blinking = true;
-+ *delay_on = 50;
-+ *delay_off = 50;
-+ }
-+
-+ err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
-+ if (err)
-+ return err;
-+
-+ return mt798x_phy_hw_led_on_set(phydev, index, false);
-+}
-+
-+static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ int err;
-+
-+ err = mt798x_phy_hw_led_blink_set(phydev, index, false);
-+ if (err)
-+ return err;
-+
-+ return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
-+}
-+
-+static const unsigned long supported_triggers =
-+ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-+ BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX);
-+
-+static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ /* All combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+};
-+
-+static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
-+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ int on, blink;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
-+
-+ if (on < 0)
-+ return -EIO;
-+
-+ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ index ? MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL);
-+ if (blink < 0)
-+ return -EIO;
-+
-+ if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-+ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-+ (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
-+ set_bit(bit_netdev, &priv->led_state);
-+ else
-+ clear_bit(bit_netdev, &priv->led_state);
-+
-+ if (on & MTK_PHY_LED_ON_FORCE_ON)
-+ set_bit(bit_on, &priv->led_state);
-+ else
-+ clear_bit(bit_on, &priv->led_state);
-+
-+ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-+ set_bit(bit_blink, &priv->led_state);
-+ else
-+ clear_bit(bit_blink, &priv->led_state);
-+
-+ if (!rules)
-+ return 0;
-+
-+ if (on & MTK_PHY_LED_ON_LINK)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+ if (on & MTK_PHY_LED_ON_LINK10)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+ if (on & MTK_PHY_LED_ON_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (on & MTK_PHY_LED_ON_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if (on & MTK_PHY_LED_ON_FDX)
-+ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
-+
-+ if (on & MTK_PHY_LED_ON_HDX)
-+ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
-+
-+ if (blink & MTK_PHY_LED_BLINK_RX)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ if (blink & MTK_PHY_LED_BLINK_TX)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ return 0;
-+};
-+
-+static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ u16 on = 0, blink = 0;
-+ int ret;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-+ on |= MTK_PHY_LED_ON_FDX;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-+ on |= MTK_PHY_LED_ON_HDX;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK10;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK100;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK1000;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX)) {
-+ blink |= (on & MTK_PHY_LED_ON_LINK) ?
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000RX : 0)) :
-+ MTK_PHY_LED_BLINK_RX;
-+ }
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
-+ blink |= (on & MTK_PHY_LED_ON_LINK) ?
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000TX : 0)) :
-+ MTK_PHY_LED_BLINK_TX;
-+ }
-+
-+ if (blink || on)
-+ set_bit(bit_netdev, &priv->led_state);
-+ else
-+ clear_bit(bit_netdev, &priv->led_state);
-+
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL :
-+ MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED_ON_FDX |
-+ MTK_PHY_LED_ON_HDX |
-+ MTK_PHY_LED_ON_LINK,
-+ on);
-+
-+ if (ret)
-+ return ret;
-+
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL, blink);
-+};
-+
-+static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
-+{
-+ struct mtk_socphy_shared *priv = phydev->shared->priv;
-+ u32 polarities;
-+
-+ if (led_num == 0)
-+ polarities = ~(priv->boottrap);
-+ else
-+ polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
-+
-+ if (polarities & BIT(phydev->mdio.addr))
-+ return true;
-+
-+ return false;
-+}
-+
-+static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
-+{
-+ struct pinctrl *pinctrl;
-+ int index;
-+
-+ /* Setup LED polarity according to bootstrap use of LED pins */
-+ for (index = 0; index < 2; ++index)
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED_ON_POLARITY,
-+ mt7988_phy_led_get_polarity(phydev, index) ?
-+ MTK_PHY_LED_ON_POLARITY : 0);
-+
-+ /* Only now setup pinctrl to avoid bogus blinking */
-+ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
-+ if (IS_ERR(pinctrl))
-+ dev_err(&phydev->mdio.bus->dev,
-+ "Failed to setup PHY LED pinctrl\n");
-+
-+ return 0;
-+}
-+
-+static int mt7988_phy_probe_shared(struct phy_device *phydev)
-+{
-+ struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
-+ struct mtk_socphy_shared *shared = phydev->shared->priv;
-+ struct regmap *regmap;
-+ u32 reg;
-+ int ret;
-+
-+ /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
-+ * LED_C and LED_D respectively. At the same time those pins are used to
-+ * bootstrap configuration of the reference clock source (LED_A),
-+ * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
-+ * In practice this is done using a LED and a resistor pulling the pin
-+ * either to GND or to VIO.
-+ * The detected value at boot time is accessible at run-time using the
-+ * TPBANK0 register located in the gpio base of the pinctrl, in order
-+ * to read it here it needs to be referenced by a phandle called
-+ * 'mediatek,pio' in the MDIO bus hosting the PHY.
-+ * The 4 bits in TPBANK0 are kept as package shared data and are used to
-+ * set LED polarity for each of the LED0.
-+ */
-+ regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
-+ if (IS_ERR(regmap))
-+ return PTR_ERR(regmap);
-+
-+ ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®);
-+ if (ret)
-+ return ret;
-+
-+ shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
-+
-+ return 0;
-+}
-+
-+static void mt798x_phy_leds_state_init(struct phy_device *phydev)
-+{
-+ int i;
-+
-+ for (i = 0; i < 2; ++i)
-+ mt798x_phy_led_hw_control_get(phydev, i, NULL);
-+}
-+
-+static int mt7988_phy_probe(struct phy_device *phydev)
-+{
-+ struct mtk_socphy_shared *shared;
-+ struct mtk_socphy_priv *priv;
-+ int err;
-+
-+ if (phydev->mdio.addr > 3)
-+ return -EINVAL;
-+
-+ err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
-+ sizeof(struct mtk_socphy_shared));
-+ if (err)
-+ return err;
-+
-+ if (phy_package_probe_once(phydev)) {
-+ err = mt7988_phy_probe_shared(phydev);
-+ if (err)
-+ return err;
-+ }
-+
-+ shared = phydev->shared->priv;
-+ priv = &shared->priv[phydev->mdio.addr];
-+
-+ phydev->priv = priv;
-+
-+ mt798x_phy_leds_state_init(phydev);
-+
-+ err = mt7988_phy_fix_leds_polarities(phydev);
-+ if (err)
-+ return err;
-+
-+ /* Disable TX power saving at probing to:
-+ * 1. Meet common mode compliance test criteria
-+ * 2. Make sure that TX-VCM calibration works fine
-+ */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
-+ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
-+
-+ return mt798x_phy_calibration(phydev);
-+}
-+
-+static int mt7981_phy_probe(struct phy_device *phydev)
-+{
-+ struct mtk_socphy_priv *priv;
-+
-+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
-+ GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ phydev->priv = priv;
-+
-+ mt798x_phy_leds_state_init(phydev);
-+
-+ return mt798x_phy_calibration(phydev);
-+}
-+
-+static struct phy_driver mtk_socphy_driver[] = {
-+ {
-+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
-+ .name = "MediaTek MT7981 PHY",
-+ .config_init = mt798x_phy_config_init,
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .probe = mt7981_phy_probe,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = mtk_socphy_read_page,
-+ .write_page = mtk_socphy_write_page,
-+ .led_blink_set = mt798x_phy_led_blink_set,
-+ .led_brightness_set = mt798x_phy_led_brightness_set,
-+ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-+ .led_hw_control_set = mt798x_phy_led_hw_control_set,
-+ .led_hw_control_get = mt798x_phy_led_hw_control_get,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
-+ .name = "MediaTek MT7988 PHY",
-+ .config_init = mt798x_phy_config_init,
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .probe = mt7988_phy_probe,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = mtk_socphy_read_page,
-+ .write_page = mtk_socphy_write_page,
-+ .led_blink_set = mt798x_phy_led_blink_set,
-+ .led_brightness_set = mt798x_phy_led_brightness_set,
-+ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-+ .led_hw_control_set = mt798x_phy_led_hw_control_set,
-+ .led_hw_control_get = mt798x_phy_led_hw_control_get,
-+ },
-+};
-+
-+module_phy_driver(mtk_socphy_driver);
-+
-+static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
-+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
-+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
-+ { }
-+};
-+
-+MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -0,0 +1,111 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+#include <linux/bitfield.h>
-+#include <linux/module.h>
-+#include <linux/phy.h>
-+
-+#define MTK_EXT_PAGE_ACCESS 0x1f
-+#define MTK_PHY_PAGE_STANDARD 0x0000
-+#define MTK_PHY_PAGE_EXTENDED 0x0001
-+#define MTK_PHY_PAGE_EXTENDED_2 0x0002
-+#define MTK_PHY_PAGE_EXTENDED_3 0x0003
-+#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-+#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-+
-+static int mtk_gephy_read_page(struct phy_device *phydev)
-+{
-+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-+}
-+
-+static int mtk_gephy_write_page(struct phy_device *phydev, int page)
-+{
-+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-+}
-+
-+static void mtk_gephy_config_init(struct phy_device *phydev)
-+{
-+ /* Enable HW auto downshift */
-+ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
-+
-+ /* Increase SlvDPSready time */
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ __phy_write(phydev, 0x10, 0xafae);
-+ __phy_write(phydev, 0x12, 0x2f);
-+ __phy_write(phydev, 0x10, 0x8fae);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ /* Adjust 100_mse_threshold */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
-+
-+ /* Disable mcc */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
-+}
-+
-+static int mt7530_phy_config_init(struct phy_device *phydev)
-+{
-+ mtk_gephy_config_init(phydev);
-+
-+ /* Increase post_update_timer */
-+ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
-+
-+ return 0;
-+}
-+
-+static int mt7531_phy_config_init(struct phy_device *phydev)
-+{
-+ mtk_gephy_config_init(phydev);
-+
-+ /* PHY link down power saving enable */
-+ phy_set_bits(phydev, 0x17, BIT(4));
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
-+
-+ /* Set TX Pair delay selection */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
-+
-+ return 0;
-+}
-+
-+static struct phy_driver mtk_gephy_driver[] = {
-+ {
-+ PHY_ID_MATCH_EXACT(0x03a29412),
-+ .name = "MediaTek MT7530 PHY",
-+ .config_init = mt7530_phy_config_init,
-+ /* Interrupts are handled by the switch, not the PHY
-+ * itself.
-+ */
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = mtk_gephy_read_page,
-+ .write_page = mtk_gephy_write_page,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(0x03a29441),
-+ .name = "MediaTek MT7531 PHY",
-+ .config_init = mt7531_phy_config_init,
-+ /* Interrupts are handled by the switch, not the PHY
-+ * itself.
-+ */
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = mtk_gephy_read_page,
-+ .write_page = mtk_gephy_write_page,
-+ },
-+};
-+
-+module_phy_driver(mtk_gephy_driver);
-+
-+static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
-+ { PHY_ID_MATCH_EXACT(0x03a29441) },
-+ { PHY_ID_MATCH_EXACT(0x03a29412) },
-+ { }
-+};
-+
-+MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
+++ /dev/null
-From 71d88c7409b91c853d7f9c933f5e27933d656e5e Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 00:34:52 +0800
-Subject: [PATCH 05/20] net: phy: mediatek: Move LED helper functions into mtk
- phy lib
-
-This patch creates mtk-phy-lib.c & mtk-phy.h and integrates mtk-ge-soc.c's
-LED helper functions so that we can use those helper functions in other
-MTK's ethernet phy driver.
-
----
- MAINTAINERS | 2 +
- drivers/net/phy/mediatek/Kconfig | 4 +
- drivers/net/phy/mediatek/Makefile | 1 +
- drivers/net/phy/mediatek/mtk-ge-soc.c | 280 +++----------------------
- drivers/net/phy/mediatek/mtk-phy-lib.c | 254 ++++++++++++++++++++++
- drivers/net/phy/mediatek/mtk.h | 86 ++++++++
- 6 files changed, 372 insertions(+), 255 deletions(-)
- create mode 100644 drivers/net/phy/mediatek/mtk-phy-lib.c
- create mode 100644 drivers/net/phy/mediatek/mtk.h
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -14428,7 +14428,9 @@ M: SkyLake Huang <SkyLake.Huang@mediatek
- S: Maintained
- F: drivers/net/phy/mediatek/mtk-ge-soc.c
-+F: drivers/net/phy/mediatek/mtk-phy-lib.c
- F: drivers/net/phy/mediatek/mtk-ge.c
-+F: drivers/net/phy/mediatek/mtk.h
- F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c
-
- MEDIATEK I2C CONTROLLER DRIVER
---- a/drivers/net/phy/mediatek/Kconfig
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -1,4 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0-only
-+config MTK_NET_PHYLIB
-+ tristate
-+
- config MEDIATEK_GE_PHY
- tristate "MediaTek Gigabit Ethernet PHYs"
- help
-@@ -13,6 +16,7 @@ config MEDIATEK_GE_SOC_PHY
- tristate "MediaTek SoC Ethernet PHYs"
- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
- depends on NVMEM_MTK_EFUSE
-+ select MTK_NET_PHYLIB
- help
- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
-
---- a/drivers/net/phy/mediatek/Makefile
-+++ b/drivers/net/phy/mediatek/Makefile
-@@ -1,3 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o
- obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
- obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -8,6 +8,8 @@
- #include <linux/phy.h>
- #include <linux/regmap.h>
-
-+#include "mtk.h"
-+
- #define MTK_GPHY_ID_MT7981 0x03a29461
- #define MTK_GPHY_ID_MT7988 0x03a29481
-
-@@ -210,41 +212,6 @@
- #define MTK_PHY_DA_TX_R50_PAIR_D 0x540
-
- /* Registers on MDIO_MMD_VEND2 */
--#define MTK_PHY_LED0_ON_CTRL 0x24
--#define MTK_PHY_LED1_ON_CTRL 0x26
--#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
--#define MTK_PHY_LED_ON_LINK1000 BIT(0)
--#define MTK_PHY_LED_ON_LINK100 BIT(1)
--#define MTK_PHY_LED_ON_LINK10 BIT(2)
--#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
-- MTK_PHY_LED_ON_LINK100 |\
-- MTK_PHY_LED_ON_LINK1000)
--#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
--#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
--#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
--#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
--#define MTK_PHY_LED_ON_POLARITY BIT(14)
--#define MTK_PHY_LED_ON_ENABLE BIT(15)
--
--#define MTK_PHY_LED0_BLINK_CTRL 0x25
--#define MTK_PHY_LED1_BLINK_CTRL 0x27
--#define MTK_PHY_LED_BLINK_1000TX BIT(0)
--#define MTK_PHY_LED_BLINK_1000RX BIT(1)
--#define MTK_PHY_LED_BLINK_100TX BIT(2)
--#define MTK_PHY_LED_BLINK_100RX BIT(3)
--#define MTK_PHY_LED_BLINK_10TX BIT(4)
--#define MTK_PHY_LED_BLINK_10RX BIT(5)
--#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
-- MTK_PHY_LED_BLINK_100RX |\
-- MTK_PHY_LED_BLINK_1000RX)
--#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
-- MTK_PHY_LED_BLINK_100TX |\
-- MTK_PHY_LED_BLINK_1000TX)
--#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
--#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
--#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
--#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
--
- #define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
-
- #define MTK_PHY_RG_BG_RASEL 0x115
-@@ -299,14 +266,6 @@ enum CAL_MODE {
- SW_M
- };
-
--#define MTK_PHY_LED_STATE_FORCE_ON 0
--#define MTK_PHY_LED_STATE_FORCE_BLINK 1
--#define MTK_PHY_LED_STATE_NETDEV 2
--
--struct mtk_socphy_priv {
-- unsigned long led_state;
--};
--
- struct mtk_socphy_shared {
- u32 boottrap;
- struct mtk_socphy_priv priv[4];
-@@ -1172,76 +1131,23 @@ static int mt798x_phy_config_init(struct
- return mt798x_phy_calibration(phydev);
- }
-
--static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-- bool on)
--{
-- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- bool changed;
--
-- if (on)
-- changed = !test_and_set_bit(bit_on, &priv->led_state);
-- else
-- changed = !!test_and_clear_bit(bit_on, &priv->led_state);
--
-- changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-- (index ? 16 : 0), &priv->led_state);
-- if (changed)
-- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL :
-- MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_MASK,
-- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-- else
-- return 0;
--}
--
--static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-- bool blinking)
--{
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-- (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- bool changed;
--
-- if (blinking)
-- changed = !test_and_set_bit(bit_blink, &priv->led_state);
-- else
-- changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
--
-- changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-- (index ? 16 : 0), &priv->led_state);
-- if (changed)
-- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL,
-- blinking ?
-- MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-- else
-- return 0;
--}
--
- static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
- unsigned long *delay_on,
- unsigned long *delay_off)
- {
- bool blinking = false;
-- int err = 0;
--
-- if (index > 1)
-- return -EINVAL;
-+ int err;
-
-- if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-- blinking = true;
-- *delay_on = 50;
-- *delay_off = 50;
-- }
-+ err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
-+ if (err < 0)
-+ return err;
-
-- err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
-+ err = mtk_phy_hw_led_blink_set(phydev, index, blinking);
- if (err)
- return err;
-
-- return mt798x_phy_hw_led_on_set(phydev, index, false);
-+ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
-+ false);
- }
-
- static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
-@@ -1249,11 +1155,12 @@ static int mt798x_phy_led_brightness_set
- {
- int err;
-
-- err = mt798x_phy_hw_led_blink_set(phydev, index, false);
-+ err = mtk_phy_hw_led_blink_set(phydev, index, false);
- if (err)
- return err;
-
-- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
-+ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
-+ (value != LED_OFF));
- }
-
- static const unsigned long supported_triggers =
-@@ -1269,155 +1176,26 @@ static const unsigned long supported_tri
- static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules)
- {
-- if (index > 1)
-- return -EINVAL;
--
-- /* All combinations of the supported triggers are allowed */
-- if (rules & ~supported_triggers)
-- return -EOPNOTSUPP;
--
-- return 0;
--};
-+ return mtk_phy_led_hw_is_supported(phydev, index, rules,
-+ supported_triggers);
-+}
-
- static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
- unsigned long *rules)
- {
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-- (index ? 16 : 0);
-- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- int on, blink;
--
-- if (index > 1)
-- return -EINVAL;
--
-- on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
--
-- if (on < 0)
-- return -EIO;
--
-- blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- index ? MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL);
-- if (blink < 0)
-- return -EIO;
--
-- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-- MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
-- set_bit(bit_netdev, &priv->led_state);
-- else
-- clear_bit(bit_netdev, &priv->led_state);
--
-- if (on & MTK_PHY_LED_ON_FORCE_ON)
-- set_bit(bit_on, &priv->led_state);
-- else
-- clear_bit(bit_on, &priv->led_state);
--
-- if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-- set_bit(bit_blink, &priv->led_state);
-- else
-- clear_bit(bit_blink, &priv->led_state);
--
-- if (!rules)
-- return 0;
--
-- if (on & MTK_PHY_LED_ON_LINK)
-- *rules |= BIT(TRIGGER_NETDEV_LINK);
--
-- if (on & MTK_PHY_LED_ON_LINK10)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_10);
--
-- if (on & MTK_PHY_LED_ON_LINK100)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_100);
--
-- if (on & MTK_PHY_LED_ON_LINK1000)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
--
-- if (on & MTK_PHY_LED_ON_FDX)
-- *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
--
-- if (on & MTK_PHY_LED_ON_HDX)
-- *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
--
-- if (blink & MTK_PHY_LED_BLINK_RX)
-- *rules |= BIT(TRIGGER_NETDEV_RX);
--
-- if (blink & MTK_PHY_LED_BLINK_TX)
-- *rules |= BIT(TRIGGER_NETDEV_TX);
--
-- return 0;
-+ return mtk_phy_led_hw_ctrl_get(phydev, index, rules,
-+ MTK_GPHY_LED_ON_SET,
-+ MTK_GPHY_LED_RX_BLINK_SET,
-+ MTK_GPHY_LED_TX_BLINK_SET);
- };
-
- static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
- unsigned long rules)
- {
-- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- u16 on = 0, blink = 0;
-- int ret;
--
-- if (index > 1)
-- return -EINVAL;
--
-- if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-- on |= MTK_PHY_LED_ON_FDX;
--
-- if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-- on |= MTK_PHY_LED_ON_HDX;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK10;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK100;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK1000;
--
-- if (rules & BIT(TRIGGER_NETDEV_RX)) {
-- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000RX : 0)) :
-- MTK_PHY_LED_BLINK_RX;
-- }
--
-- if (rules & BIT(TRIGGER_NETDEV_TX)) {
-- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000TX : 0)) :
-- MTK_PHY_LED_BLINK_TX;
-- }
--
-- if (blink || on)
-- set_bit(bit_netdev, &priv->led_state);
-- else
-- clear_bit(bit_netdev, &priv->led_state);
--
-- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL :
-- MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_FDX |
-- MTK_PHY_LED_ON_HDX |
-- MTK_PHY_LED_ON_LINK,
-- on);
--
-- if (ret)
-- return ret;
--
-- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL, blink);
-+ return mtk_phy_led_hw_ctrl_set(phydev, index, rules,
-+ MTK_GPHY_LED_ON_SET,
-+ MTK_GPHY_LED_RX_BLINK_SET,
-+ MTK_GPHY_LED_TX_BLINK_SET);
- };
-
- static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
-@@ -1492,14 +1270,6 @@ static int mt7988_phy_probe_shared(struc
- return 0;
- }
-
--static void mt798x_phy_leds_state_init(struct phy_device *phydev)
--{
-- int i;
--
-- for (i = 0; i < 2; ++i)
-- mt798x_phy_led_hw_control_get(phydev, i, NULL);
--}
--
- static int mt7988_phy_probe(struct phy_device *phydev)
- {
- struct mtk_socphy_shared *shared;
-@@ -1525,7 +1295,7 @@ static int mt7988_phy_probe(struct phy_d
-
- phydev->priv = priv;
-
-- mt798x_phy_leds_state_init(phydev);
-+ mtk_phy_leds_state_init(phydev);
-
- err = mt7988_phy_fix_leds_polarities(phydev);
- if (err)
-@@ -1552,7 +1322,7 @@ static int mt7981_phy_probe(struct phy_d
-
- phydev->priv = priv;
-
-- mt798x_phy_leds_state_init(phydev);
-+ mtk_phy_leds_state_init(phydev);
-
- return mt798x_phy_calibration(phydev);
- }
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -0,0 +1,254 @@
-+// SPDX-License-Identifier: GPL-2.0
-+#include <linux/phy.h>
-+#include <linux/module.h>
-+
-+#include <linux/netdevice.h>
-+
-+#include "mtk.h"
-+
-+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules,
-+ unsigned long supported_triggers)
-+{
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ /* All combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
-+
-+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules, u16 on_set,
-+ u16 rx_blink_set, u16 tx_blink_set)
-+{
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
-+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ int on, blink;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
-+
-+ if (on < 0)
-+ return -EIO;
-+
-+ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ index ? MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL);
-+ if (blink < 0)
-+ return -EIO;
-+
-+ if ((on & (on_set | MTK_PHY_LED_ON_FDX |
-+ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-+ (blink & (rx_blink_set | tx_blink_set)))
-+ set_bit(bit_netdev, &priv->led_state);
-+ else
-+ clear_bit(bit_netdev, &priv->led_state);
-+
-+ if (on & MTK_PHY_LED_ON_FORCE_ON)
-+ set_bit(bit_on, &priv->led_state);
-+ else
-+ clear_bit(bit_on, &priv->led_state);
-+
-+ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-+ set_bit(bit_blink, &priv->led_state);
-+ else
-+ clear_bit(bit_blink, &priv->led_state);
-+
-+ if (!rules)
-+ return 0;
-+
-+ if (on & on_set)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+ if (on & MTK_PHY_LED_ON_LINK10)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+ if (on & MTK_PHY_LED_ON_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (on & MTK_PHY_LED_ON_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if (on & MTK_PHY_LED_ON_LINK2500)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
-+
-+ if (on & MTK_PHY_LED_ON_FDX)
-+ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
-+
-+ if (on & MTK_PHY_LED_ON_HDX)
-+ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
-+
-+ if (blink & rx_blink_set)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ if (blink & tx_blink_set)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
-+
-+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules, u16 on_set,
-+ u16 rx_blink_set, u16 tx_blink_set)
-+{
-+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ u16 on = 0, blink = 0;
-+ int ret;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-+ on |= MTK_PHY_LED_ON_FDX;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-+ on |= MTK_PHY_LED_ON_HDX;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK10;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK100;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK1000;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK2500;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX)) {
-+ blink |= (on & on_set) ?
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK2500) ?
-+ MTK_PHY_LED_BLINK_2500RX : 0)) :
-+ rx_blink_set;
-+ }
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
-+ blink |= (on & on_set) ?
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK2500) ?
-+ MTK_PHY_LED_BLINK_2500TX : 0)) :
-+ tx_blink_set;
-+ }
-+
-+ if (blink || on)
-+ set_bit(bit_netdev, &priv->led_state);
-+ else
-+ clear_bit(bit_netdev, &priv->led_state);
-+
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
-+ on);
-+
-+ if (ret)
-+ return ret;
-+
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL, blink);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
-+
-+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
-+ unsigned long *delay_off, bool *blinking)
-+{
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-+ *blinking = true;
-+ *delay_on = 50;
-+ *delay_off = 50;
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
-+
-+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-+ u16 led_on_mask, bool on)
-+{
-+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (on)
-+ changed = !test_and_set_bit(bit_on, &priv->led_state);
-+ else
-+ changed = !!test_and_clear_bit(bit_on, &priv->led_state);
-+
-+ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-+ (index ? 16 : 0), &priv->led_state);
-+ if (changed)
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL :
-+ MTK_PHY_LED0_ON_CTRL,
-+ led_on_mask,
-+ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-+ else
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
-+
-+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking)
-+{
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (blinking)
-+ changed = !test_and_set_bit(bit_blink, &priv->led_state);
-+ else
-+ changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
-+
-+ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-+ (index ? 16 : 0), &priv->led_state);
-+ if (changed)
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL,
-+ blinking ?
-+ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-+ else
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
-+
-+void mtk_phy_leds_state_init(struct phy_device *phydev)
-+{
-+ int i;
-+
-+ for (i = 0; i < 2; ++i)
-+ phydev->drv->led_hw_control_get(phydev, i, NULL);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
-+
-+MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -0,0 +1,86 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Common definition for Mediatek Ethernet PHYs
-+ * Copyright (c) 2024 MediaTek Inc.
-+ */
-+
-+#ifndef _MTK_EPHY_H_
-+#define _MTK_EPHY_H_
-+
-+#define MTK_EXT_PAGE_ACCESS 0x1f
-+
-+/* Registers on MDIO_MMD_VEND2 */
-+#define MTK_PHY_LED0_ON_CTRL 0x24
-+#define MTK_PHY_LED1_ON_CTRL 0x26
-+#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0)
-+#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0)
-+#define MTK_PHY_LED_ON_LINK1000 BIT(0)
-+#define MTK_PHY_LED_ON_LINK100 BIT(1)
-+#define MTK_PHY_LED_ON_LINK10 BIT(2)
-+#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
-+#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
-+#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
-+#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
-+#define MTK_PHY_LED_ON_LINK2500 BIT(7)
-+#define MTK_PHY_LED_ON_POLARITY BIT(14)
-+#define MTK_PHY_LED_ON_ENABLE BIT(15)
-+
-+#define MTK_PHY_LED0_BLINK_CTRL 0x25
-+#define MTK_PHY_LED1_BLINK_CTRL 0x27
-+#define MTK_PHY_LED_BLINK_1000TX BIT(0)
-+#define MTK_PHY_LED_BLINK_1000RX BIT(1)
-+#define MTK_PHY_LED_BLINK_100TX BIT(2)
-+#define MTK_PHY_LED_BLINK_100RX BIT(3)
-+#define MTK_PHY_LED_BLINK_10TX BIT(4)
-+#define MTK_PHY_LED_BLINK_10RX BIT(5)
-+#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
-+#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
-+#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
-+#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
-+#define MTK_PHY_LED_BLINK_2500TX BIT(10)
-+#define MTK_PHY_LED_BLINK_2500RX BIT(11)
-+
-+#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \
-+ MTK_PHY_LED_ON_LINK100 | \
-+ MTK_PHY_LED_ON_LINK10)
-+#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
-+ MTK_PHY_LED_BLINK_100RX | \
-+ MTK_PHY_LED_BLINK_10RX)
-+#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
-+ MTK_PHY_LED_BLINK_100RX | \
-+ MTK_PHY_LED_BLINK_10RX)
-+
-+#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \
-+ MTK_GPHY_LED_ON_SET)
-+#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
-+ MTK_GPHY_LED_RX_BLINK_SET)
-+#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
-+ MTK_GPHY_LED_TX_BLINK_SET)
-+
-+#define MTK_PHY_LED_STATE_FORCE_ON 0
-+#define MTK_PHY_LED_STATE_FORCE_BLINK 1
-+#define MTK_PHY_LED_STATE_NETDEV 2
-+
-+struct mtk_socphy_priv {
-+ unsigned long led_state;
-+};
-+
-+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules,
-+ unsigned long supported_triggers);
-+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules, u16 on_set,
-+ u16 rx_blink_set, u16 tx_blink_set);
-+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules, u16 on_set,
-+ u16 rx_blink_set, u16 tx_blink_set);
-+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
-+ unsigned long *delay_off, bool *blinking);
-+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-+ u16 led_on_mask, bool on);
-+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-+ bool blinking);
-+void mtk_phy_leds_state_init(struct phy_device *phydev);
-+
-+#endif /* _MTK_EPHY_H_ */
+++ /dev/null
-From 3efd0595fc7aaae300f5d9f4f0ae86f432c8d2c7 Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 00:34:53 +0800
-Subject: [PATCH 06/20] net: phy: mediatek: Improve readability of
- mtk-phy-lib.c's mtk_phy_led_hw_ctrl_set()
-
-This patch removes parens around TRIGGER_NETDEV_RX/TRIGGER_NETDEV_TX in
-mtk_phy_led_hw_ctrl_set(), which improves readability.
-
----
- drivers/net/phy/mediatek/mtk-phy-lib.c | 44 ++++++++++++++------------
- 1 file changed, 24 insertions(+), 20 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -129,29 +129,33 @@ int mtk_phy_led_hw_ctrl_set(struct phy_d
- on |= MTK_PHY_LED_ON_LINK2500;
-
- if (rules & BIT(TRIGGER_NETDEV_RX)) {
-- blink |= (on & on_set) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK2500) ?
-- MTK_PHY_LED_BLINK_2500RX : 0)) :
-- rx_blink_set;
-+ if (on & on_set) {
-+ if (on & MTK_PHY_LED_ON_LINK10)
-+ blink |= MTK_PHY_LED_BLINK_10RX;
-+ if (on & MTK_PHY_LED_ON_LINK100)
-+ blink |= MTK_PHY_LED_BLINK_100RX;
-+ if (on & MTK_PHY_LED_ON_LINK1000)
-+ blink |= MTK_PHY_LED_BLINK_1000RX;
-+ if (on & MTK_PHY_LED_ON_LINK2500)
-+ blink |= MTK_PHY_LED_BLINK_2500RX;
-+ } else {
-+ blink |= rx_blink_set;
-+ }
- }
-
- if (rules & BIT(TRIGGER_NETDEV_TX)) {
-- blink |= (on & on_set) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK2500) ?
-- MTK_PHY_LED_BLINK_2500TX : 0)) :
-- tx_blink_set;
-+ if (on & on_set) {
-+ if (on & MTK_PHY_LED_ON_LINK10)
-+ blink |= MTK_PHY_LED_BLINK_10TX;
-+ if (on & MTK_PHY_LED_ON_LINK100)
-+ blink |= MTK_PHY_LED_BLINK_100TX;
-+ if (on & MTK_PHY_LED_ON_LINK1000)
-+ blink |= MTK_PHY_LED_BLINK_1000TX;
-+ if (on & MTK_PHY_LED_ON_LINK2500)
-+ blink |= MTK_PHY_LED_BLINK_2500TX;
-+ } else {
-+ blink |= tx_blink_set;
-+ }
- }
-
- if (blink || on)
+++ /dev/null
-From 50a97d716105a5f35aaecca0bdfe8e23cba0e87f Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 00:34:54 +0800
-Subject: [PATCH 07/20] net: phy: mediatek: Integrate read/write page helper
- functions
-
-This patch integrates read/write page helper functions as MTK phy lib.
-They are basically the same in mtk-ge.c & mtk-ge-soc.c.
-
----
- drivers/net/phy/mediatek/Kconfig | 1 +
- drivers/net/phy/mediatek/mtk-ge-soc.c | 18 ++++--------------
- drivers/net/phy/mediatek/mtk-ge.c | 20 ++++++--------------
- drivers/net/phy/mediatek/mtk-phy-lib.c | 12 ++++++++++++
- drivers/net/phy/mediatek/mtk.h | 3 +++
- 5 files changed, 26 insertions(+), 28 deletions(-)
-
---- a/drivers/net/phy/mediatek/Kconfig
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -4,6 +4,7 @@ config MTK_NET_PHYLIB
-
- config MEDIATEK_GE_PHY
- tristate "MediaTek Gigabit Ethernet PHYs"
-+ select MTK_NET_PHYLIB
- help
- Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -271,16 +271,6 @@ struct mtk_socphy_shared {
- struct mtk_socphy_priv priv[4];
- };
-
--static int mtk_socphy_read_page(struct phy_device *phydev)
--{
-- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_socphy_write_page(struct phy_device *phydev, int page)
--{
-- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
- /* One calibration cycle consists of:
- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
- * until AD_CAL_COMP is ready to output calibration result.
-@@ -1337,8 +1327,8 @@ static struct phy_driver mtk_socphy_driv
- .probe = mt7981_phy_probe,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-- .read_page = mtk_socphy_read_page,
-- .write_page = mtk_socphy_write_page,
-+ .read_page = mtk_phy_read_page,
-+ .write_page = mtk_phy_write_page,
- .led_blink_set = mt798x_phy_led_blink_set,
- .led_brightness_set = mt798x_phy_led_brightness_set,
- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-@@ -1354,8 +1344,8 @@ static struct phy_driver mtk_socphy_driv
- .probe = mt7988_phy_probe,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-- .read_page = mtk_socphy_read_page,
-- .write_page = mtk_socphy_write_page,
-+ .read_page = mtk_phy_read_page,
-+ .write_page = mtk_phy_write_page,
- .led_blink_set = mt798x_phy_led_blink_set,
- .led_brightness_set = mt798x_phy_led_brightness_set,
- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -3,6 +3,8 @@
- #include <linux/module.h>
- #include <linux/phy.h>
-
-+#include "mtk.h"
-+
- #define MTK_EXT_PAGE_ACCESS 0x1f
- #define MTK_PHY_PAGE_STANDARD 0x0000
- #define MTK_PHY_PAGE_EXTENDED 0x0001
-@@ -11,16 +13,6 @@
- #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
- #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-
--static int mtk_gephy_read_page(struct phy_device *phydev)
--{
-- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_gephy_write_page(struct phy_device *phydev, int page)
--{
-- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
- static void mtk_gephy_config_init(struct phy_device *phydev)
- {
- /* Enable HW auto downshift */
-@@ -77,8 +69,8 @@ static struct phy_driver mtk_gephy_drive
- .handle_interrupt = genphy_handle_interrupt_no_ack,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-- .read_page = mtk_gephy_read_page,
-- .write_page = mtk_gephy_write_page,
-+ .read_page = mtk_phy_read_page,
-+ .write_page = mtk_phy_write_page,
- },
- {
- PHY_ID_MATCH_EXACT(0x03a29441),
-@@ -91,8 +83,8 @@ static struct phy_driver mtk_gephy_drive
- .handle_interrupt = genphy_handle_interrupt_no_ack,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-- .read_page = mtk_gephy_read_page,
-- .write_page = mtk_gephy_write_page,
-+ .read_page = mtk_phy_read_page,
-+ .write_page = mtk_phy_write_page,
- },
- };
-
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -6,6 +6,18 @@
-
- #include "mtk.h"
-
-+int mtk_phy_read_page(struct phy_device *phydev)
-+{
-+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_read_page);
-+
-+int mtk_phy_write_page(struct phy_device *phydev, int page)
-+{
-+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_write_page);
-+
- int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules,
- unsigned long supported_triggers)
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -66,6 +66,9 @@ struct mtk_socphy_priv {
- unsigned long led_state;
- };
-
-+int mtk_phy_read_page(struct phy_device *phydev);
-+int mtk_phy_write_page(struct phy_device *phydev, int page);
-+
- int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules,
- unsigned long supported_triggers);
+++ /dev/null
-From e6579df175d5b1baa605c82f8e759542262637cf Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 00:34:55 +0800
-Subject: [PATCH 08/20] net: phy: mediatek: add MT7530 & MT7531's PHY ID macros
-
-This patch adds MT7530 & MT7531's PHY ID macros in mtk-ge.c so that
-it follows the same rule of mtk-ge-soc.c.
-
----
- drivers/net/phy/mediatek/mtk-ge.c | 11 +++++++----
- 1 file changed, 7 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -5,6 +5,9 @@
-
- #include "mtk.h"
-
-+#define MTK_GPHY_ID_MT7530 0x03a29412
-+#define MTK_GPHY_ID_MT7531 0x03a29441
-+
- #define MTK_EXT_PAGE_ACCESS 0x1f
- #define MTK_PHY_PAGE_STANDARD 0x0000
- #define MTK_PHY_PAGE_EXTENDED 0x0001
-@@ -59,7 +62,7 @@ static int mt7531_phy_config_init(struct
-
- static struct phy_driver mtk_gephy_driver[] = {
- {
-- PHY_ID_MATCH_EXACT(0x03a29412),
-+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
- .name = "MediaTek MT7530 PHY",
- .config_init = mt7530_phy_config_init,
- /* Interrupts are handled by the switch, not the PHY
-@@ -73,7 +76,7 @@ static struct phy_driver mtk_gephy_drive
- .write_page = mtk_phy_write_page,
- },
- {
-- PHY_ID_MATCH_EXACT(0x03a29441),
-+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531),
- .name = "MediaTek MT7531 PHY",
- .config_init = mt7531_phy_config_init,
- /* Interrupts are handled by the switch, not the PHY
-@@ -91,8 +94,8 @@ static struct phy_driver mtk_gephy_drive
- module_phy_driver(mtk_gephy_driver);
-
- static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
-- { PHY_ID_MATCH_EXACT(0x03a29441) },
-- { PHY_ID_MATCH_EXACT(0x03a29412) },
-+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) },
-+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) },
- { }
- };
-
+++ /dev/null
-From e127f7380aaf2cd1614961d826a4af7ab297d37f Mon Sep 17 00:00:00 2001
-Date: Sun, 12 Jan 2025 15:14:50 +0100
-Subject: [PATCH 09/20] net: phy: Constify struct mdio_device_id
-
-'struct mdio_device_id' is not modified in these drivers.
-
-Constifying these structures moves some data to a read-only section, so
-increase overall security.
-
-On a x86_64, with allmodconfig, as an example:
-Before:
-======
- text data bss dec hex filename
- 27014 12792 0 39806 9b7e drivers/net/phy/broadcom.o
-
-After:
-=====
- text data bss dec hex filename
- 27206 12600 0 39806 9b7e drivers/net/phy/broadcom.o
-
-Link: https://patch.msgid.link/403c381b7d9156b67ad68ffc44b8eee70c5e86a9.1736691226.git.christophe.jaillet@wanadoo.fr
----
- drivers/net/phy/adin.c | 2 +-
- drivers/net/phy/adin1100.c | 2 +-
- drivers/net/phy/air_en8811h.c | 2 +-
- drivers/net/phy/amd.c | 2 +-
- drivers/net/phy/aquantia/aquantia_main.c | 2 +-
- drivers/net/phy/ax88796b.c | 2 +-
- drivers/net/phy/bcm-cygnus.c | 2 +-
- drivers/net/phy/bcm54140.c | 2 +-
- drivers/net/phy/bcm63xx.c | 2 +-
- drivers/net/phy/bcm7xxx.c | 2 +-
- drivers/net/phy/bcm84881.c | 2 +-
- drivers/net/phy/broadcom.c | 2 +-
- drivers/net/phy/cicada.c | 2 +-
- drivers/net/phy/cortina.c | 2 +-
- drivers/net/phy/davicom.c | 2 +-
- drivers/net/phy/dp83640.c | 2 +-
- drivers/net/phy/dp83822.c | 2 +-
- drivers/net/phy/dp83848.c | 2 +-
- drivers/net/phy/dp83867.c | 2 +-
- drivers/net/phy/dp83869.c | 2 +-
- drivers/net/phy/dp83tc811.c | 2 +-
- drivers/net/phy/dp83td510.c | 2 +-
- drivers/net/phy/dp83tg720.c | 2 +-
- drivers/net/phy/et1011c.c | 2 +-
- drivers/net/phy/icplus.c | 2 +-
- drivers/net/phy/intel-xway.c | 2 +-
- drivers/net/phy/lxt.c | 2 +-
- drivers/net/phy/marvell-88q2xxx.c | 2 +-
- drivers/net/phy/marvell-88x2222.c | 2 +-
- drivers/net/phy/marvell.c | 2 +-
- drivers/net/phy/marvell10g.c | 2 +-
- drivers/net/phy/mediatek/mtk-ge-soc.c | 2 +-
- drivers/net/phy/mediatek/mtk-ge.c | 2 +-
- drivers/net/phy/meson-gxl.c | 2 +-
- drivers/net/phy/micrel.c | 2 +-
- drivers/net/phy/microchip.c | 2 +-
- drivers/net/phy/microchip_t1.c | 2 +-
- drivers/net/phy/microchip_t1s.c | 2 +-
- drivers/net/phy/mscc/mscc_main.c | 2 +-
- drivers/net/phy/mxl-gpy.c | 2 +-
- drivers/net/phy/national.c | 2 +-
- drivers/net/phy/ncn26000.c | 2 +-
- drivers/net/phy/nxp-c45-tja11xx.c | 2 +-
- drivers/net/phy/nxp-cbtx.c | 2 +-
- drivers/net/phy/nxp-tja11xx.c | 2 +-
- drivers/net/phy/qcom/at803x.c | 2 +-
- drivers/net/phy/qcom/qca807x.c | 2 +-
- drivers/net/phy/qcom/qca808x.c | 2 +-
- drivers/net/phy/qcom/qca83xx.c | 2 +-
- drivers/net/phy/qsemi.c | 2 +-
- drivers/net/phy/rockchip.c | 2 +-
- drivers/net/phy/smsc.c | 2 +-
- drivers/net/phy/ste10Xp.c | 2 +-
- drivers/net/phy/teranetics.c | 2 +-
- drivers/net/phy/uPD60620.c | 2 +-
- drivers/net/phy/vitesse.c | 2 +-
- 56 files changed, 56 insertions(+), 56 deletions(-)
-
---- a/drivers/net/phy/adin.c
-+++ b/drivers/net/phy/adin.c
-@@ -1040,7 +1040,7 @@ static struct phy_driver adin_driver[] =
-
- module_phy_driver(adin_driver);
-
--static struct mdio_device_id __maybe_unused adin_tbl[] = {
-+static const struct mdio_device_id __maybe_unused adin_tbl[] = {
- { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1200) },
- { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1300) },
- { }
---- a/drivers/net/phy/adin1100.c
-+++ b/drivers/net/phy/adin1100.c
-@@ -340,7 +340,7 @@ static struct phy_driver adin_driver[] =
-
- module_phy_driver(adin_driver);
-
--static struct mdio_device_id __maybe_unused adin_tbl[] = {
-+static const struct mdio_device_id __maybe_unused adin_tbl[] = {
- { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1100) },
- { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1110) },
- { PHY_ID_MATCH_MODEL(PHY_ID_ADIN2111) },
---- a/drivers/net/phy/air_en8811h.c
-+++ b/drivers/net/phy/air_en8811h.c
-@@ -1075,7 +1075,7 @@ static struct phy_driver en8811h_driver[
-
- module_phy_driver(en8811h_driver);
-
--static struct mdio_device_id __maybe_unused en8811h_tbl[] = {
-+static const struct mdio_device_id __maybe_unused en8811h_tbl[] = {
- { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) },
- { }
- };
---- a/drivers/net/phy/amd.c
-+++ b/drivers/net/phy/amd.c
-@@ -111,7 +111,7 @@ static struct phy_driver am79c_drivers[]
-
- module_phy_driver(am79c_drivers);
-
--static struct mdio_device_id __maybe_unused amd_tbl[] = {
-+static const struct mdio_device_id __maybe_unused amd_tbl[] = {
- { PHY_ID_AC101L, 0xfffffff0 },
- { PHY_ID_AM79C874, 0xfffffff0 },
- { }
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -1096,7 +1096,7 @@ static struct phy_driver aqr_driver[] =
-
- module_phy_driver(aqr_driver);
-
--static struct mdio_device_id __maybe_unused aqr_tbl[] = {
-+static const struct mdio_device_id __maybe_unused aqr_tbl[] = {
- { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) },
---- a/drivers/net/phy/ax88796b.c
-+++ b/drivers/net/phy/ax88796b.c
-@@ -121,7 +121,7 @@ static struct phy_driver asix_driver[] =
-
- module_phy_driver(asix_driver);
-
--static struct mdio_device_id __maybe_unused asix_tbl[] = {
-+static const struct mdio_device_id __maybe_unused asix_tbl[] = {
- { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A) },
- { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C) },
- { PHY_ID_ASIX_AX88796B, 0xfffffff0 },
---- a/drivers/net/phy/bcm-cygnus.c
-+++ b/drivers/net/phy/bcm-cygnus.c
-@@ -278,7 +278,7 @@ static struct phy_driver bcm_cygnus_phy_
- }
- };
-
--static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = {
-+static const struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = {
- { PHY_ID_BCM_CYGNUS, 0xfffffff0, },
- { PHY_ID_BCM_OMEGA, 0xfffffff0, },
- { }
---- a/drivers/net/phy/bcm54140.c
-+++ b/drivers/net/phy/bcm54140.c
-@@ -883,7 +883,7 @@ static struct phy_driver bcm54140_driver
- };
- module_phy_driver(bcm54140_drivers);
-
--static struct mdio_device_id __maybe_unused bcm54140_tbl[] = {
-+static const struct mdio_device_id __maybe_unused bcm54140_tbl[] = {
- { PHY_ID_BCM54140, BCM54140_PHY_ID_MASK },
- { }
- };
---- a/drivers/net/phy/bcm63xx.c
-+++ b/drivers/net/phy/bcm63xx.c
-@@ -93,7 +93,7 @@ static struct phy_driver bcm63xx_driver[
-
- module_phy_driver(bcm63xx_driver);
-
--static struct mdio_device_id __maybe_unused bcm63xx_tbl[] = {
-+static const struct mdio_device_id __maybe_unused bcm63xx_tbl[] = {
- { 0x00406000, 0xfffffc00 },
- { 0x002bdc00, 0xfffffc00 },
- { }
---- a/drivers/net/phy/bcm7xxx.c
-+++ b/drivers/net/phy/bcm7xxx.c
-@@ -929,7 +929,7 @@ static struct phy_driver bcm7xxx_driver[
- BCM7XXX_16NM_EPHY(PHY_ID_BCM7712, "Broadcom BCM7712"),
- };
-
--static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
-+static const struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
- { PHY_ID_BCM72113, 0xfffffff0 },
- { PHY_ID_BCM72116, 0xfffffff0, },
- { PHY_ID_BCM72165, 0xfffffff0, },
---- a/drivers/net/phy/bcm84881.c
-+++ b/drivers/net/phy/bcm84881.c
-@@ -252,7 +252,7 @@ static struct phy_driver bcm84881_driver
- module_phy_driver(bcm84881_drivers);
-
- /* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */
--static struct mdio_device_id __maybe_unused bcm84881_tbl[] = {
-+static const struct mdio_device_id __maybe_unused bcm84881_tbl[] = {
- { 0xae025150, 0xfffffff0 },
- { },
- };
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -1717,7 +1717,7 @@ static struct phy_driver broadcom_driver
-
- module_phy_driver(broadcom_drivers);
-
--static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
-+static const struct mdio_device_id __maybe_unused broadcom_tbl[] = {
- { PHY_ID_BCM5411, 0xfffffff0 },
- { PHY_ID_BCM5421, 0xfffffff0 },
- { PHY_ID_BCM54210E, 0xfffffff0 },
---- a/drivers/net/phy/cicada.c
-+++ b/drivers/net/phy/cicada.c
-@@ -145,7 +145,7 @@ static struct phy_driver cis820x_driver[
-
- module_phy_driver(cis820x_driver);
-
--static struct mdio_device_id __maybe_unused cicada_tbl[] = {
-+static const struct mdio_device_id __maybe_unused cicada_tbl[] = {
- { 0x000fc410, 0x000ffff0 },
- { 0x000fc440, 0x000fffc0 },
- { }
---- a/drivers/net/phy/cortina.c
-+++ b/drivers/net/phy/cortina.c
-@@ -87,7 +87,7 @@ static struct phy_driver cortina_driver[
-
- module_phy_driver(cortina_driver);
-
--static struct mdio_device_id __maybe_unused cortina_tbl[] = {
-+static const struct mdio_device_id __maybe_unused cortina_tbl[] = {
- { PHY_ID_CS4340, 0xffffffff},
- {},
- };
---- a/drivers/net/phy/davicom.c
-+++ b/drivers/net/phy/davicom.c
-@@ -209,7 +209,7 @@ static struct phy_driver dm91xx_driver[]
-
- module_phy_driver(dm91xx_driver);
-
--static struct mdio_device_id __maybe_unused davicom_tbl[] = {
-+static const struct mdio_device_id __maybe_unused davicom_tbl[] = {
- { 0x0181b880, 0x0ffffff0 },
- { 0x0181b8b0, 0x0ffffff0 },
- { 0x0181b8a0, 0x0ffffff0 },
---- a/drivers/net/phy/dp83640.c
-+++ b/drivers/net/phy/dp83640.c
-@@ -1548,7 +1548,7 @@ MODULE_LICENSE("GPL");
- module_init(dp83640_init);
- module_exit(dp83640_exit);
-
--static struct mdio_device_id __maybe_unused dp83640_tbl[] = {
-+static const struct mdio_device_id __maybe_unused dp83640_tbl[] = {
- { DP83640_PHY_ID, 0xfffffff0 },
- { }
- };
---- a/drivers/net/phy/dp83822.c
-+++ b/drivers/net/phy/dp83822.c
-@@ -825,7 +825,7 @@ static struct phy_driver dp83822_driver[
- };
- module_phy_driver(dp83822_driver);
-
--static struct mdio_device_id __maybe_unused dp83822_tbl[] = {
-+static const struct mdio_device_id __maybe_unused dp83822_tbl[] = {
- { DP83822_PHY_ID, 0xfffffff0 },
- { DP83825I_PHY_ID, 0xfffffff0 },
- { DP83826C_PHY_ID, 0xfffffff0 },
---- a/drivers/net/phy/dp83848.c
-+++ b/drivers/net/phy/dp83848.c
-@@ -123,7 +123,7 @@ static int dp83848_config_init(struct ph
- return 0;
- }
-
--static struct mdio_device_id __maybe_unused dp83848_tbl[] = {
-+static const struct mdio_device_id __maybe_unused dp83848_tbl[] = {
- { TI_DP83848C_PHY_ID, 0xfffffff0 },
- { NS_DP83848C_PHY_ID, 0xfffffff0 },
- { TI_DP83620_PHY_ID, 0xfffffff0 },
---- a/drivers/net/phy/dp83867.c
-+++ b/drivers/net/phy/dp83867.c
-@@ -1210,7 +1210,7 @@ static struct phy_driver dp83867_driver[
- };
- module_phy_driver(dp83867_driver);
-
--static struct mdio_device_id __maybe_unused dp83867_tbl[] = {
-+static const struct mdio_device_id __maybe_unused dp83867_tbl[] = {
- { DP83867_PHY_ID, 0xfffffff0 },
- { }
- };
---- a/drivers/net/phy/dp83869.c
-+++ b/drivers/net/phy/dp83869.c
-@@ -928,7 +928,7 @@ static struct phy_driver dp83869_driver[
- };
- module_phy_driver(dp83869_driver);
-
--static struct mdio_device_id __maybe_unused dp83869_tbl[] = {
-+static const struct mdio_device_id __maybe_unused dp83869_tbl[] = {
- { PHY_ID_MATCH_MODEL(DP83869_PHY_ID) },
- { PHY_ID_MATCH_MODEL(DP83561_PHY_ID) },
- { }
---- a/drivers/net/phy/dp83tc811.c
-+++ b/drivers/net/phy/dp83tc811.c
-@@ -403,7 +403,7 @@ static struct phy_driver dp83811_driver[
- };
- module_phy_driver(dp83811_driver);
-
--static struct mdio_device_id __maybe_unused dp83811_tbl[] = {
-+static const struct mdio_device_id __maybe_unused dp83811_tbl[] = {
- { DP83TC811_PHY_ID, 0xfffffff0 },
- { },
- };
---- a/drivers/net/phy/dp83td510.c
-+++ b/drivers/net/phy/dp83td510.c
-@@ -605,7 +605,7 @@ static struct phy_driver dp83td510_drive
- } };
- module_phy_driver(dp83td510_driver);
-
--static struct mdio_device_id __maybe_unused dp83td510_tbl[] = {
-+static const struct mdio_device_id __maybe_unused dp83td510_tbl[] = {
- { PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID) },
- { }
- };
---- a/drivers/net/phy/dp83tg720.c
-+++ b/drivers/net/phy/dp83tg720.c
-@@ -361,7 +361,7 @@ static struct phy_driver dp83tg720_drive
- } };
- module_phy_driver(dp83tg720_driver);
-
--static struct mdio_device_id __maybe_unused dp83tg720_tbl[] = {
-+static const struct mdio_device_id __maybe_unused dp83tg720_tbl[] = {
- { PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID) },
- { }
- };
---- a/drivers/net/phy/et1011c.c
-+++ b/drivers/net/phy/et1011c.c
-@@ -94,7 +94,7 @@ static struct phy_driver et1011c_driver[
-
- module_phy_driver(et1011c_driver);
-
--static struct mdio_device_id __maybe_unused et1011c_tbl[] = {
-+static const struct mdio_device_id __maybe_unused et1011c_tbl[] = {
- { 0x0282f014, 0xfffffff0 },
- { }
- };
---- a/drivers/net/phy/icplus.c
-+++ b/drivers/net/phy/icplus.c
-@@ -624,7 +624,7 @@ static struct phy_driver icplus_driver[]
-
- module_phy_driver(icplus_driver);
-
--static struct mdio_device_id __maybe_unused icplus_tbl[] = {
-+static const struct mdio_device_id __maybe_unused icplus_tbl[] = {
- { PHY_ID_MATCH_MODEL(IP175C_PHY_ID) },
- { PHY_ID_MATCH_MODEL(IP1001_PHY_ID) },
- { PHY_ID_MATCH_EXACT(IP101A_PHY_ID) },
---- a/drivers/net/phy/intel-xway.c
-+++ b/drivers/net/phy/intel-xway.c
-@@ -456,7 +456,7 @@ static struct phy_driver xway_gphy[] = {
- };
- module_phy_driver(xway_gphy);
-
--static struct mdio_device_id __maybe_unused xway_gphy_tbl[] = {
-+static const struct mdio_device_id __maybe_unused xway_gphy_tbl[] = {
- { PHY_ID_PHY11G_1_3, 0xffffffff },
- { PHY_ID_PHY22F_1_3, 0xffffffff },
- { PHY_ID_PHY11G_1_4, 0xffffffff },
---- a/drivers/net/phy/lxt.c
-+++ b/drivers/net/phy/lxt.c
-@@ -348,7 +348,7 @@ static struct phy_driver lxt97x_driver[]
-
- module_phy_driver(lxt97x_driver);
-
--static struct mdio_device_id __maybe_unused lxt_tbl[] = {
-+static const struct mdio_device_id __maybe_unused lxt_tbl[] = {
- { 0x78100000, 0xfffffff0 },
- { 0x001378e0, 0xfffffff0 },
- { 0x00137a10, 0xfffffff0 },
---- a/drivers/net/phy/marvell-88q2xxx.c
-+++ b/drivers/net/phy/marvell-88q2xxx.c
-@@ -940,7 +940,7 @@ static struct phy_driver mv88q2xxx_drive
-
- module_phy_driver(mv88q2xxx_driver);
-
--static struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = {
-+static const struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = {
- { MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK },
- { MARVELL_PHY_ID_88Q2220, MARVELL_PHY_ID_MASK },
- { /*sentinel*/ }
---- a/drivers/net/phy/marvell-88x2222.c
-+++ b/drivers/net/phy/marvell-88x2222.c
-@@ -613,7 +613,7 @@ static struct phy_driver mv2222_drivers[
- };
- module_phy_driver(mv2222_drivers);
-
--static struct mdio_device_id __maybe_unused mv2222_tbl[] = {
-+static const struct mdio_device_id __maybe_unused mv2222_tbl[] = {
- { MARVELL_PHY_ID_88X2222, MARVELL_PHY_ID_MASK },
- { }
- };
---- a/drivers/net/phy/marvell.c
-+++ b/drivers/net/phy/marvell.c
-@@ -4133,7 +4133,7 @@ static struct phy_driver marvell_drivers
-
- module_phy_driver(marvell_drivers);
-
--static struct mdio_device_id __maybe_unused marvell_tbl[] = {
-+static const struct mdio_device_id __maybe_unused marvell_tbl[] = {
- { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
- { MARVELL_PHY_ID_88E3082, MARVELL_PHY_ID_MASK },
- { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
---- a/drivers/net/phy/marvell10g.c
-+++ b/drivers/net/phy/marvell10g.c
-@@ -1484,7 +1484,7 @@ static struct phy_driver mv3310_drivers[
-
- module_phy_driver(mv3310_drivers);
-
--static struct mdio_device_id __maybe_unused mv3310_tbl[] = {
-+static const struct mdio_device_id __maybe_unused mv3310_tbl[] = {
- { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK },
- { MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK },
- { },
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -1356,7 +1356,7 @@ static struct phy_driver mtk_socphy_driv
-
- module_phy_driver(mtk_socphy_driver);
-
--static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
-+static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
- { }
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -93,7 +93,7 @@ static struct phy_driver mtk_gephy_drive
-
- module_phy_driver(mtk_gephy_driver);
-
--static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
-+static const struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) },
- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) },
- { }
---- a/drivers/net/phy/meson-gxl.c
-+++ b/drivers/net/phy/meson-gxl.c
-@@ -221,7 +221,7 @@ static struct phy_driver meson_gxl_phy[]
- },
- };
-
--static struct mdio_device_id __maybe_unused meson_gxl_tbl[] = {
-+static const struct mdio_device_id __maybe_unused meson_gxl_tbl[] = {
- { PHY_ID_MATCH_VENDOR(0x01814400) },
- { PHY_ID_MATCH_VENDOR(0x01803301) },
- { }
---- a/drivers/net/phy/micrel.c
-+++ b/drivers/net/phy/micrel.c
-@@ -5691,7 +5691,7 @@ MODULE_DESCRIPTION("Micrel PHY driver");
- MODULE_AUTHOR("David J. Choi");
- MODULE_LICENSE("GPL");
-
--static struct mdio_device_id __maybe_unused micrel_tbl[] = {
-+static const struct mdio_device_id __maybe_unused micrel_tbl[] = {
- { PHY_ID_KSZ9021, 0x000ffffe },
- { PHY_ID_KSZ9031, MICREL_PHY_ID_MASK },
- { PHY_ID_KSZ9131, MICREL_PHY_ID_MASK },
---- a/drivers/net/phy/microchip.c
-+++ b/drivers/net/phy/microchip.c
-@@ -508,7 +508,7 @@ static struct phy_driver microchip_phy_d
-
- module_phy_driver(microchip_phy_driver);
-
--static struct mdio_device_id __maybe_unused microchip_tbl[] = {
-+static const struct mdio_device_id __maybe_unused microchip_tbl[] = {
- { 0x0007c132, 0xfffffff2 },
- { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX) },
- { }
---- a/drivers/net/phy/microchip_t1.c
-+++ b/drivers/net/phy/microchip_t1.c
-@@ -1886,7 +1886,7 @@ static struct phy_driver microchip_t1_ph
-
- module_phy_driver(microchip_t1_phy_driver);
-
--static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
-+static const struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
- { PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX) },
- { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X) },
- { PHY_ID_MATCH_MODEL(PHY_ID_LAN887X) },
---- a/drivers/net/phy/microchip_t1s.c
-+++ b/drivers/net/phy/microchip_t1s.c
-@@ -323,7 +323,7 @@ static struct phy_driver microchip_t1s_d
-
- module_phy_driver(microchip_t1s_driver);
-
--static struct mdio_device_id __maybe_unused tbl[] = {
-+static const struct mdio_device_id __maybe_unused tbl[] = {
- { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1) },
- { PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0) },
- { }
---- a/drivers/net/phy/mscc/mscc_main.c
-+++ b/drivers/net/phy/mscc/mscc_main.c
-@@ -2700,7 +2700,7 @@ static struct phy_driver vsc85xx_driver[
-
- module_phy_driver(vsc85xx_driver);
-
--static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
-+static const struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
- { PHY_ID_MATCH_VENDOR(PHY_VENDOR_MSCC) },
- { }
- };
---- a/drivers/net/phy/mxl-gpy.c
-+++ b/drivers/net/phy/mxl-gpy.c
-@@ -1047,7 +1047,7 @@ static struct phy_driver gpy_drivers[] =
- };
- module_phy_driver(gpy_drivers);
-
--static struct mdio_device_id __maybe_unused gpy_tbl[] = {
-+static const struct mdio_device_id __maybe_unused gpy_tbl[] = {
- {PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)},
- {PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK},
- {PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)},
---- a/drivers/net/phy/national.c
-+++ b/drivers/net/phy/national.c
-@@ -173,7 +173,7 @@ MODULE_DESCRIPTION("NatSemi PHY driver")
- MODULE_AUTHOR("Stuart Menefy");
- MODULE_LICENSE("GPL");
-
--static struct mdio_device_id __maybe_unused ns_tbl[] = {
-+static const struct mdio_device_id __maybe_unused ns_tbl[] = {
- { DP83865_PHY_ID, 0xfffffff0 },
- { }
- };
---- a/drivers/net/phy/ncn26000.c
-+++ b/drivers/net/phy/ncn26000.c
-@@ -159,7 +159,7 @@ static struct phy_driver ncn26000_driver
-
- module_phy_driver(ncn26000_driver);
-
--static struct mdio_device_id __maybe_unused ncn26000_tbl[] = {
-+static const struct mdio_device_id __maybe_unused ncn26000_tbl[] = {
- { PHY_ID_MATCH_MODEL(PHY_ID_NCN26000) },
- { }
- };
---- a/drivers/net/phy/nxp-c45-tja11xx.c
-+++ b/drivers/net/phy/nxp-c45-tja11xx.c
-@@ -2102,7 +2102,7 @@ static struct phy_driver nxp_c45_driver[
-
- module_phy_driver(nxp_c45_driver);
-
--static struct mdio_device_id __maybe_unused nxp_c45_tbl[] = {
-+static const struct mdio_device_id __maybe_unused nxp_c45_tbl[] = {
- { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103) },
- { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120) },
- { /*sentinel*/ },
---- a/drivers/net/phy/nxp-cbtx.c
-+++ b/drivers/net/phy/nxp-cbtx.c
-@@ -215,7 +215,7 @@ static struct phy_driver cbtx_driver[] =
-
- module_phy_driver(cbtx_driver);
-
--static struct mdio_device_id __maybe_unused cbtx_tbl[] = {
-+static const struct mdio_device_id __maybe_unused cbtx_tbl[] = {
- { PHY_ID_MATCH_MODEL(PHY_ID_CBTX_SJA1110) },
- { },
- };
---- a/drivers/net/phy/nxp-tja11xx.c
-+++ b/drivers/net/phy/nxp-tja11xx.c
-@@ -888,7 +888,7 @@ static struct phy_driver tja11xx_driver[
-
- module_phy_driver(tja11xx_driver);
-
--static struct mdio_device_id __maybe_unused tja11xx_tbl[] = {
-+static const struct mdio_device_id __maybe_unused tja11xx_tbl[] = {
- { PHY_ID_MATCH_MODEL(PHY_ID_TJA1100) },
- { PHY_ID_MATCH_MODEL(PHY_ID_TJA1101) },
- { PHY_ID_MATCH_MODEL(PHY_ID_TJA1102) },
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -1098,7 +1098,7 @@ static struct phy_driver at803x_driver[]
-
- module_phy_driver(at803x_driver);
-
--static struct mdio_device_id __maybe_unused atheros_tbl[] = {
-+static const struct mdio_device_id __maybe_unused atheros_tbl[] = {
- { ATH8030_PHY_ID, AT8030_PHY_ID_MASK },
- { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) },
- { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
---- a/drivers/net/phy/qcom/qca807x.c
-+++ b/drivers/net/phy/qcom/qca807x.c
-@@ -828,7 +828,7 @@ static struct phy_driver qca807x_drivers
- };
- module_phy_driver(qca807x_drivers);
-
--static struct mdio_device_id __maybe_unused qca807x_tbl[] = {
-+static const struct mdio_device_id __maybe_unused qca807x_tbl[] = {
- { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) },
- { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) },
- { }
---- a/drivers/net/phy/qcom/qca808x.c
-+++ b/drivers/net/phy/qcom/qca808x.c
-@@ -655,7 +655,7 @@ static struct phy_driver qca808x_driver[
-
- module_phy_driver(qca808x_driver);
-
--static struct mdio_device_id __maybe_unused qca808x_tbl[] = {
-+static const struct mdio_device_id __maybe_unused qca808x_tbl[] = {
- { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
- { }
- };
---- a/drivers/net/phy/qcom/qca83xx.c
-+++ b/drivers/net/phy/qcom/qca83xx.c
-@@ -261,7 +261,7 @@ static struct phy_driver qca83xx_driver[
-
- module_phy_driver(qca83xx_driver);
-
--static struct mdio_device_id __maybe_unused qca83xx_tbl[] = {
-+static const struct mdio_device_id __maybe_unused qca83xx_tbl[] = {
- { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
- { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
- { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
---- a/drivers/net/phy/qsemi.c
-+++ b/drivers/net/phy/qsemi.c
-@@ -155,7 +155,7 @@ static struct phy_driver qs6612_driver[]
-
- module_phy_driver(qs6612_driver);
-
--static struct mdio_device_id __maybe_unused qs6612_tbl[] = {
-+static const struct mdio_device_id __maybe_unused qs6612_tbl[] = {
- { 0x00181440, 0xfffffff0 },
- { }
- };
---- a/drivers/net/phy/rockchip.c
-+++ b/drivers/net/phy/rockchip.c
-@@ -188,7 +188,7 @@ static struct phy_driver rockchip_phy_dr
-
- module_phy_driver(rockchip_phy_driver);
-
--static struct mdio_device_id __maybe_unused rockchip_phy_tbl[] = {
-+static const struct mdio_device_id __maybe_unused rockchip_phy_tbl[] = {
- { INTERNAL_EPHY_ID, 0xfffffff0 },
- { }
- };
---- a/drivers/net/phy/smsc.c
-+++ b/drivers/net/phy/smsc.c
-@@ -837,7 +837,7 @@ MODULE_DESCRIPTION("SMSC PHY driver");
- MODULE_AUTHOR("Herbert Valerio Riedel");
- MODULE_LICENSE("GPL");
-
--static struct mdio_device_id __maybe_unused smsc_tbl[] = {
-+static const struct mdio_device_id __maybe_unused smsc_tbl[] = {
- { 0x0007c0a0, 0xfffffff0 },
- { 0x0007c0b0, 0xfffffff0 },
- { 0x0007c0c0, 0xfffffff0 },
---- a/drivers/net/phy/ste10Xp.c
-+++ b/drivers/net/phy/ste10Xp.c
-@@ -124,7 +124,7 @@ static struct phy_driver ste10xp_pdriver
-
- module_phy_driver(ste10xp_pdriver);
-
--static struct mdio_device_id __maybe_unused ste10Xp_tbl[] = {
-+static const struct mdio_device_id __maybe_unused ste10Xp_tbl[] = {
- { STE101P_PHY_ID, 0xfffffff0 },
- { STE100P_PHY_ID, 0xffffffff },
- { }
---- a/drivers/net/phy/teranetics.c
-+++ b/drivers/net/phy/teranetics.c
-@@ -87,7 +87,7 @@ static struct phy_driver teranetics_driv
-
- module_phy_driver(teranetics_driver);
-
--static struct mdio_device_id __maybe_unused teranetics_tbl[] = {
-+static const struct mdio_device_id __maybe_unused teranetics_tbl[] = {
- { PHY_ID_TN2020, 0xffffffff },
- { }
- };
---- a/drivers/net/phy/uPD60620.c
-+++ b/drivers/net/phy/uPD60620.c
-@@ -90,7 +90,7 @@ static struct phy_driver upd60620_driver
-
- module_phy_driver(upd60620_driver);
-
--static struct mdio_device_id __maybe_unused upd60620_tbl[] = {
-+static const struct mdio_device_id __maybe_unused upd60620_tbl[] = {
- { UPD60620_PHY_ID, 0xfffffffe },
- { }
- };
---- a/drivers/net/phy/vitesse.c
-+++ b/drivers/net/phy/vitesse.c
-@@ -674,7 +674,7 @@ static struct phy_driver vsc82xx_driver[
-
- module_phy_driver(vsc82xx_driver);
-
--static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
-+static const struct mdio_device_id __maybe_unused vitesse_tbl[] = {
- { PHY_ID_VSC8234, 0x000ffff0 },
- { PHY_ID_VSC8244, 0x000fffc0 },
- { PHY_ID_VSC8572, 0x000ffff0 },
+++ /dev/null
-From 7e06c3dbfa5f1e39eba92eb79d854fab2a7ad5fe Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:49 +0800
-Subject: [PATCH 10/20] net: phy: mediatek: Change to more meaningful macros
-
-Replace magic number with more meaningful macros in mtk-ge.c.
-Also, move some common macros into mtk-phy-lib.c.
-
----
- drivers/net/phy/mediatek/mtk-ge-soc.c | 1 -
- drivers/net/phy/mediatek/mtk-ge.c | 71 +++++++++++++++++++++------
- drivers/net/phy/mediatek/mtk.h | 2 +
- 3 files changed, 57 insertions(+), 17 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -24,7 +24,6 @@
- #define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
-
- #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-
- #define ANALOG_INTERNAL_OPERATION_MAX_US 20
- #define TXRESERVE_MIN 0
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -8,18 +8,38 @@
- #define MTK_GPHY_ID_MT7530 0x03a29412
- #define MTK_GPHY_ID_MT7531 0x03a29441
-
--#define MTK_EXT_PAGE_ACCESS 0x1f
--#define MTK_PHY_PAGE_STANDARD 0x0000
--#define MTK_PHY_PAGE_EXTENDED 0x0001
--#define MTK_PHY_PAGE_EXTENDED_2 0x0002
--#define MTK_PHY_PAGE_EXTENDED_3 0x0003
--#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-+#define MTK_PHY_PAGE_EXTENDED_1 0x0001
-+#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
-+#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
-+
-+#define MTK_PHY_PAGE_EXTENDED_2 0x0002
-+#define MTK_PHY_PAGE_EXTENDED_3 0x0003
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11
-+
-+#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-+
-+/* Registers on MDIO_MMD_VEND1 */
-+#define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13
-+#define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14
-+#define MTK_TX_DELAY_PAIR_B_MASK GENMASK(10, 8)
-+#define MTK_TX_DELAY_PAIR_D_MASK GENMASK(2, 0)
-+
-+#define MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL 0xa6
-+#define MTK_MCC_NEARECHO_OFFSET_MASK GENMASK(15, 8)
-+
-+#define MTK_PHY_RXADC_CTRL_RG7 0xc6
-+#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
-+
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123 0x123
-+#define MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK GENMASK(15, 8)
-+#define MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK GENMASK(7, 0)
-
- static void mtk_gephy_config_init(struct phy_device *phydev)
- {
- /* Enable HW auto downshift */
-- phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
-+ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
-+ MTK_PHY_AUX_CTRL_AND_STATUS,
-+ 0, MTK_PHY_ENABLE_DOWNSHIFT);
-
- /* Increase SlvDPSready time */
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-@@ -29,10 +49,20 @@ static void mtk_gephy_config_init(struct
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- /* Adjust 100_mse_threshold */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
--
-- /* Disable mcc */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123,
-+ MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK |
-+ MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK,
-+ 0xff) |
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
-+ 0xff));
-+
-+ /* If echo time is narrower than 0x3, it will be regarded as noise */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL,
-+ MTK_MCC_NEARECHO_OFFSET_MASK,
-+ FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3));
- }
-
- static int mt7530_phy_config_init(struct phy_device *phydev)
-@@ -40,7 +70,8 @@ static int mt7530_phy_config_init(struct
- mtk_gephy_config_init(phydev);
-
- /* Increase post_update_timer */
-- phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
-+ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11, 0x4b);
-
- return 0;
- }
-@@ -51,11 +82,19 @@ static int mt7531_phy_config_init(struct
-
- /* PHY link down power saving enable */
- phy_set_bits(phydev, 0x17, BIT(4));
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
-+ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK,
-+ FIELD_PREP(MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3));
-
- /* Set TX Pair delay selection */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_GBE_MODE_TX_DELAY_SEL,
-+ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
-+ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
-+ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TEST_MODE_TX_DELAY_SEL,
-+ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
-+ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
-+ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
-
- return 0;
- }
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -9,6 +9,8 @@
- #define _MTK_EPHY_H_
-
- #define MTK_EXT_PAGE_ACCESS 0x1f
-+#define MTK_PHY_PAGE_STANDARD 0x0000
-+#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-
- /* Registers on MDIO_MMD_VEND2 */
- #define MTK_PHY_LED0_ON_CTRL 0x24
--- /dev/null
+From a2e1ba275eae96a8171deb19e9c7c2f5978fee7b Mon Sep 17 00:00:00 2001
+Date: Fri, 4 Oct 2024 17:18:16 +0100
+Subject: [PATCH] net: phy: aquantia: allow forcing order of MDI pairs
+
+Despite supporting Auto MDI-X, it looks like Aquantia only supports
+swapping pair (1,2) with pair (3,6) like it used to be for MDI-X on
+100MBit/s networks.
+
+When all 4 pairs are in use (for 1000MBit/s or faster) the link does not
+come up with pair order is not configured correctly, either using
+MDI_CFG pin or using the "PMA Receive Reserved Vendor Provisioning 1"
+register.
+
+Normally, the order of MDI pairs being either ABCD or DCBA is configured
+by pulling the MDI_CFG pin.
+
+However, some hardware designs require overriding the value configured
+by that bootstrap pin. The PHY allows doing that by setting a bit in
+"PMA Receive Reserved Vendor Provisioning 1" register which allows
+ignoring the state of the MDI_CFG pin and another bit configuring
+whether the order of MDI pairs should be normal (ABCD) or reverse
+(DCBA). Pair polarity is not affected and remains identical in both
+settings.
+
+Introduce property "marvell,mdi-cfg-order" which allows forcing either
+normal or reverse order of the MDI pairs from DT.
+
+If the property isn't present, the behavior is unchanged and MDI pair
+order configuration is untouched (ie. either the result of MDI_CFG pin
+pull-up/pull-down, or pair order override already configured by the
+bootloader before Linux is started).
+
+Forcing normal pair order is required on the Adtran SDG-8733A Wi-Fi 7
+residential gateway.
+
+Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org
+---
+ drivers/net/phy/aquantia/aquantia_main.c | 33 ++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+--- a/drivers/net/phy/aquantia/aquantia_main.c
++++ b/drivers/net/phy/aquantia/aquantia_main.c
+@@ -11,6 +11,7 @@
+ #include <linux/module.h>
+ #include <linux/delay.h>
+ #include <linux/bitfield.h>
++#include <linux/of.h>
+ #include <linux/phy.h>
+
+ #include "aquantia.h"
+@@ -71,6 +72,11 @@
+ #define MDIO_AN_TX_VEND_INT_MASK2 0xd401
+ #define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0)
+
++#define PMAPMD_RSVD_VEND_PROV 0xe400
++#define PMAPMD_RSVD_VEND_PROV_MDI_CONF GENMASK(1, 0)
++#define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE BIT(0)
++#define PMAPMD_RSVD_VEND_PROV_MDI_FORCE BIT(1)
++
+ #define MDIO_AN_RX_LP_STAT1 0xe820
+ #define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15)
+ #define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14)
+@@ -485,6 +491,29 @@ static void aqr107_chip_info(struct phy_
+ fw_major, fw_minor, build_id, prov_id);
+ }
+
++static int aqr107_config_mdi(struct phy_device *phydev)
++{
++ struct device_node *np = phydev->mdio.dev.of_node;
++ u32 mdi_conf;
++ int ret;
++
++ ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf);
++
++ /* Do nothing in case property "marvell,mdi-cfg-order" is not present */
++ if (ret == -ENOENT)
++ return 0;
++
++ if (ret)
++ return ret;
++
++ if (mdi_conf & ~PMAPMD_RSVD_VEND_PROV_MDI_REVERSE)
++ return -EINVAL;
++
++ return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV,
++ PMAPMD_RSVD_VEND_PROV_MDI_CONF,
++ mdi_conf | PMAPMD_RSVD_VEND_PROV_MDI_FORCE);
++}
++
+ static int aqr107_config_init(struct phy_device *phydev)
+ {
+ struct aqr107_priv *priv = phydev->priv;
+@@ -514,6 +543,10 @@ static int aqr107_config_init(struct phy
+ if (ret)
+ return ret;
+
++ ret = aqr107_config_mdi(phydev);
++ if (ret)
++ return ret;
++
+ /* Restore LED polarity state after reset */
+ for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
+ ret = aqr_phy_led_active_low_set(phydev, led_active_low, true);
--- /dev/null
+From ce21b8fb255ebf0b49913fb4c62741d7eb05c6f6 Mon Sep 17 00:00:00 2001
+Date: Fri, 11 Oct 2024 22:28:43 +0100
+Subject: [PATCH] net: phy: aquantia: fix return value check in
+ aqr107_config_mdi()
+
+of_property_read_u32() returns -EINVAL in case the property cannot be
+found rather than -ENOENT. Fix the check to not abort probing in case
+of the property being missing, and also in case CONFIG_OF is not set
+which will result in -ENOSYS.
+
+Fixes: a2e1ba275eae ("net: phy: aquantia: allow forcing order of MDI pairs")
+---
+ drivers/net/phy/aquantia/aquantia_main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/phy/aquantia/aquantia_main.c
++++ b/drivers/net/phy/aquantia/aquantia_main.c
+@@ -500,7 +500,7 @@ static int aqr107_config_mdi(struct phy_
+ ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf);
+
+ /* Do nothing in case property "marvell,mdi-cfg-order" is not present */
+- if (ret == -ENOENT)
++ if (ret == -EINVAL || ret == -ENOSYS)
+ return 0;
+
+ if (ret)
--- /dev/null
+From a274465cc3bef2dfd9c9ea5100848dda0a8641e1 Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Oct 2024 13:54:19 +0100
+Subject: [PATCH 1/4] net: phy: support 'active-high' property for PHY LEDs
+
+In addition to 'active-low' and 'inactive-high-impedance' also
+support 'active-high' property for PHY LED pin configuration.
+As only either 'active-high' or 'active-low' can be set at the
+same time, WARN and return an error in case both are set.
+
+Link: https://patch.msgid.link/91598487773d768f254d5faf06cf65b13e972f0e.1728558223.git.daniel@makrotopia.org
+---
+ drivers/net/phy/phy_device.c | 6 ++++++
+ include/linux/phy.h | 5 +++--
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -3385,11 +3385,17 @@ static int of_phy_led(struct phy_device
+ if (index > U8_MAX)
+ return -EINVAL;
+
++ if (of_property_read_bool(led, "active-high"))
++ set_bit(PHY_LED_ACTIVE_HIGH, &modes);
+ if (of_property_read_bool(led, "active-low"))
+ set_bit(PHY_LED_ACTIVE_LOW, &modes);
+ if (of_property_read_bool(led, "inactive-high-impedance"))
+ set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
+
++ if (WARN_ON(modes & BIT(PHY_LED_ACTIVE_LOW) &&
++ modes & BIT(PHY_LED_ACTIVE_HIGH)))
++ return -EINVAL;
++
+ if (modes) {
+ /* Return error if asked to set polarity modes but not supported */
+ if (!phydev->drv->led_polarity_set)
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -877,8 +877,9 @@ struct phy_plca_status {
+
+ /* Modes for PHY LED configuration */
+ enum phy_led_modes {
+- PHY_LED_ACTIVE_LOW = 0,
+- PHY_LED_INACTIVE_HIGH_IMPEDANCE = 1,
++ PHY_LED_ACTIVE_HIGH = 0,
++ PHY_LED_ACTIVE_LOW = 1,
++ PHY_LED_INACTIVE_HIGH_IMPEDANCE = 2,
+
+ /* keep it last */
+ __PHY_LED_MODES_NUM,
--- /dev/null
+From 9d55e68b19f222e6334ef4021c5527998f5ab537 Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Oct 2024 13:55:00 +0100
+Subject: [PATCH 2/4] net: phy: aquantia: correctly describe LED polarity
+ override
+
+Use newly defined 'active-high' property to set the
+VEND1_GLOBAL_LED_DRIVE_VDD bit and let 'active-low' clear that bit. This
+reflects the technical reality which was inverted in the previous
+description in which the 'active-low' property was used to actually set
+the VEND1_GLOBAL_LED_DRIVE_VDD bit, which means that VDD (ie. supply
+voltage) of the LED is driven rather than GND.
+
+Link: https://patch.msgid.link/86a413b4387c42dcb54f587cc2433a06f16aae83.1728558223.git.daniel@makrotopia.org
+---
+ drivers/net/phy/aquantia/aquantia.h | 1 +
+ drivers/net/phy/aquantia/aquantia_leds.c | 19 ++++++++++++++-----
+ drivers/net/phy/aquantia/aquantia_main.c | 12 +++++++++---
+ 3 files changed, 24 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/aquantia/aquantia.h
++++ b/drivers/net/phy/aquantia/aquantia.h
+@@ -177,6 +177,7 @@ static const struct aqr107_hw_stat aqr10
+ struct aqr107_priv {
+ u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
+ unsigned long leds_active_low;
++ unsigned long leds_active_high;
+ };
+
+ #if IS_REACHABLE(CONFIG_HWMON)
+--- a/drivers/net/phy/aquantia/aquantia_leds.c
++++ b/drivers/net/phy/aquantia/aquantia_leds.c
+@@ -121,13 +121,13 @@ int aqr_phy_led_active_low_set(struct ph
+ {
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
+ VEND1_GLOBAL_LED_DRIVE_VDD,
+- enable ? VEND1_GLOBAL_LED_DRIVE_VDD : 0);
++ enable ? 0 : VEND1_GLOBAL_LED_DRIVE_VDD);
+ }
+
+ int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
+ {
++ bool force_active_low = false, force_active_high = false;
+ struct aqr107_priv *priv = phydev->priv;
+- bool active_low = false;
+ u32 mode;
+
+ if (index >= AQR_MAX_LEDS)
+@@ -136,7 +136,10 @@ int aqr_phy_led_polarity_set(struct phy_
+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
+ switch (mode) {
+ case PHY_LED_ACTIVE_LOW:
+- active_low = true;
++ force_active_low = true;
++ break;
++ case PHY_LED_ACTIVE_HIGH:
++ force_active_high = true;
+ break;
+ default:
+ return -EINVAL;
+@@ -144,8 +147,14 @@ int aqr_phy_led_polarity_set(struct phy_
+ }
+
+ /* Save LED driver vdd state to restore on SW reset */
+- if (active_low)
++ if (force_active_low)
+ priv->leds_active_low |= BIT(index);
+
+- return aqr_phy_led_active_low_set(phydev, index, active_low);
++ if (force_active_high)
++ priv->leds_active_high |= BIT(index);
++
++ if (force_active_high || force_active_low)
++ return aqr_phy_led_active_low_set(phydev, index, force_active_low);
++
++ unreachable();
+ }
+--- a/drivers/net/phy/aquantia/aquantia_main.c
++++ b/drivers/net/phy/aquantia/aquantia_main.c
+@@ -517,7 +517,7 @@ static int aqr107_config_mdi(struct phy_
+ static int aqr107_config_init(struct phy_device *phydev)
+ {
+ struct aqr107_priv *priv = phydev->priv;
+- u32 led_active_low;
++ u32 led_idx;
+ int ret;
+
+ /* Check that the PHY interface type is compatible */
+@@ -548,8 +548,14 @@ static int aqr107_config_init(struct phy
+ return ret;
+
+ /* Restore LED polarity state after reset */
+- for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
+- ret = aqr_phy_led_active_low_set(phydev, led_active_low, true);
++ for_each_set_bit(led_idx, &priv->leds_active_low, AQR_MAX_LEDS) {
++ ret = aqr_phy_led_active_low_set(phydev, led_idx, true);
++ if (ret)
++ return ret;
++ }
++
++ for_each_set_bit(led_idx, &priv->leds_active_high, AQR_MAX_LEDS) {
++ ret = aqr_phy_led_active_low_set(phydev, led_idx, false);
+ if (ret)
+ return ret;
+ }
--- /dev/null
+From 78997e9a5e4d8a4df561e083a92c91ae23010e07 Mon Sep 17 00:00:00 2001
+Date: Tue, 1 Oct 2024 01:17:18 +0100
+Subject: [PATCH] net: phy: mxl-gpy: add basic LED support
+
+Add basic support for LEDs connected to MaxLinear GPY2xx and GPY115 PHYs.
+The PHYs allow up to 4 LEDs to be connected.
+Implement controlling LEDs in software as well as netdev trigger offloading
+and LED polarity setup.
+
+The hardware claims to support 16 PWM brightness levels but there is no
+documentation on how to use that feature, hence this is not supported.
+
+Link: https://patch.msgid.link/b6ec9050339f8244ff898898a1cecc33b13a48fc.1727741563.git.daniel@makrotopia.org
+---
+ drivers/net/phy/mxl-gpy.c | 218 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 218 insertions(+)
+
+--- a/drivers/net/phy/mxl-gpy.c
++++ b/drivers/net/phy/mxl-gpy.c
+@@ -38,6 +38,7 @@
+ #define PHY_MIISTAT 0x18 /* MII state */
+ #define PHY_IMASK 0x19 /* interrupt mask */
+ #define PHY_ISTAT 0x1A /* interrupt status */
++#define PHY_LED 0x1B /* LEDs */
+ #define PHY_FWV 0x1E /* firmware version */
+
+ #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
+@@ -61,6 +62,11 @@
+ PHY_IMASK_ADSC | \
+ PHY_IMASK_ANC)
+
++#define GPY_MAX_LEDS 4
++#define PHY_LED_POLARITY(idx) BIT(12 + (idx))
++#define PHY_LED_HWCONTROL(idx) BIT(8 + (idx))
++#define PHY_LED_ON(idx) BIT(idx)
++
+ #define PHY_FWV_REL_MASK BIT(15)
+ #define PHY_FWV_MAJOR_MASK GENMASK(11, 8)
+ #define PHY_FWV_MINOR_MASK GENMASK(7, 0)
+@@ -72,6 +78,23 @@
+ #define PHY_MDI_MDI_X_CD 0x1
+ #define PHY_MDI_MDI_X_CROSS 0x0
+
++/* LED */
++#define VSPEC1_LED(idx) (1 + (idx))
++#define VSPEC1_LED_BLINKS GENMASK(15, 12)
++#define VSPEC1_LED_PULSE GENMASK(11, 8)
++#define VSPEC1_LED_CON GENMASK(7, 4)
++#define VSPEC1_LED_BLINKF GENMASK(3, 0)
++
++#define VSPEC1_LED_LINK10 BIT(0)
++#define VSPEC1_LED_LINK100 BIT(1)
++#define VSPEC1_LED_LINK1000 BIT(2)
++#define VSPEC1_LED_LINK2500 BIT(3)
++
++#define VSPEC1_LED_TXACT BIT(0)
++#define VSPEC1_LED_RXACT BIT(1)
++#define VSPEC1_LED_COL BIT(2)
++#define VSPEC1_LED_NO_CON BIT(3)
++
+ /* SGMII */
+ #define VSPEC1_SGMII_CTRL 0x08
+ #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */
+@@ -835,6 +858,156 @@ static int gpy115_loopback(struct phy_de
+ return genphy_soft_reset(phydev);
+ }
+
++static int gpy_led_brightness_set(struct phy_device *phydev,
++ u8 index, enum led_brightness value)
++{
++ int ret;
++
++ if (index >= GPY_MAX_LEDS)
++ return -EINVAL;
++
++ /* clear HWCONTROL and set manual LED state */
++ ret = phy_modify(phydev, PHY_LED,
++ ((value == LED_OFF) ? PHY_LED_HWCONTROL(index) : 0) |
++ PHY_LED_ON(index),
++ (value == LED_OFF) ? 0 : PHY_LED_ON(index));
++ if (ret)
++ return ret;
++
++ /* ToDo: set PWM brightness */
++
++ /* clear HW LED setup */
++ if (value == LED_OFF)
++ return phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), 0);
++ else
++ return 0;
++}
++
++static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
++ 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 gpy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ if (index >= GPY_MAX_LEDS)
++ return -EINVAL;
++
++ /* All combinations of the supported triggers are allowed */
++ if (rules & ~supported_triggers)
++ return -EOPNOTSUPP;
++
++ return 0;
++}
++
++static int gpy_led_hw_control_get(struct phy_device *phydev, u8 index,
++ unsigned long *rules)
++{
++ int val;
++
++ if (index >= GPY_MAX_LEDS)
++ return -EINVAL;
++
++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index));
++ if (val < 0)
++ return val;
++
++ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK10)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
++
++ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK100)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK1000)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK2500)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
++
++ if (FIELD_GET(VSPEC1_LED_CON, val) == (VSPEC1_LED_LINK10 |
++ VSPEC1_LED_LINK100 |
++ VSPEC1_LED_LINK1000 |
++ VSPEC1_LED_LINK2500))
++ *rules |= BIT(TRIGGER_NETDEV_LINK);
++
++ if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_TXACT)
++ *rules |= BIT(TRIGGER_NETDEV_TX);
++
++ if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_RXACT)
++ *rules |= BIT(TRIGGER_NETDEV_RX);
++
++ return 0;
++}
++
++static int gpy_led_hw_control_set(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ u16 val = 0;
++ int ret;
++
++ if (index >= GPY_MAX_LEDS)
++ return -EINVAL;
++
++ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
++ rules & BIT(TRIGGER_NETDEV_LINK_10))
++ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK10);
++
++ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
++ rules & BIT(TRIGGER_NETDEV_LINK_100))
++ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK100);
++
++ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
++ rules & BIT(TRIGGER_NETDEV_LINK_1000))
++ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK1000);
++
++ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
++ rules & BIT(TRIGGER_NETDEV_LINK_2500))
++ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK2500);
++
++ if (rules & BIT(TRIGGER_NETDEV_TX))
++ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_TXACT);
++
++ if (rules & BIT(TRIGGER_NETDEV_RX))
++ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_RXACT);
++
++ /* allow RX/TX pulse without link indication */
++ if ((rules & BIT(TRIGGER_NETDEV_TX) || rules & BIT(TRIGGER_NETDEV_RX)) &&
++ !(val & VSPEC1_LED_CON))
++ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_NO_CON) | VSPEC1_LED_CON;
++
++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), val);
++ if (ret)
++ return ret;
++
++ return phy_set_bits(phydev, PHY_LED, PHY_LED_HWCONTROL(index));
++}
++
++static int gpy_led_polarity_set(struct phy_device *phydev, int index,
++ unsigned long modes)
++{
++ bool active_low = false;
++ u32 mode;
++
++ if (index >= GPY_MAX_LEDS)
++ return -EINVAL;
++
++ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
++ switch (mode) {
++ case PHY_LED_ACTIVE_LOW:
++ active_low = true;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index),
++ active_low ? 0 : PHY_LED_POLARITY(index));
++}
++
+ static struct phy_driver gpy_drivers[] = {
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx),
+@@ -852,6 +1025,11 @@ static struct phy_driver gpy_drivers[] =
+ .set_wol = gpy_set_wol,
+ .get_wol = gpy_get_wol,
+ .set_loopback = gpy_loopback,
++ .led_brightness_set = gpy_led_brightness_set,
++ .led_hw_is_supported = gpy_led_hw_is_supported,
++ .led_hw_control_get = gpy_led_hw_control_get,
++ .led_hw_control_set = gpy_led_hw_control_set,
++ .led_polarity_set = gpy_led_polarity_set,
+ },
+ {
+ .phy_id = PHY_ID_GPY115B,
+@@ -870,6 +1048,11 @@ static struct phy_driver gpy_drivers[] =
+ .set_wol = gpy_set_wol,
+ .get_wol = gpy_get_wol,
+ .set_loopback = gpy115_loopback,
++ .led_brightness_set = gpy_led_brightness_set,
++ .led_hw_is_supported = gpy_led_hw_is_supported,
++ .led_hw_control_get = gpy_led_hw_control_get,
++ .led_hw_control_set = gpy_led_hw_control_set,
++ .led_polarity_set = gpy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_GPY115C),
+@@ -887,6 +1070,11 @@ static struct phy_driver gpy_drivers[] =
+ .set_wol = gpy_set_wol,
+ .get_wol = gpy_get_wol,
+ .set_loopback = gpy115_loopback,
++ .led_brightness_set = gpy_led_brightness_set,
++ .led_hw_is_supported = gpy_led_hw_is_supported,
++ .led_hw_control_get = gpy_led_hw_control_get,
++ .led_hw_control_set = gpy_led_hw_control_set,
++ .led_polarity_set = gpy_led_polarity_set,
+ },
+ {
+ .phy_id = PHY_ID_GPY211B,
+@@ -905,6 +1093,11 @@ static struct phy_driver gpy_drivers[] =
+ .set_wol = gpy_set_wol,
+ .get_wol = gpy_get_wol,
+ .set_loopback = gpy_loopback,
++ .led_brightness_set = gpy_led_brightness_set,
++ .led_hw_is_supported = gpy_led_hw_is_supported,
++ .led_hw_control_get = gpy_led_hw_control_get,
++ .led_hw_control_set = gpy_led_hw_control_set,
++ .led_polarity_set = gpy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_GPY211C),
+@@ -922,6 +1115,11 @@ static struct phy_driver gpy_drivers[] =
+ .set_wol = gpy_set_wol,
+ .get_wol = gpy_get_wol,
+ .set_loopback = gpy_loopback,
++ .led_brightness_set = gpy_led_brightness_set,
++ .led_hw_is_supported = gpy_led_hw_is_supported,
++ .led_hw_control_get = gpy_led_hw_control_get,
++ .led_hw_control_set = gpy_led_hw_control_set,
++ .led_polarity_set = gpy_led_polarity_set,
+ },
+ {
+ .phy_id = PHY_ID_GPY212B,
+@@ -940,6 +1138,11 @@ static struct phy_driver gpy_drivers[] =
+ .set_wol = gpy_set_wol,
+ .get_wol = gpy_get_wol,
+ .set_loopback = gpy_loopback,
++ .led_brightness_set = gpy_led_brightness_set,
++ .led_hw_is_supported = gpy_led_hw_is_supported,
++ .led_hw_control_get = gpy_led_hw_control_get,
++ .led_hw_control_set = gpy_led_hw_control_set,
++ .led_polarity_set = gpy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_GPY212C),
+@@ -957,6 +1160,11 @@ static struct phy_driver gpy_drivers[] =
+ .set_wol = gpy_set_wol,
+ .get_wol = gpy_get_wol,
+ .set_loopback = gpy_loopback,
++ .led_brightness_set = gpy_led_brightness_set,
++ .led_hw_is_supported = gpy_led_hw_is_supported,
++ .led_hw_control_get = gpy_led_hw_control_get,
++ .led_hw_control_set = gpy_led_hw_control_set,
++ .led_polarity_set = gpy_led_polarity_set,
+ },
+ {
+ .phy_id = PHY_ID_GPY215B,
+@@ -975,6 +1183,11 @@ static struct phy_driver gpy_drivers[] =
+ .set_wol = gpy_set_wol,
+ .get_wol = gpy_get_wol,
+ .set_loopback = gpy_loopback,
++ .led_brightness_set = gpy_led_brightness_set,
++ .led_hw_is_supported = gpy_led_hw_is_supported,
++ .led_hw_control_get = gpy_led_hw_control_get,
++ .led_hw_control_set = gpy_led_hw_control_set,
++ .led_polarity_set = gpy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_GPY215C),
+@@ -992,6 +1205,11 @@ static struct phy_driver gpy_drivers[] =
+ .set_wol = gpy_set_wol,
+ .get_wol = gpy_get_wol,
+ .set_loopback = gpy_loopback,
++ .led_brightness_set = gpy_led_brightness_set,
++ .led_hw_is_supported = gpy_led_hw_is_supported,
++ .led_hw_control_get = gpy_led_hw_control_get,
++ .led_hw_control_set = gpy_led_hw_control_set,
++ .led_polarity_set = gpy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_GPY241B),
--- /dev/null
+From f95b4725e796b12e5f347a0d161e1d3843142aa8 Mon Sep 17 00:00:00 2001
+Date: Fri, 4 Oct 2024 16:56:35 +0100
+Subject: [PATCH] net: phy: mxl-gpy: add missing support for
+ TRIGGER_NETDEV_LINK_10
+
+The PHY also support 10MBit/s links as well as the corresponding link
+indication trigger to be offloaded. Add TRIGGER_NETDEV_LINK_10 to the
+supported triggers.
+
+Link: https://patch.msgid.link/cc5da0a989af8b0d49d823656d88053c4de2ab98.1728057367.git.daniel@makrotopia.org
+---
+ drivers/net/phy/mxl-gpy.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/phy/mxl-gpy.c
++++ b/drivers/net/phy/mxl-gpy.c
+@@ -884,6 +884,7 @@ static int gpy_led_brightness_set(struct
+ }
+
+ static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
++ BIT(TRIGGER_NETDEV_LINK_10) |
+ BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000) |
+ BIT(TRIGGER_NETDEV_LINK_2500) |
--- /dev/null
+From eb89c79c1b8f17fc1611540768678e60df89ac42 Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Oct 2024 13:55:17 +0100
+Subject: [PATCH 3/4] net: phy: mxl-gpy: correctly describe LED polarity
+
+According the datasheet covering the LED (0x1b) register:
+0B Active High LEDx pin driven high when activated
+1B Active Low LEDx pin driven low when activated
+
+Make use of the now available 'active-high' property and correctly
+reflect the polarity setting which was previously inverted.
+
+Link: https://patch.msgid.link/180ccafa837f09908b852a8a874a3808c5ecd2d0.1728558223.git.daniel@makrotopia.org
+---
+ drivers/net/phy/mxl-gpy.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/mxl-gpy.c
++++ b/drivers/net/phy/mxl-gpy.c
+@@ -989,7 +989,7 @@ static int gpy_led_hw_control_set(struct
+ static int gpy_led_polarity_set(struct phy_device *phydev, int index,
+ unsigned long modes)
+ {
+- bool active_low = false;
++ bool force_active_low = false, force_active_high = false;
+ u32 mode;
+
+ if (index >= GPY_MAX_LEDS)
+@@ -998,15 +998,23 @@ static int gpy_led_polarity_set(struct p
+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
+ switch (mode) {
+ case PHY_LED_ACTIVE_LOW:
+- active_low = true;
++ force_active_low = true;
++ break;
++ case PHY_LED_ACTIVE_HIGH:
++ force_active_high = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+- return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index),
+- active_low ? 0 : PHY_LED_POLARITY(index));
++ if (force_active_low)
++ return phy_set_bits(phydev, PHY_LED, PHY_LED_POLARITY(index));
++
++ if (force_active_high)
++ return phy_clear_bits(phydev, PHY_LED, PHY_LED_POLARITY(index));
++
++ unreachable();
+ }
+
+ static struct phy_driver gpy_drivers[] = {
--- /dev/null
+From 1758af47b98c17da464cb45f476875150955dd48 Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Oct 2024 13:55:29 +0100
+Subject: [PATCH 4/4] net: phy: intel-xway: add support for PHY LEDs
+
+The intel-xway PHY driver predates the PHY LED framework and currently
+initializes all LED pins to equal default values.
+
+Add PHY LED functions to the drivers and don't set default values if
+LEDs are defined in device tree.
+
+According the datasheets 3 LEDs are supported on all Intel XWAY PHYs.
+
+Link: https://patch.msgid.link/81f4717ab9acf38f3239727a4540ae96fd01109b.1728558223.git.daniel@makrotopia.org
+---
+ drivers/net/phy/intel-xway.c | 253 +++++++++++++++++++++++++++++++++--
+ 1 file changed, 244 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/phy/intel-xway.c
++++ b/drivers/net/phy/intel-xway.c
+@@ -151,6 +151,13 @@
+ #define XWAY_MMD_LED3H 0x01E8
+ #define XWAY_MMD_LED3L 0x01E9
+
++#define XWAY_GPHY_MAX_LEDS 3
++#define XWAY_GPHY_LED_INV(idx) BIT(12 + (idx))
++#define XWAY_GPHY_LED_EN(idx) BIT(8 + (idx))
++#define XWAY_GPHY_LED_DA(idx) BIT(idx)
++#define XWAY_MMD_LEDxH(idx) (XWAY_MMD_LED0H + 2 * (idx))
++#define XWAY_MMD_LEDxL(idx) (XWAY_MMD_LED0L + 2 * (idx))
++
+ #define PHY_ID_PHY11G_1_3 0x030260D1
+ #define PHY_ID_PHY22F_1_3 0x030260E1
+ #define PHY_ID_PHY11G_1_4 0xD565A400
+@@ -229,20 +236,12 @@ static int xway_gphy_rgmii_init(struct p
+ XWAY_MDIO_MIICTRL_TXSKEW_MASK, val);
+ }
+
+-static int xway_gphy_config_init(struct phy_device *phydev)
++static int xway_gphy_init_leds(struct phy_device *phydev)
+ {
+ int err;
+ u32 ledxh;
+ u32 ledxl;
+
+- /* Mask all interrupts */
+- err = phy_write(phydev, XWAY_MDIO_IMASK, 0);
+- if (err)
+- return err;
+-
+- /* Clear all pending interrupts */
+- phy_read(phydev, XWAY_MDIO_ISTAT);
+-
+ /* Ensure that integrated led function is enabled for all leds */
+ err = phy_write(phydev, XWAY_MDIO_LED,
+ XWAY_MDIO_LED_LED0_EN |
+@@ -276,6 +275,26 @@ static int xway_gphy_config_init(struct
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl);
+
++ return 0;
++}
++
++static int xway_gphy_config_init(struct phy_device *phydev)
++{
++ struct device_node *np = phydev->mdio.dev.of_node;
++ int err;
++
++ /* Mask all interrupts */
++ err = phy_write(phydev, XWAY_MDIO_IMASK, 0);
++ if (err)
++ return err;
++
++ /* Use default LED configuration if 'leds' node isn't defined */
++ if (!of_get_child_by_name(np, "leds"))
++ xway_gphy_init_leds(phydev);
++
++ /* Clear all pending interrupts */
++ phy_read(phydev, XWAY_MDIO_ISTAT);
++
+ err = xway_gphy_rgmii_init(phydev);
+ if (err)
+ return err;
+@@ -347,6 +366,172 @@ static irqreturn_t xway_gphy_handle_inte
+ return IRQ_HANDLED;
+ }
+
++static int xway_gphy_led_brightness_set(struct phy_device *phydev,
++ u8 index, enum led_brightness value)
++{
++ int ret;
++
++ if (index >= XWAY_GPHY_MAX_LEDS)
++ return -EINVAL;
++
++ /* clear EN and set manual LED state */
++ ret = phy_modify(phydev, XWAY_MDIO_LED,
++ ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) |
++ XWAY_GPHY_LED_DA(index),
++ (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index));
++ if (ret)
++ return ret;
++
++ /* clear HW LED setup */
++ if (value == LED_OFF) {
++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0);
++ if (ret)
++ return ret;
++
++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0);
++ } else {
++ return 0;
++ }
++}
++
++static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
++ BIT(TRIGGER_NETDEV_LINK_10) |
++ BIT(TRIGGER_NETDEV_LINK_100) |
++ BIT(TRIGGER_NETDEV_LINK_1000) |
++ BIT(TRIGGER_NETDEV_RX) |
++ BIT(TRIGGER_NETDEV_TX));
++
++static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ if (index >= XWAY_GPHY_MAX_LEDS)
++ return -EINVAL;
++
++ /* activity triggers are not possible without combination with a link
++ * trigger.
++ */
++ if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) &&
++ !(rules & (BIT(TRIGGER_NETDEV_LINK) |
++ BIT(TRIGGER_NETDEV_LINK_10) |
++ BIT(TRIGGER_NETDEV_LINK_100) |
++ BIT(TRIGGER_NETDEV_LINK_1000))))
++ return -EOPNOTSUPP;
++
++ /* All other combinations of the supported triggers are allowed */
++ if (rules & ~supported_triggers)
++ return -EOPNOTSUPP;
++
++ return 0;
++}
++
++static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index,
++ unsigned long *rules)
++{
++ int lval, hval;
++
++ if (index >= XWAY_GPHY_MAX_LEDS)
++ return -EINVAL;
++
++ hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index));
++ if (hval < 0)
++ return hval;
++
++ lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index));
++ if (lval < 0)
++ return lval;
++
++ if (hval & XWAY_MMD_LEDxH_CON_LINK10)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
++
++ if (hval & XWAY_MMD_LEDxH_CON_LINK100)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++ if (hval & XWAY_MMD_LEDxH_CON_LINK1000)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++ if ((hval & XWAY_MMD_LEDxH_CON_LINK10) &&
++ (hval & XWAY_MMD_LEDxH_CON_LINK100) &&
++ (hval & XWAY_MMD_LEDxH_CON_LINK1000))
++ *rules |= BIT(TRIGGER_NETDEV_LINK);
++
++ if (lval & XWAY_MMD_LEDxL_PULSE_TXACT)
++ *rules |= BIT(TRIGGER_NETDEV_TX);
++
++ if (lval & XWAY_MMD_LEDxL_PULSE_RXACT)
++ *rules |= BIT(TRIGGER_NETDEV_RX);
++
++ return 0;
++}
++
++static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ u16 hval = 0, lval = 0;
++ int ret;
++
++ if (index >= XWAY_GPHY_MAX_LEDS)
++ return -EINVAL;
++
++ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
++ rules & BIT(TRIGGER_NETDEV_LINK_10))
++ hval |= XWAY_MMD_LEDxH_CON_LINK10;
++
++ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
++ rules & BIT(TRIGGER_NETDEV_LINK_100))
++ hval |= XWAY_MMD_LEDxH_CON_LINK100;
++
++ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
++ rules & BIT(TRIGGER_NETDEV_LINK_1000))
++ hval |= XWAY_MMD_LEDxH_CON_LINK1000;
++
++ if (rules & BIT(TRIGGER_NETDEV_TX))
++ lval |= XWAY_MMD_LEDxL_PULSE_TXACT;
++
++ if (rules & BIT(TRIGGER_NETDEV_RX))
++ lval |= XWAY_MMD_LEDxL_PULSE_RXACT;
++
++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval);
++ if (ret)
++ return ret;
++
++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval);
++ if (ret)
++ return ret;
++
++ return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index));
++}
++
++static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index,
++ unsigned long modes)
++{
++ bool force_active_low = false, force_active_high = false;
++ u32 mode;
++
++ if (index >= XWAY_GPHY_MAX_LEDS)
++ return -EINVAL;
++
++ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
++ switch (mode) {
++ case PHY_LED_ACTIVE_LOW:
++ force_active_low = true;
++ break;
++ case PHY_LED_ACTIVE_HIGH:
++ force_active_high = true;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ if (force_active_low)
++ return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
++
++ if (force_active_high)
++ return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
++
++ unreachable();
++}
++
+ static struct phy_driver xway_gphy[] = {
+ {
+ .phy_id = PHY_ID_PHY11G_1_3,
+@@ -359,6 +544,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ }, {
+ .phy_id = PHY_ID_PHY22F_1_3,
+ .phy_id_mask = 0xffffffff,
+@@ -370,6 +560,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ }, {
+ .phy_id = PHY_ID_PHY11G_1_4,
+ .phy_id_mask = 0xffffffff,
+@@ -381,6 +576,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ }, {
+ .phy_id = PHY_ID_PHY22F_1_4,
+ .phy_id_mask = 0xffffffff,
+@@ -392,6 +592,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ }, {
+ .phy_id = PHY_ID_PHY11G_1_5,
+ .phy_id_mask = 0xffffffff,
+@@ -402,6 +607,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ }, {
+ .phy_id = PHY_ID_PHY22F_1_5,
+ .phy_id_mask = 0xffffffff,
+@@ -412,6 +622,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ }, {
+ .phy_id = PHY_ID_PHY11G_VR9_1_1,
+ .phy_id_mask = 0xffffffff,
+@@ -422,6 +637,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ }, {
+ .phy_id = PHY_ID_PHY22F_VR9_1_1,
+ .phy_id_mask = 0xffffffff,
+@@ -432,6 +652,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ }, {
+ .phy_id = PHY_ID_PHY11G_VR9_1_2,
+ .phy_id_mask = 0xffffffff,
+@@ -442,6 +667,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ }, {
+ .phy_id = PHY_ID_PHY22F_VR9_1_2,
+ .phy_id_mask = 0xffffffff,
+@@ -452,6 +682,11 @@ static struct phy_driver xway_gphy[] = {
+ .config_intr = xway_gphy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
++ .led_brightness_set = xway_gphy_led_brightness_set,
++ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
++ .led_hw_control_get = xway_gphy_led_hw_control_get,
++ .led_hw_control_set = xway_gphy_led_hw_control_set,
++ .led_polarity_set = xway_gphy_led_polarity_set,
+ },
+ };
+ module_phy_driver(xway_gphy);
+++ /dev/null
-From 6e7370079669b0d55c9464bb7c3fb8fb7368b912 Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:50 +0800
-Subject: [PATCH 11/20] net: phy: mediatek: Add token ring access helper
- functions in mtk-phy-lib
-
-This patch adds TR(token ring) manipulations and adds correct
-macro names for those magic numbers. TR is a way to access
-proprietary registers on page 52b5. Use these helper functions
-so we can see which fields we're going to modify/set/clear.
-
-TR functions with __* prefix mean that the operations inside
-aren't wrapped by page select/restore functions.
-
-This patch doesn't really change registers' settings but just
-enhances readability and maintainability.
-
----
- drivers/net/phy/mediatek/mtk-ge-soc.c | 231 +++++++++++++++++--------
- drivers/net/phy/mediatek/mtk-ge.c | 11 +-
- drivers/net/phy/mediatek/mtk-phy-lib.c | 63 +++++++
- drivers/net/phy/mediatek/mtk.h | 5 +
- 4 files changed, 230 insertions(+), 80 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -25,6 +25,90 @@
-
- #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-
-+/* Registers on Token Ring debug nodes */
-+/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */
-+/* NormMseLoThresh */
-+#define NORMAL_MSE_LO_THRESH_MASK GENMASK(15, 8)
-+
-+/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
-+/* RemAckCntLimitCtrl */
-+#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK GENMASK(2, 1)
-+
-+/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */
-+/* VcoSlicerThreshBitsHigh */
-+#define VCO_SLICER_THRESH_HIGH_MASK GENMASK(23, 0)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */
-+/* DfeTailEnableVgaThresh1000 */
-+#define DFE_TAIL_EANBLE_VGA_TRHESH_1000 GENMASK(5, 1)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */
-+/* MrvlTrFix100Kp */
-+#define MRVL_TR_FIX_100KP_MASK GENMASK(22, 20)
-+/* MrvlTrFix100Kf */
-+#define MRVL_TR_FIX_100KF_MASK GENMASK(19, 17)
-+/* MrvlTrFix1000Kp */
-+#define MRVL_TR_FIX_1000KP_MASK GENMASK(16, 14)
-+/* MrvlTrFix1000Kf */
-+#define MRVL_TR_FIX_1000KF_MASK GENMASK(13, 11)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */
-+/* VgaDecRate */
-+#define VGA_DECIMATION_RATE_MASK GENMASK(8, 5)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
-+/* SlvDSPreadyTime */
-+#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15)
-+/* MasDSPreadyTime */
-+#define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
-+/* ResetSyncOffset */
-+#define RESET_SYNC_OFFSET_MASK GENMASK(11, 8)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */
-+/* FfeUpdGainForceVal */
-+#define FFE_UPDATE_GAIN_FORCE_VAL_MASK GENMASK(9, 7)
-+/* FfeUpdGainForce */
-+#define FFE_UPDATE_GAIN_FORCE BIT(6)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
-+/* SS: Steady-state, KP: Proportional Gain */
-+/* SSTrKp100 */
-+#define SS_TR_KP100_MASK GENMASK(21, 19)
-+/* SSTrKf100 */
-+#define SS_TR_KF100_MASK GENMASK(18, 16)
-+/* SSTrKp1000Mas */
-+#define SS_TR_KP1000_MASTER_MASK GENMASK(15, 13)
-+/* SSTrKf1000Mas */
-+#define SS_TR_KF1000_MASTER_MASK GENMASK(12, 10)
-+/* SSTrKp1000Slv */
-+#define SS_TR_KP1000_SLAVE_MASK GENMASK(9, 7)
-+/* SSTrKf1000Slv */
-+#define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
-+/* RegEEE_st2TrKf1000 */
-+#define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */
-+/* RegEEE_slv_waketr_timer_tar */
-+#define SLAVE_WAKETR_TIMER_MASK GENMASK(20, 11)
-+/* RegEEE_slv_remtx_timer_tar */
-+#define SLAVE_REMTX_TIMER_MASK GENMASK(10, 1)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */
-+/* RegEEE_slv_wake_int_timer_tar */
-+#define SLAVE_WAKEINT_TIMER_MASK GENMASK(10, 1)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */
-+/* RegEEE_trfreeze_timer2 */
-+#define TR_FREEZE_TIMER2_MASK GENMASK(9, 0)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */
-+/* RegEEE100Stg1_tar */
-+#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0)
-+
- #define ANALOG_INTERNAL_OPERATION_MAX_US 20
- #define TXRESERVE_MIN 0
- #define TXRESERVE_MAX 7
-@@ -700,40 +784,41 @@ restore:
- static void mt798x_phy_common_finetune(struct phy_device *phydev)
- {
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
-- __phy_write(phydev, 0x11, 0xc71);
-- __phy_write(phydev, 0x12, 0xc);
-- __phy_write(phydev, 0x10, 0x8fae);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x17,
-+ SLAVE_DSP_READY_TIME_MASK | MASTER_DSP_READY_TIME_MASK,
-+ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) |
-+ FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18));
-
- /* EnabRandUpdTrig = 1 */
- __phy_write(phydev, 0x11, 0x2f00);
- __phy_write(phydev, 0x12, 0xe);
- __phy_write(phydev, 0x10, 0x8fb0);
-
-- /* NormMseLoThresh = 85 */
-- __phy_write(phydev, 0x11, 0x55a0);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x83aa);
--
-- /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
-- __phy_write(phydev, 0x11, 0x240);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9680);
-+ __mtk_tr_modify(phydev, 0x0, 0x7, 0x15,
-+ NORMAL_MSE_LO_THRESH_MASK,
-+ FIELD_PREP(NORMAL_MSE_LO_THRESH_MASK, 0x55));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x0,
-+ FFE_UPDATE_GAIN_FORCE_VAL_MASK,
-+ FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) |
-+ FFE_UPDATE_GAIN_FORCE);
-
- /* TrFreeze = 0 (mt7988 default) */
- __phy_write(phydev, 0x11, 0x0);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x9686);
-
-- /* SSTrKp100 = 5 */
-- /* SSTrKf100 = 6 */
-- /* SSTrKp1000Mas = 5 */
-- /* SSTrKf1000Mas = 6 */
-- /* SSTrKp1000Slv = 5 */
-- /* SSTrKf1000Slv = 6 */
-- __phy_write(phydev, 0x11, 0xbaef);
-- __phy_write(phydev, 0x12, 0x2e);
-- __phy_write(phydev, 0x10, 0x968c);
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x6,
-+ SS_TR_KP100_MASK | SS_TR_KF100_MASK |
-+ SS_TR_KP1000_MASTER_MASK | SS_TR_KF1000_MASTER_MASK |
-+ SS_TR_KP1000_SLAVE_MASK | SS_TR_KF1000_SLAVE_MASK,
-+ FIELD_PREP(SS_TR_KP100_MASK, 0x5) |
-+ FIELD_PREP(SS_TR_KF100_MASK, 0x6) |
-+ FIELD_PREP(SS_TR_KP1000_MASTER_MASK, 0x5) |
-+ FIELD_PREP(SS_TR_KF1000_MASTER_MASK, 0x6) |
-+ FIELD_PREP(SS_TR_KP1000_SLAVE_MASK, 0x5) |
-+ FIELD_PREP(SS_TR_KF1000_SLAVE_MASK, 0x6));
-+
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
- }
-
-@@ -756,27 +841,29 @@ static void mt7981_phy_finetune(struct p
- }
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* ResetSyncOffset = 6 */
-- __phy_write(phydev, 0x11, 0x600);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8fc0);
--
-- /* VgaDecRate = 1 */
-- __phy_write(phydev, 0x11, 0x4c2a);
-- __phy_write(phydev, 0x12, 0x3e);
-- __phy_write(phydev, 0x10, 0x8fa4);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
-+ RESET_SYNC_OFFSET_MASK,
-+ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x6));
-+
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x12,
-+ VGA_DECIMATION_RATE_MASK,
-+ FIELD_PREP(VGA_DECIMATION_RATE_MASK, 0x1));
-
- /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
- * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
- */
-- __phy_write(phydev, 0x11, 0xd10a);
-- __phy_write(phydev, 0x12, 0x34);
-- __phy_write(phydev, 0x10, 0x8f82);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
-+ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
-+ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
-+ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x3) |
-+ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x2) |
-+ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x3) |
-+ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x2));
-
- /* VcoSlicerThreshBitsHigh */
-- __phy_write(phydev, 0x11, 0x5555);
-- __phy_write(phydev, 0x12, 0x55);
-- __phy_write(phydev, 0x10, 0x8ec0);
-+ __mtk_tr_modify(phydev, 0x1, 0xd, 0x20,
-+ VCO_SLICER_THRESH_HIGH_MASK,
-+ FIELD_PREP(VCO_SLICER_THRESH_HIGH_MASK, 0x555555));
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
-@@ -828,25 +915,23 @@ static void mt7988_phy_finetune(struct p
- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* ResetSyncOffset = 5 */
-- __phy_write(phydev, 0x11, 0x500);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8fc0);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
-+ RESET_SYNC_OFFSET_MASK,
-+ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x5));
-
- /* VgaDecRate is 1 at default on mt7988 */
-
-- /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
-- * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
-- */
-- __phy_write(phydev, 0x11, 0xb90a);
-- __phy_write(phydev, 0x12, 0x6f);
-- __phy_write(phydev, 0x10, 0x8f82);
--
-- /* RemAckCntLimitCtrl = 1 */
-- __phy_write(phydev, 0x11, 0xfbba);
-- __phy_write(phydev, 0x12, 0xc3);
-- __phy_write(phydev, 0x10, 0x87f8);
--
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
-+ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
-+ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
-+ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x6) |
-+ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x7) |
-+ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x6) |
-+ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x7));
-+
-+ __mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
-+ REMOTE_ACK_COUNT_LIMIT_CTRL_MASK,
-+ FIELD_PREP(REMOTE_ACK_COUNT_LIMIT_CTRL_MASK, 0x1));
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
-@@ -927,40 +1012,36 @@ static void mt798x_phy_eee(struct phy_de
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x9690);
-
-- /* REG_EEE_st2TrKf1000 = 2 */
-- __phy_write(phydev, 0x11, 0x114f);
-- __phy_write(phydev, 0x12, 0x2);
-- __phy_write(phydev, 0x10, 0x969a);
--
-- /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
-- __phy_write(phydev, 0x11, 0x3028);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x969e);
--
-- /* RegEEE_slv_wake_int_timer_tar = 8 */
-- __phy_write(phydev, 0x11, 0x5010);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96a0);
--
-- /* RegEEE_trfreeze_timer2 = 586 */
-- __phy_write(phydev, 0x11, 0x24a);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96a8);
--
-- /* RegEEE100Stg1_tar = 16 */
-- __phy_write(phydev, 0x11, 0x3210);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96b8);
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0xd,
-+ EEE1000_STAGE2_TR_KF_MASK,
-+ FIELD_PREP(EEE1000_STAGE2_TR_KF_MASK, 0x2));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0xf,
-+ SLAVE_WAKETR_TIMER_MASK | SLAVE_REMTX_TIMER_MASK,
-+ FIELD_PREP(SLAVE_WAKETR_TIMER_MASK, 0x6) |
-+ FIELD_PREP(SLAVE_REMTX_TIMER_MASK, 0x14));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x10,
-+ SLAVE_WAKEINT_TIMER_MASK,
-+ FIELD_PREP(SLAVE_WAKEINT_TIMER_MASK, 0x8));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x14,
-+ TR_FREEZE_TIMER2_MASK,
-+ FIELD_PREP(TR_FREEZE_TIMER2_MASK, 0x24a));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x1c,
-+ EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
-+ FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
-+ 0x10));
-
- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
- __phy_write(phydev, 0x11, 0x1463);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x96ca);
-
-- /* DfeTailEnableVgaThresh1000 = 27 */
-- __phy_write(phydev, 0x11, 0x36);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8f80);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x0,
-+ DFE_TAIL_EANBLE_VGA_TRHESH_1000,
-+ FIELD_PREP(DFE_TAIL_EANBLE_VGA_TRHESH_1000, 0x1b));
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -18,6 +18,10 @@
-
- #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-
-+/* Registers on Token Ring debug nodes */
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
-+#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15)
-+
- /* Registers on MDIO_MMD_VEND1 */
- #define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13
- #define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14
-@@ -42,11 +46,8 @@ static void mtk_gephy_config_init(struct
- 0, MTK_PHY_ENABLE_DOWNSHIFT);
-
- /* Increase SlvDPSready time */
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- __phy_write(phydev, 0x10, 0xafae);
-- __phy_write(phydev, 0x12, 0x2f);
-- __phy_write(phydev, 0x10, 0x8fae);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+ mtk_tr_modify(phydev, 0x1, 0xf, 0x17, SLAVE_DSP_READY_TIME_MASK,
-+ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x5e));
-
- /* Adjust 100_mse_threshold */
- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -6,6 +6,69 @@
-
- #include "mtk.h"
-
-+/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is
-+ * mtk_tr* functions: wrapped by page switching operations
-+ * __mtk_tr* functions: no page switching operations
-+ */
-+
-+static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr,
-+ u8 node_addr, u8 data_addr)
-+{
-+ u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */
-+
-+ if (read)
-+ tr_cmd |= BIT(13);
-+
-+ tr_cmd |= (((ch_addr & 0x3) << 11) |
-+ ((node_addr & 0xf) << 7) |
-+ ((data_addr & 0x3f) << 1));
-+ dev_dbg(&phydev->mdio.dev, "tr_cmd: 0x%x\n", tr_cmd);
-+ __phy_write(phydev, 0x10, tr_cmd);
-+}
-+
-+static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u16 *tr_high, u16 *tr_low)
-+{
-+ __mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr);
-+ *tr_low = __phy_read(phydev, 0x11);
-+ *tr_high = __phy_read(phydev, 0x12);
-+ dev_dbg(&phydev->mdio.dev, "tr_high read: 0x%x, tr_low read: 0x%x\n",
-+ *tr_high, *tr_low);
-+}
-+
-+static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 tr_data)
-+{
-+ __phy_write(phydev, 0x11, tr_data & 0xffff);
-+ __phy_write(phydev, 0x12, tr_data >> 16);
-+ dev_dbg(&phydev->mdio.dev, "tr_high write: 0x%x, tr_low write: 0x%x\n",
-+ tr_data >> 16, tr_data & 0xffff);
-+ __mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr);
-+}
-+
-+void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 mask, u32 set)
-+{
-+ u32 tr_data;
-+ u16 tr_high;
-+ u16 tr_low;
-+
-+ __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low);
-+ tr_data = (tr_high << 16) | tr_low;
-+ tr_data = (tr_data & ~mask) | set;
-+ __mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data);
-+}
-+EXPORT_SYMBOL_GPL(__mtk_tr_modify);
-+
-+void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 mask, u32 set)
-+{
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+}
-+EXPORT_SYMBOL_GPL(mtk_tr_modify);
-+
- int mtk_phy_read_page(struct phy_device *phydev)
- {
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -68,6 +68,11 @@ struct mtk_socphy_priv {
- unsigned long led_state;
- };
-
-+void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 mask, u32 set);
-+void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 mask, u32 set);
-+
- int mtk_phy_read_page(struct phy_device *phydev);
- int mtk_phy_write_page(struct phy_device *phydev, int page);
-
+++ /dev/null
-From c7e2fb3421ef5ebbb4c91f44bd735ab10edd755a Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:51 +0800
-Subject: [PATCH 12/20] net: phy: mediatek: Add token ring set bit operation
- support
-
-Previously in mtk-ge-soc.c, we set some register bits via token
-ring, which were implemented in three __phy_write().
-Now we can do the same thing via __mtk_tr_set_bits() helper.
-
----
- drivers/net/phy/mediatek/mtk-ge-soc.c | 10 ++++++----
- drivers/net/phy/mediatek/mtk-phy-lib.c | 7 +++++++
- drivers/net/phy/mediatek/mtk.h | 2 ++
- 3 files changed, 15 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -62,6 +62,10 @@
- /* MasDSPreadyTime */
- #define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7)
-
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */
-+/* EnabRandUpdTrig */
-+#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER BIT(8)
-+
- /* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
- /* ResetSyncOffset */
- #define RESET_SYNC_OFFSET_MASK GENMASK(11, 8)
-@@ -789,10 +793,8 @@ static void mt798x_phy_common_finetune(s
- FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) |
- FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18));
-
-- /* EnabRandUpdTrig = 1 */
-- __phy_write(phydev, 0x11, 0x2f00);
-- __phy_write(phydev, 0x12, 0xe);
-- __phy_write(phydev, 0x10, 0x8fb0);
-+ __mtk_tr_set_bits(phydev, 0x1, 0xf, 0x18,
-+ ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER);
-
- __mtk_tr_modify(phydev, 0x0, 0x7, 0x15,
- NORMAL_MSE_LO_THRESH_MASK,
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -69,6 +69,13 @@ void mtk_tr_modify(struct phy_device *ph
- }
- EXPORT_SYMBOL_GPL(mtk_tr_modify);
-
-+void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 set)
-+{
-+ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set);
-+}
-+EXPORT_SYMBOL_GPL(__mtk_tr_set_bits);
-+
- int mtk_phy_read_page(struct phy_device *phydev)
- {
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -72,6 +72,8 @@ void __mtk_tr_modify(struct phy_device *
- u8 data_addr, u32 mask, u32 set);
- void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
- u8 data_addr, u32 mask, u32 set);
-+void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 set);
-
- int mtk_phy_read_page(struct phy_device *phydev);
- int mtk_phy_write_page(struct phy_device *phydev, int page);
+++ /dev/null
-From 7851c73a416b15aff6f9ada9c88affc5f48ff011 Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:52 +0800
-Subject: [PATCH 13/20] net: phy: mediatek: Add token ring clear bit operation
- support
-
-Similar to __mtk_tr_set_bits() support. Previously in mtk-ge-soc.c,
-we clear some register bits via token ring, which were also implemented
-in three __phy_write(). Now we can do the same thing via
-__mtk_tr_clr_bits() helper.
-
----
- drivers/net/phy/mediatek/mtk-ge-soc.c | 30 +++++++++++++++-----------
- drivers/net/phy/mediatek/mtk-phy-lib.c | 7 ++++++
- drivers/net/phy/mediatek/mtk.h | 2 ++
- 3 files changed, 27 insertions(+), 12 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -76,6 +76,10 @@
- /* FfeUpdGainForce */
- #define FFE_UPDATE_GAIN_FORCE BIT(6)
-
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */
-+/* TrFreeze */
-+#define TR_FREEZE_MASK GENMASK(11, 0)
-+
- /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
- /* SS: Steady-state, KP: Proportional Gain */
- /* SSTrKp100 */
-@@ -91,6 +95,11 @@
- /* SSTrKf1000Slv */
- #define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4)
-
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */
-+/* clear this bit if wanna select from AFE */
-+/* Regsigdet_sel_1000 */
-+#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE BIT(4)
-+
- /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
- /* RegEEE_st2TrKf1000 */
- #define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11)
-@@ -113,6 +122,10 @@
- /* RegEEE100Stg1_tar */
- #define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0)
-
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */
-+/* REGEEE_wake_slv_tr_wait_dfesigdet_en */
-+#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN BIT(11)
-+
- #define ANALOG_INTERNAL_OPERATION_MAX_US 20
- #define TXRESERVE_MIN 0
- #define TXRESERVE_MAX 7
-@@ -805,10 +818,7 @@ static void mt798x_phy_common_finetune(s
- FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) |
- FFE_UPDATE_GAIN_FORCE);
-
-- /* TrFreeze = 0 (mt7988 default) */
-- __phy_write(phydev, 0x11, 0x0);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9686);
-+ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x3, TR_FREEZE_MASK);
-
- __mtk_tr_modify(phydev, 0x2, 0xd, 0x6,
- SS_TR_KP100_MASK | SS_TR_KF100_MASK |
-@@ -1009,10 +1019,8 @@ static void mt798x_phy_eee(struct phy_de
- MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* Regsigdet_sel_1000 = 0 */
-- __phy_write(phydev, 0x11, 0xb);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9690);
-+ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x8,
-+ EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE);
-
- __mtk_tr_modify(phydev, 0x2, 0xd, 0xd,
- EEE1000_STAGE2_TR_KF_MASK,
-@@ -1036,10 +1044,8 @@ static void mt798x_phy_eee(struct phy_de
- FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
- 0x10));
-
-- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
-- __phy_write(phydev, 0x11, 0x1463);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96ca);
-+ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x25,
-+ WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN);
-
- __mtk_tr_modify(phydev, 0x1, 0xf, 0x0,
- DFE_TAIL_EANBLE_VGA_TRHESH_1000,
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -76,6 +76,13 @@ void __mtk_tr_set_bits(struct phy_device
- }
- EXPORT_SYMBOL_GPL(__mtk_tr_set_bits);
-
-+void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 clr)
-+{
-+ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0);
-+}
-+EXPORT_SYMBOL_GPL(__mtk_tr_clr_bits);
-+
- int mtk_phy_read_page(struct phy_device *phydev)
- {
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -74,6 +74,8 @@ void mtk_tr_modify(struct phy_device *ph
- u8 data_addr, u32 mask, u32 set);
- void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
- u8 data_addr, u32 set);
-+void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 clr);
-
- int mtk_phy_read_page(struct phy_device *phydev);
- int mtk_phy_write_page(struct phy_device *phydev, int page);
+++ /dev/null
-From bae8c61522c4d5a5250a24dcb57d120ea593fab1 Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:53 +0800
-Subject: [PATCH 14/20] net: phy: mediatek: Move some macros to phy-lib for
- later use
-
-Move some macros to phy-lib because MediaTek's 2.5G built-in
-ethernet PHY will also use them.
-
----
- drivers/net/phy/mediatek/mtk-ge.c | 4 ----
- drivers/net/phy/mediatek/mtk.h | 4 ++++
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -8,10 +8,6 @@
- #define MTK_GPHY_ID_MT7530 0x03a29412
- #define MTK_GPHY_ID_MT7531 0x03a29441
-
--#define MTK_PHY_PAGE_EXTENDED_1 0x0001
--#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
--#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
--
- #define MTK_PHY_PAGE_EXTENDED_2 0x0002
- #define MTK_PHY_PAGE_EXTENDED_3 0x0003
- #define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -8,7 +8,11 @@
- #ifndef _MTK_EPHY_H_
- #define _MTK_EPHY_H_
-
-+#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
-+#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
-+
- #define MTK_EXT_PAGE_ACCESS 0x1f
-+#define MTK_PHY_PAGE_EXTENDED_1 0x0001
- #define MTK_PHY_PAGE_STANDARD 0x0000
- #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-
+++ /dev/null
-From e5566162af8b9690e096d2e6089e4ed955a0d13d Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Apr 2025 12:04:03 +0200
-Subject: [PATCH] net: phy: mediatek: permit to compile test GE SOC PHY driver
-
-When commit 462a3daad679 ("net: phy: mediatek: fix compile-test
-dependencies") fixed the dependency, it should have also introduced
-an or on COMPILE_TEST to permit this driver to be compile-tested even if
-NVMEM_MTK_EFUSE wasn't selected. The driver makes use of NVMEM API that
-are always compiled (return error) so the driver can actually be
-compiled even without that config.
-
-Fix and simplify the dependency condition of this kernel config.
-
-Fixes: 462a3daad679 ("net: phy: mediatek: fix compile-test dependencies")
----
- drivers/net/phy/mediatek/Kconfig | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/net/phy/mediatek/Kconfig
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -15,8 +15,7 @@ config MEDIATEK_GE_PHY
-
- config MEDIATEK_GE_SOC_PHY
- tristate "MediaTek SoC Ethernet PHYs"
-- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
-- depends on NVMEM_MTK_EFUSE
-+ depends on (ARM64 && ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST
- select MTK_NET_PHYLIB
- help
- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+++ /dev/null
-From 4590c8bc10951feee3e439bf7fff1b458c2e6fad Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Apr 2025 12:04:04 +0200
-Subject: [PATCH 17/20] net: phy: mediatek: add Airoha PHY ID to SoC driver
-
-Airoha AN7581 SoC ship with a Switch based on the MT753x Switch embedded
-in other SoC like the MT7581 and the MT7988. Similar to these they
-require configuring some pin to enable LED PHYs.
-
-Add support for the PHY ID for the Airoha embedded Switch and define a
-simple probe function to toggle these pins. Also fill the LED functions
-and add dedicated function to define LED polarity.
-
----
- drivers/net/phy/mediatek/Kconfig | 4 +-
- drivers/net/phy/mediatek/mtk-ge-soc.c | 62 +++++++++++++++++++++++++++
- 2 files changed, 65 insertions(+), 1 deletion(-)
-
---- a/drivers/net/phy/mediatek/Kconfig
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -15,7 +15,9 @@ config MEDIATEK_GE_PHY
-
- config MEDIATEK_GE_SOC_PHY
- tristate "MediaTek SoC Ethernet PHYs"
-- depends on (ARM64 && ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST
-+ depends on ARM64 || COMPILE_TEST
-+ depends on ARCH_AIROHA || (ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || \
-+ COMPILE_TEST
- select MTK_NET_PHYLIB
- help
- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -10,8 +10,11 @@
-
- #include "mtk.h"
-
-+#define MTK_PHY_MAX_LEDS 2
-+
- #define MTK_GPHY_ID_MT7981 0x03a29461
- #define MTK_GPHY_ID_MT7988 0x03a29481
-+#define MTK_GPHY_ID_AN7581 0x03a294c1
-
- #define MTK_EXT_PAGE_ACCESS 0x1f
- #define MTK_PHY_PAGE_STANDARD 0x0000
-@@ -1405,6 +1408,53 @@ static int mt7981_phy_probe(struct phy_d
- return mt798x_phy_calibration(phydev);
- }
-
-+static int an7581_phy_probe(struct phy_device *phydev)
-+{
-+ struct mtk_socphy_priv *priv;
-+ struct pinctrl *pinctrl;
-+
-+ /* Toggle pinctrl to enable PHY LED */
-+ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
-+ if (IS_ERR(pinctrl))
-+ dev_err(&phydev->mdio.bus->dev,
-+ "Failed to setup PHY LED pinctrl\n");
-+
-+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ phydev->priv = priv;
-+
-+ return 0;
-+}
-+
-+static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes)
-+{
-+ u32 mode;
-+ u16 val;
-+
-+ if (index >= MTK_PHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ val = MTK_PHY_LED_ON_POLARITY;
-+ break;
-+ case PHY_LED_ACTIVE_HIGH:
-+ val = 0;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED_ON_POLARITY, val);
-+}
-+
- static struct phy_driver mtk_socphy_driver[] = {
- {
- PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
-@@ -1440,6 +1490,17 @@ static struct phy_driver mtk_socphy_driv
- .led_hw_control_set = mt798x_phy_led_hw_control_set,
- .led_hw_control_get = mt798x_phy_led_hw_control_get,
- },
-+ {
-+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581),
-+ .name = "Airoha AN7581 PHY",
-+ .probe = an7581_phy_probe,
-+ .led_blink_set = mt798x_phy_led_blink_set,
-+ .led_brightness_set = mt798x_phy_led_brightness_set,
-+ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-+ .led_hw_control_set = mt798x_phy_led_hw_control_set,
-+ .led_hw_control_get = mt798x_phy_led_hw_control_get,
-+ .led_polarity_set = an7581_phy_led_polarity_set,
-+ },
- };
-
- module_phy_driver(mtk_socphy_driver);
-@@ -1447,6 +1508,7 @@ module_phy_driver(mtk_socphy_driver);
- static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
-+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581) },
- { }
- };
-
+++ /dev/null
-From 34501d047ac0a6cbb13285ba9d15f75c1deb7da7 Mon Sep 17 00:00:00 2001
-Date: Tue, 15 Apr 2025 12:53:05 +0200
-Subject: [PATCH 18/20] net: phy: mediatek: init val in .phy_led_polarity_set
- for AN7581
-
-Fix smatch warning for uninitialised val in .phy_led_polarity_set for
-AN7581 driver.
-
-Correctly init to 0 to set polarity high by default.
-
-Fixes: 6a325aed130b ("net: phy: mediatek: add Airoha PHY ID to SoC driver")
----
- drivers/net/phy/mediatek/mtk-ge-soc.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -1431,8 +1431,8 @@ static int an7581_phy_probe(struct phy_d
- static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,
- unsigned long modes)
- {
-+ u16 val = 0;
- u32 mode;
-- u16 val;
-
- if (index >= MTK_PHY_MAX_LEDS)
- return -EINVAL;
-@@ -1443,7 +1443,6 @@ static int an7581_phy_led_polarity_set(s
- val = MTK_PHY_LED_ON_POLARITY;
- break;
- case PHY_LED_ACTIVE_HIGH:
-- val = 0;
- break;
- default:
- return -EINVAL;
--- /dev/null
+From 7b590490e3aa6bfa38bf6e2069a529017fd3c1d2 Mon Sep 17 00:00:00 2001
+Date: Fri, 13 Oct 2023 00:08:35 +0200
+Subject: [PATCH] net: dsa: mv88e6xxx: Support LED control
+
+This adds control over the hardware LEDs in the Marvell
+MV88E6xxx DSA switch and enables it for MV88E6352.
+
+This fixes an imminent problem on the Inteno XG6846 which
+has a WAN LED that simply do not work with hardware
+defaults: driver amendment is necessary.
+
+The patch is modeled after Christian Marangis LED support
+code for the QCA8k DSA switch, I got help with the register
+definitions from Tim Harvey.
+
+After this patch it is possible to activate hardware link
+indication like this (or with a similar script):
+
+ cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
+ echo netdev > trigger
+ echo 1 > link
+
+This makes the green link indicator come up on any link
+speed. It is also possible to be more elaborate, like this:
+
+ cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
+ echo netdev > trigger
+ echo 1 > link_1000
+ cd /sys/class/leds/Marvell\ 88E6352:05:01:amber:wan/
+ echo netdev > trigger
+ echo 1 > link_100
+
+Making the green LED come on for a gigabit link and the
+amber LED come on for a 100 mbit link.
+
+Each port has 2 LED slots (the hardware may use just one or
+none) and the hardware triggers are specified in four bits per
+LED, and some of the hardware triggers are only available on the
+SFP (fiber) uplink. The restrictions are described in the
+port.h header file where the registers are described. For
+example, selector 1 set for LED 1 on port 5 or 6 will indicate
+Fiber 1000 (gigabit) and activity with a blinking LED, but
+ONLY for an SFP connection. If port 5/6 is used with something
+not SFP, this selector is a noop: something else need to be
+selected.
+
+After the previous series rewriting the MV88E6xxx DT
+bindings to use YAML a "leds" subnode is already valid
+for each port, in my scratch device tree it looks like
+this:
+
+ leds {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@0 {
+ reg = <0>;
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ default-state = "off";
+ linux,default-trigger = "netdev";
+ };
+ led@1 {
+ reg = <1>;
+ color = <LED_COLOR_ID_AMBER>;
+ function = LED_FUNCTION_LAN;
+ default-state = "off";
+ };
+ };
+
+This DT config is not yet configuring everything: when the netdev
+default trigger is assigned the hw acceleration callbacks are
+not called, and there is no way to set the netdev sub-trigger
+type (such as link_1000) from the device tree, such as if you want
+a gigabit link indicator. This has to be done from userspace at
+this point.
+
+We add LED operations to all switches in the 6352 family:
+6172, 6176, 6240 and 6352.
+
+---
+ drivers/net/dsa/mv88e6xxx/Kconfig | 10 +
+ drivers/net/dsa/mv88e6xxx/Makefile | 1 +
+ drivers/net/dsa/mv88e6xxx/chip.c | 38 +-
+ drivers/net/dsa/mv88e6xxx/chip.h | 11 +
+ drivers/net/dsa/mv88e6xxx/leds.c | 839 +++++++++++++++++++++++++++++
+ drivers/net/dsa/mv88e6xxx/port.c | 1 +
+ drivers/net/dsa/mv88e6xxx/port.h | 133 +++++
+ 7 files changed, 1031 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c
+
+--- a/drivers/net/dsa/mv88e6xxx/Kconfig
++++ b/drivers/net/dsa/mv88e6xxx/Kconfig
+@@ -17,3 +17,13 @@ config NET_DSA_MV88E6XXX_PTP
+ help
+ Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch
+ chips that support it.
++
++config NET_DSA_MV88E6XXX_LEDS
++ bool "LED support for Marvell 88E6xxx"
++ default y
++ depends on NET_DSA_MV88E6XXX
++ depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_MV88E6XXX
++ depends on LEDS_TRIGGERS
++ help
++ This enabled support for controlling the LEDs attached to the
++ Marvell 88E6xxx switch chips.
+--- a/drivers/net/dsa/mv88e6xxx/Makefile
++++ b/drivers/net/dsa/mv88e6xxx/Makefile
+@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
+ mv88e6xxx-objs += global2_avb.o
+ mv88e6xxx-objs += global2_scratch.o
+ mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
++mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_LEDS) += leds.o
+ mv88e6xxx-objs += pcs-6185.o
+ mv88e6xxx-objs += pcs-6352.o
+ mv88e6xxx-objs += pcs-639x.o
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -27,6 +27,7 @@
+ #include <linux/of_irq.h>
+ #include <linux/of_mdio.h>
+ #include <linux/platform_data/mv88e6xxx.h>
++#include <linux/property.h>
+ #include <linux/netdevice.h>
+ #include <linux/gpio/consumer.h>
+ #include <linux/phylink.h>
+@@ -3412,14 +3413,43 @@ static int mv88e6xxx_setup_upstream_port
+ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
+ {
+ struct device_node *phy_handle = NULL;
++ struct fwnode_handle *ports_fwnode;
++ struct fwnode_handle *port_fwnode;
+ struct dsa_switch *ds = chip->ds;
++ struct mv88e6xxx_port *p;
+ struct dsa_port *dp;
+ int tx_amp;
+ int err;
+ u16 reg;
++ u32 val;
+
+- chip->ports[port].chip = chip;
+- chip->ports[port].port = port;
++ p = &chip->ports[port];
++ p->chip = chip;
++ p->port = port;
++
++ /* Look up corresponding fwnode if any */
++ ports_fwnode = device_get_named_child_node(chip->dev, "ethernet-ports");
++ if (!ports_fwnode)
++ ports_fwnode = device_get_named_child_node(chip->dev, "ports");
++ if (ports_fwnode) {
++ fwnode_for_each_child_node(ports_fwnode, port_fwnode) {
++ if (fwnode_property_read_u32(port_fwnode, "reg", &val))
++ continue;
++ if (val == port) {
++ p->fwnode = port_fwnode;
++ p->fiber = fwnode_property_present(port_fwnode, "sfp");
++ break;
++ }
++ }
++ } else {
++ dev_dbg(chip->dev, "no ethernet ports node defined for the device\n");
++ }
++
++ if (chip->info->ops->port_setup_leds) {
++ err = chip->info->ops->port_setup_leds(chip, port);
++ if (err && err != -EOPNOTSUPP)
++ return err;
++ }
+
+ err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
+ SPEED_UNFORCED, DUPLEX_UNFORCED,
+@@ -4653,6 +4683,7 @@ static const struct mv88e6xxx_ops mv88e6
+ .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+ .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+ .port_get_cmode = mv88e6352_port_get_cmode,
++ .port_setup_leds = mv88e6xxx_port_setup_leds,
+ .port_setup_message_port = mv88e6xxx_setup_message_port,
+ .stats_snapshot = mv88e6320_g1_stats_snapshot,
+ .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+@@ -4755,6 +4786,7 @@ static const struct mv88e6xxx_ops mv88e6
+ .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+ .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+ .port_get_cmode = mv88e6352_port_get_cmode,
++ .port_setup_leds = mv88e6xxx_port_setup_leds,
+ .port_setup_message_port = mv88e6xxx_setup_message_port,
+ .stats_snapshot = mv88e6320_g1_stats_snapshot,
+ .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+@@ -5030,6 +5062,7 @@ static const struct mv88e6xxx_ops mv88e6
+ .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+ .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+ .port_get_cmode = mv88e6352_port_get_cmode,
++ .port_setup_leds = mv88e6xxx_port_setup_leds,
+ .port_setup_message_port = mv88e6xxx_setup_message_port,
+ .stats_snapshot = mv88e6320_g1_stats_snapshot,
+ .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+@@ -5460,6 +5493,7 @@ static const struct mv88e6xxx_ops mv88e6
+ .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+ .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+ .port_get_cmode = mv88e6352_port_get_cmode,
++ .port_setup_leds = mv88e6xxx_port_setup_leds,
+ .port_setup_message_port = mv88e6xxx_setup_message_port,
+ .stats_snapshot = mv88e6320_g1_stats_snapshot,
+ .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+--- a/drivers/net/dsa/mv88e6xxx/chip.h
++++ b/drivers/net/dsa/mv88e6xxx/chip.h
+@@ -13,7 +13,9 @@
+ #include <linux/irq.h>
+ #include <linux/gpio/consumer.h>
+ #include <linux/kthread.h>
++#include <linux/leds.h>
+ #include <linux/phy.h>
++#include <linux/property.h>
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/timecounter.h>
+ #include <net/dsa.h>
+@@ -276,6 +278,7 @@ struct mv88e6xxx_vlan {
+ struct mv88e6xxx_port {
+ struct mv88e6xxx_chip *chip;
+ int port;
++ struct fwnode_handle *fwnode;
+ struct mv88e6xxx_vlan bridge_pvid;
+ u64 serdes_stats[2];
+ u64 atu_member_violation;
+@@ -290,6 +293,11 @@ struct mv88e6xxx_port {
+ struct devlink_region *region;
+ void *pcs_private;
+
++ /* LED related information */
++ bool fiber;
++ struct led_classdev led0;
++ struct led_classdev led1;
++
+ /* MacAuth Bypass control flag */
+ bool mab;
+ };
+@@ -574,6 +582,9 @@ struct mv88e6xxx_ops {
+ phy_interface_t mode);
+ int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
+
++ /* LED control */
++ int (*port_setup_leds)(struct mv88e6xxx_chip *chip, int port);
++
+ /* Some devices have a per port register indicating what is
+ * the upstream port this port should forward to.
+ */
+--- /dev/null
++++ b/drivers/net/dsa/mv88e6xxx/leds.c
+@@ -0,0 +1,839 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++#include <linux/bitfield.h>
++#include <linux/leds.h>
++#include <linux/property.h>
++
++#include "chip.h"
++#include "global2.h"
++#include "port.h"
++
++/* Offset 0x16: LED control */
++
++static int mv88e6xxx_port_led_write(struct mv88e6xxx_chip *chip, int port, u16 reg)
++{
++ reg |= MV88E6XXX_PORT_LED_CONTROL_UPDATE;
++
++ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, reg);
++}
++
++static int mv88e6xxx_port_led_read(struct mv88e6xxx_chip *chip, int port,
++ u16 ptr, u16 *val)
++{
++ int err;
++
++ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, ptr);
++ if (err)
++ return err;
++
++ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_LED_CONTROL, val);
++ *val &= 0x3ff;
++
++ return err;
++}
++
++static int mv88e6xxx_led_brightness_set(struct mv88e6xxx_port *p, int led,
++ int brightness)
++{
++ u16 reg;
++ int err;
++
++ err = mv88e6xxx_port_led_read(p->chip, p->port,
++ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
++ ®);
++ if (err)
++ return err;
++
++ if (led == 1)
++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
++ else
++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
++
++ if (brightness) {
++ /* Selector 0x0f == Force LED ON */
++ if (led == 1)
++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELF;
++ else
++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELF;
++ } else {
++ /* Selector 0x0e == Force LED OFF */
++ if (led == 1)
++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE;
++ else
++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE;
++ }
++
++ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
++
++ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
++}
++
++static int mv88e6xxx_led0_brightness_set_blocking(struct led_classdev *ldev,
++ enum led_brightness brightness)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
++ int err;
++
++ mv88e6xxx_reg_lock(p->chip);
++ err = mv88e6xxx_led_brightness_set(p, 0, brightness);
++ mv88e6xxx_reg_unlock(p->chip);
++
++ return err;
++}
++
++static int mv88e6xxx_led1_brightness_set_blocking(struct led_classdev *ldev,
++ enum led_brightness brightness)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
++ int err;
++
++ mv88e6xxx_reg_lock(p->chip);
++ err = mv88e6xxx_led_brightness_set(p, 1, brightness);
++ mv88e6xxx_reg_unlock(p->chip);
++
++ return err;
++}
++
++struct mv88e6xxx_led_hwconfig {
++ int led;
++ u8 portmask;
++ unsigned long rules;
++ bool fiber;
++ bool blink_activity;
++ u16 selector;
++};
++
++/* The following is a lookup table to check what rules we can support on a
++ * certain LED given restrictions such as that some rules only work with fiber
++ * (SFP) connections and some blink on activity by default.
++ */
++#define MV88E6XXX_PORTS_0_3 (BIT(0) | BIT(1) | BIT(2) | BIT(3))
++#define MV88E6XXX_PORTS_4_5 (BIT(4) | BIT(5))
++#define MV88E6XXX_PORT_4 BIT(4)
++#define MV88E6XXX_PORT_5 BIT(5)
++
++/* Entries are listed in selector order.
++ *
++ * These configurations vary across different switch families, list
++ * different tables per-family here.
++ */
++static const struct mv88e6xxx_led_hwconfig mv88e6352_led_hwconfigs[] = {
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORT_4,
++ .rules = BIT(TRIGGER_NETDEV_LINK),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORT_5,
++ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_4_5,
++ .rules = BIT(TRIGGER_NETDEV_LINK_100),
++ .blink_activity = true,
++ .fiber = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_4_5,
++ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
++ .blink_activity = true,
++ .fiber = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_4_5,
++ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
++ .blink_activity = true,
++ .fiber = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_4_5,
++ .rules = BIT(TRIGGER_NETDEV_LINK_100),
++ .blink_activity = true,
++ .fiber = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_4_5,
++ .rules = BIT(TRIGGER_NETDEV_LINK),
++ .fiber = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORT_4,
++ .rules = BIT(TRIGGER_NETDEV_LINK),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORT_5,
++ .rules = BIT(TRIGGER_NETDEV_LINK),
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORT_4,
++ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORT_5,
++ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK),
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORT_5,
++ .rules = BIT(TRIGGER_NETDEV_LINK),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_10),
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_100),
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_10),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELA,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_100),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELA,
++ },
++ {
++ .led = 0,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELB,
++ },
++ {
++ .led = 1,
++ .portmask = MV88E6XXX_PORTS_0_3,
++ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
++ .blink_activity = true,
++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELB,
++ },
++};
++
++/* mv88e6xxx_led_match_selector() - look up the appropriate LED mode selector
++ * @p: port state container
++ * @led: LED number, 0 or 1
++ * @blink_activity: blink the LED (usually blink on indicated activity)
++ * @fiber: the link is connected to fiber such as SFP
++ * @rules: LED status flags from the LED classdev core
++ * @selector: fill in the selector in this parameter with an OR operation
++ */
++static int mv88e6xxx_led_match_selector(struct mv88e6xxx_port *p, int led, bool blink_activity,
++ bool fiber, unsigned long rules, u16 *selector)
++{
++ const struct mv88e6xxx_led_hwconfig *conf;
++ int i;
++
++ /* No rules means we turn the LED off */
++ if (!rules) {
++ if (led == 1)
++ *selector |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE;
++ else
++ *selector |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE;
++ return 0;
++ }
++
++ /* TODO: these rules are for MV88E6352, when adding other families,
++ * think about making sure you select the table that match the
++ * specific switch family.
++ */
++ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
++ conf = &mv88e6352_led_hwconfigs[i];
++
++ if (conf->led != led)
++ continue;
++
++ if (!(conf->portmask & BIT(p->port)))
++ continue;
++
++ if (conf->blink_activity != blink_activity)
++ continue;
++
++ if (conf->fiber != fiber)
++ continue;
++
++ if (conf->rules == rules) {
++ dev_dbg(p->chip->dev, "port%d LED %d set selector %04x for rules %08lx\n",
++ p->port, led, conf->selector, rules);
++ *selector |= conf->selector;
++ return 0;
++ }
++ }
++
++ return -EOPNOTSUPP;
++}
++
++/* mv88e6xxx_led_match_selector() - find Linux netdev rules from a selector value
++ * @p: port state container
++ * @selector: the selector value from the LED actity register
++ * @led: LED number, 0 or 1
++ * @rules: Linux netdev activity rules found from selector
++ */
++static int
++mv88e6xxx_led_match_rule(struct mv88e6xxx_port *p, u16 selector, int led, unsigned long *rules)
++{
++ const struct mv88e6xxx_led_hwconfig *conf;
++ int i;
++
++ /* Find the selector in the table, we just look for the right selector
++ * and ignore if the activity has special properties such as blinking
++ * or is fiber-only.
++ */
++ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
++ conf = &mv88e6352_led_hwconfigs[i];
++
++ if (conf->led != led)
++ continue;
++
++ if (!(conf->portmask & BIT(p->port)))
++ continue;
++
++ if (conf->selector == selector) {
++ dev_dbg(p->chip->dev, "port%d LED %d has selector %04x, rules %08lx\n",
++ p->port, led, selector, conf->rules);
++ *rules = conf->rules;
++ return 0;
++ }
++ }
++
++ return -EINVAL;
++}
++
++/* mv88e6xxx_led_get_selector() - get the appropriate LED mode selector
++ * @p: port state container
++ * @led: LED number, 0 or 1
++ * @fiber: the link is connected to fiber such as SFP
++ * @rules: LED status flags from the LED classdev core
++ * @selector: fill in the selector in this parameter with an OR operation
++ */
++static int mv88e6xxx_led_get_selector(struct mv88e6xxx_port *p, int led,
++ bool fiber, unsigned long rules, u16 *selector)
++{
++ int err;
++
++ /* What happens here is that we first try to locate a trigger with solid
++ * indicator (such as LED is on for a 1000 link) else we try a second
++ * sweep to find something suitable with a trigger that will blink on
++ * activity.
++ */
++ err = mv88e6xxx_led_match_selector(p, led, false, fiber, rules, selector);
++ if (err)
++ return mv88e6xxx_led_match_selector(p, led, true, fiber, rules, selector);
++
++ return 0;
++}
++
++/* Sets up the hardware blinking period */
++static int mv88e6xxx_led_set_blinking_period(struct mv88e6xxx_port *p, int led,
++ unsigned long delay_on, unsigned long delay_off)
++{
++ unsigned long period;
++ u16 reg;
++
++ period = delay_on + delay_off;
++
++ reg = 0;
++
++ switch (period) {
++ case 21:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS;
++ break;
++ case 42:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS;
++ break;
++ case 84:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS;
++ break;
++ case 168:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS;
++ break;
++ case 336:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS;
++ break;
++ case 672:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS;
++ break;
++ default:
++ /* Fall back to software blinking */
++ return -EINVAL;
++ }
++
++ /* This is essentially PWM duty cycle: how long time of the period
++ * will the LED be on. Zero isn't great in most cases.
++ */
++ switch (delay_on) {
++ case 0:
++ /* This is usually pretty useless and will make the LED look OFF */
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE;
++ break;
++ case 21:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS;
++ break;
++ case 42:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS;
++ break;
++ case 84:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS;
++ break;
++ case 168:
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS;
++ break;
++ default:
++ /* Just use something non-zero */
++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS;
++ break;
++ }
++
++ /* Set up blink rate */
++ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK;
++
++ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
++}
++
++static int mv88e6xxx_led_blink_set(struct mv88e6xxx_port *p, int led,
++ unsigned long *delay_on, unsigned long *delay_off)
++{
++ u16 reg;
++ int err;
++
++ /* Choose a sensible default 336 ms (~3 Hz) */
++ if ((*delay_on == 0) && (*delay_off == 0)) {
++ *delay_on = 168;
++ *delay_off = 168;
++ }
++
++ /* No off delay is just on */
++ if (*delay_off == 0)
++ return mv88e6xxx_led_brightness_set(p, led, 1);
++
++ err = mv88e6xxx_led_set_blinking_period(p, led, *delay_on, *delay_off);
++ if (err)
++ return err;
++
++ err = mv88e6xxx_port_led_read(p->chip, p->port,
++ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
++ ®);
++ if (err)
++ return err;
++
++ if (led == 1)
++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
++ else
++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
++
++ /* This will select the forced blinking status */
++ if (led == 1)
++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELD;
++ else
++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELD;
++
++ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
++
++ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
++}
++
++static int mv88e6xxx_led0_blink_set(struct led_classdev *ldev,
++ unsigned long *delay_on,
++ unsigned long *delay_off)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
++ int err;
++
++ mv88e6xxx_reg_lock(p->chip);
++ err = mv88e6xxx_led_blink_set(p, 0, delay_on, delay_off);
++ mv88e6xxx_reg_unlock(p->chip);
++
++ return err;
++}
++
++static int mv88e6xxx_led1_blink_set(struct led_classdev *ldev,
++ unsigned long *delay_on,
++ unsigned long *delay_off)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
++ int err;
++
++ mv88e6xxx_reg_lock(p->chip);
++ err = mv88e6xxx_led_blink_set(p, 1, delay_on, delay_off);
++ mv88e6xxx_reg_unlock(p->chip);
++
++ return err;
++}
++
++static int
++mv88e6xxx_led0_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
++ u16 selector = 0;
++
++ return mv88e6xxx_led_get_selector(p, 0, p->fiber, rules, &selector);
++}
++
++static int
++mv88e6xxx_led1_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
++ u16 selector = 0;
++
++ return mv88e6xxx_led_get_selector(p, 1, p->fiber, rules, &selector);
++}
++
++static int mv88e6xxx_led_hw_control_set(struct mv88e6xxx_port *p,
++ int led, unsigned long rules)
++{
++ u16 reg;
++ int err;
++
++ err = mv88e6xxx_port_led_read(p->chip, p->port,
++ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
++ ®);
++ if (err)
++ return err;
++
++ if (led == 1)
++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
++ else
++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
++
++ err = mv88e6xxx_led_get_selector(p, led, p->fiber, rules, ®);
++ if (err)
++ return err;
++
++ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
++
++ if (led == 0)
++ dev_dbg(p->chip->dev, "LED 0 hw control on port %d trigger selector 0x%02x\n",
++ p->port,
++ (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK));
++ else
++ dev_dbg(p->chip->dev, "LED 1 hw control on port %d trigger selector 0x%02x\n",
++ p->port,
++ (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK) >> 4);
++
++ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
++}
++
++static int
++mv88e6xxx_led_hw_control_get(struct mv88e6xxx_port *p, int led, unsigned long *rules)
++{
++ u16 val;
++ int err;
++
++ mv88e6xxx_reg_lock(p->chip);
++ err = mv88e6xxx_port_led_read(p->chip, p->port,
++ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, &val);
++ mv88e6xxx_reg_unlock(p->chip);
++ if (err)
++ return err;
++
++ /* Mask out the selector bits for this port */
++ if (led == 1) {
++ val &= MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
++ /* It's forced blinking/OFF/ON */
++ if (val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELD ||
++ val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELE ||
++ val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELF) {
++ *rules = 0;
++ return 0;
++ }
++ } else {
++ val &= MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
++ /* It's forced blinking/OFF/ON */
++ if (val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELD ||
++ val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELE ||
++ val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELF) {
++ *rules = 0;
++ return 0;
++ }
++ }
++
++ err = mv88e6xxx_led_match_rule(p, val, led, rules);
++ if (!err)
++ return 0;
++
++ dev_dbg(p->chip->dev, "couldn't find matching selector for %04x\n", val);
++ *rules = 0;
++ return 0;
++}
++
++static int
++mv88e6xxx_led0_hw_control_set(struct led_classdev *ldev, unsigned long rules)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
++ int err;
++
++ mv88e6xxx_reg_lock(p->chip);
++ err = mv88e6xxx_led_hw_control_set(p, 0, rules);
++ mv88e6xxx_reg_unlock(p->chip);
++
++ return err;
++}
++
++static int
++mv88e6xxx_led1_hw_control_set(struct led_classdev *ldev, unsigned long rules)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
++ int err;
++
++ mv88e6xxx_reg_lock(p->chip);
++ err = mv88e6xxx_led_hw_control_set(p, 1, rules);
++ mv88e6xxx_reg_unlock(p->chip);
++
++ return err;
++}
++
++static int
++mv88e6xxx_led0_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
++
++ return mv88e6xxx_led_hw_control_get(p, 0, rules);
++}
++
++static int
++mv88e6xxx_led1_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
++
++ return mv88e6xxx_led_hw_control_get(p, 1, rules);
++}
++
++static struct device *mv88e6xxx_led_hw_control_get_device(struct mv88e6xxx_port *p)
++{
++ struct dsa_port *dp;
++
++ dp = dsa_to_port(p->chip->ds, p->port);
++ if (!dp)
++ return NULL;
++ if (dp->user)
++ return &dp->user->dev;
++ return NULL;
++}
++
++static struct device *
++mv88e6xxx_led0_hw_control_get_device(struct led_classdev *ldev)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
++
++ return mv88e6xxx_led_hw_control_get_device(p);
++}
++
++static struct device *
++mv88e6xxx_led1_hw_control_get_device(struct led_classdev *ldev)
++{
++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
++
++ return mv88e6xxx_led_hw_control_get_device(p);
++}
++
++int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port)
++{
++ struct fwnode_handle *led = NULL, *leds = NULL;
++ struct led_init_data init_data = { };
++ enum led_default_state state;
++ struct mv88e6xxx_port *p;
++ struct led_classdev *l;
++ struct device *dev;
++ u32 led_num;
++ int ret;
++
++ /* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */
++ if (port > 5)
++ return -EOPNOTSUPP;
++
++ p = &chip->ports[port];
++ if (!p->fwnode)
++ return 0;
++
++ dev = chip->dev;
++
++ leds = fwnode_get_named_child_node(p->fwnode, "leds");
++ if (!leds) {
++ dev_dbg(dev, "No Leds node specified in device tree for port %d!\n",
++ port);
++ return 0;
++ }
++
++ fwnode_for_each_child_node(leds, led) {
++ /* Reg represent the led number of the port, max 2
++ * LEDs can be connected to each port, in some designs
++ * only one LED is connected.
++ */
++ if (fwnode_property_read_u32(led, "reg", &led_num))
++ continue;
++ if (led_num > 1) {
++ dev_err(dev, "invalid LED specified port %d\n", port);
++ return -EINVAL;
++ }
++
++ if (led_num == 0)
++ l = &p->led0;
++ else
++ l = &p->led1;
++
++ state = led_init_default_state_get(led);
++ switch (state) {
++ case LEDS_DEFSTATE_ON:
++ l->brightness = 1;
++ mv88e6xxx_led_brightness_set(p, led_num, 1);
++ break;
++ case LEDS_DEFSTATE_KEEP:
++ break;
++ default:
++ l->brightness = 0;
++ mv88e6xxx_led_brightness_set(p, led_num, 0);
++ }
++
++ l->max_brightness = 1;
++ if (led_num == 0) {
++ l->brightness_set_blocking = mv88e6xxx_led0_brightness_set_blocking;
++ l->blink_set = mv88e6xxx_led0_blink_set;
++ l->hw_control_is_supported = mv88e6xxx_led0_hw_control_is_supported;
++ l->hw_control_set = mv88e6xxx_led0_hw_control_set;
++ l->hw_control_get = mv88e6xxx_led0_hw_control_get;
++ l->hw_control_get_device = mv88e6xxx_led0_hw_control_get_device;
++ } else {
++ l->brightness_set_blocking = mv88e6xxx_led1_brightness_set_blocking;
++ l->blink_set = mv88e6xxx_led1_blink_set;
++ l->hw_control_is_supported = mv88e6xxx_led1_hw_control_is_supported;
++ l->hw_control_set = mv88e6xxx_led1_hw_control_set;
++ l->hw_control_get = mv88e6xxx_led1_hw_control_get;
++ l->hw_control_get_device = mv88e6xxx_led1_hw_control_get_device;
++ }
++ l->hw_control_trigger = "netdev";
++
++ init_data.default_label = ":port";
++ init_data.fwnode = led;
++ init_data.devname_mandatory = true;
++ init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name,
++ port, led_num);
++ if (!init_data.devicename)
++ return -ENOMEM;
++
++ ret = devm_led_classdev_register_ext(dev, l, &init_data);
++ kfree(init_data.devicename);
++
++ if (ret) {
++ dev_err(dev, "Failed to init LED %d for port %d", led_num, port);
++ return ret;
++ }
++ }
++
++ return 0;
++}
+--- a/drivers/net/dsa/mv88e6xxx/port.c
++++ b/drivers/net/dsa/mv88e6xxx/port.c
+@@ -12,6 +12,7 @@
+ #include <linux/if_bridge.h>
+ #include <linux/phy.h>
+ #include <linux/phylink.h>
++#include <linux/property.h>
+
+ #include "chip.h"
+ #include "global2.h"
+--- a/drivers/net/dsa/mv88e6xxx/port.h
++++ b/drivers/net/dsa/mv88e6xxx/port.h
+@@ -309,6 +309,130 @@
+ /* Offset 0x13: OutFiltered Counter */
+ #define MV88E6XXX_PORT_OUT_FILTERED 0x13
+
++/* Offset 0x16: LED Control */
++#define MV88E6XXX_PORT_LED_CONTROL 0x16
++#define MV88E6XXX_PORT_LED_CONTROL_UPDATE BIT(15)
++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_MASK GENMASK(14, 12)
++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL (0x00 << 12) /* Control for LED 0 and 1 */
++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK (0x06 << 12) /* Stetch and Blink Rate */
++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_CNTL_SPECIAL (0x07 << 12) /* Control for the Port's Special LED */
++#define MV88E6XXX_PORT_LED_CONTROL_DATA_MASK GENMASK(10, 0)
++/* Selection masks valid for either port 1,2,3,4 or 5 */
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK GENMASK(3, 0)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK GENMASK(7, 4)
++/* Selection control for LED 0 and 1, ports 5 and 6 only has LED 0
++ * Bits Function
++ * 0..3 LED 0 control selector on ports 1-5
++ * 4..7 LED 1 control selector on ports 1-4 on port 5 this controls LED 0 of port 6
++ *
++ * Sel Port LED Function for the 6352 family:
++ * 0 1-4 0 Link/Act/Speed by Blink Rate (off=no link, on=link, blink=activity, blink speed=link speed)
++ * 1-4 1 Port 2's Special LED
++ * 5-6 0 Port 5 Link/Act (off=no link, on=link, blink=activity)
++ * 5-6 1 Port 6 Link/Act (off=no link, on=link 1000, blink=activity)
++ * 1 1-4 0 100/1000 Link/Act (off=no link, on=100 or 1000 link, blink=activity)
++ * 1-4 1 10/100 Link Act (off=no link, on=10 or 100 link, blink=activity)
++ * 5-6 0 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
++ * 5-6 1 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
++ * 2 1-4 0 1000 Link/Act (off=no link, on=link 1000, blink=activity)
++ * 1-4 1 10/100 Link/Act (off=no link, on=10 or 100 link, blink=activity)
++ * 5-6 0 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
++ * 5-6 1 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
++ * 3 1-4 0 Link/Act (off=no link, on=link, blink=activity)
++ * 1-4 1 1000 Link (off=no link, on=1000 link)
++ * 5-6 0 Port 0's Special LED
++ * 5-6 1 Fiber Link (off=no link, on=link)
++ * 4 1-4 0 Port 0's Special LED
++ * 1-4 1 Port 1's Special LED
++ * 5-6 0 Port 1's Special LED
++ * 5-6 1 Port 5 Link/Act (off=no link, on=link, blink=activity)
++ * 5 1-4 0 Reserved
++ * 1-4 1 Reserved
++ * 5-6 0 Port 2's Special LED
++ * 5-6 1 Port 6 Link (off=no link, on=link)
++ * 6 1-4 0 Duplex/Collision (off=half-duplex,on=full-duplex,blink=collision)
++ * 1-4 1 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
++ * 5-6 0 Port 5 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
++ * 5-6 1 Port 6 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
++ * 7 1-4 0 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
++ * 1-4 1 10/1000 Link (off=no link, on=10 or 1000 link)
++ * 5-6 0 Port 5 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed)
++ * 5-6 1 Port 6 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed)
++ * 8 1-4 0 Link (off=no link, on=link)
++ * 1-4 1 Activity (off=no link, blink on=activity)
++ * 5-6 0 Port 6 Link/Act (off=no link, on=link, blink=activity)
++ * 5-6 1 Port 0's Special LED
++ * 9 1-4 0 10 Link (off=no link, on=10 link)
++ * 1-4 1 100 Link (off=no link, on=100 link)
++ * 5-6 0 Reserved
++ * 5-6 1 Port 1's Special LED
++ * a 1-4 0 10 Link/Act (off=no link, on=10 link, blink=activity)
++ * 1-4 1 100 Link/Act (off=no link, on=100 link, blink=activity)
++ * 5-6 0 Reserved
++ * 5-6 1 Port 2's Special LED
++ * b 1-4 0 100/1000 Link (off=no link, on=100 or 1000 link)
++ * 1-4 1 10/100 Link (off=no link, on=100 link, blink=activity)
++ * 5-6 0 Reserved
++ * 5-6 1 Reserved
++ * c * * PTP Act (blink on=PTP activity)
++ * d * * Force Blink
++ * e * * Force Off
++ * f * * Force On
++ */
++/* Select LED0 output */
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0 0x0
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1 0x1
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2 0x2
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3 0x3
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL4 0x4
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL5 0x5
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6 0x6
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7 0x7
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8 0x8
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9 0x9
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELA 0xa
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELB 0xb
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELC 0xc
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELD 0xd
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELE 0xe
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELF 0xf
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0 (0x0 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1 (0x1 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2 (0x2 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3 (0x3 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4 (0x4 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5 (0x5 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6 (0x6 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7 (0x7 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8 (0x8 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9 (0x9 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELA (0xa << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELB (0xb << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELC (0xc << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELD (0xd << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELE (0xe << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELF (0xf << 4)
++/* Stretch and Blink Rate Control (Index 0x06 of LED Control) */
++/* Pulse Stretch Selection for all LED's on this port */
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE (0 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS (1 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS (2 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS (3 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS (4 << 4)
++/* Blink Rate Selection for all LEDs on this port */
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS 0
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS 1
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS 2
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS 3
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS 4
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS 5
++ /* Control for Special LED (Index 0x7 of LED Control on Port0) */
++#define MV88E6XXX_PORT_LED_CONTROL_0x07_P0_LAN_LINKACT_SHIFT 0 /* bits 6:0 LAN Link Activity LED */
++/* Control for Special LED (Index 0x7 of LED Control on Port 1) */
++#define MV88E6XXX_PORT_LED_CONTROL_0x07_P1_WAN_LINKACT_SHIFT 0 /* bits 6:0 WAN Link Activity LED */
++/* Control for Special LED (Index 0x7 of LED Control on Port 2) */
++#define MV88E6XXX_PORT_LED_CONTROL_0x07_P2_PTP_ACT 0 /* bits 6:0 PTP Activity */
++
+ /* Offset 0x18: IEEE Priority Mapping Table */
+ #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18
+ #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000
+@@ -457,6 +581,15 @@ int mv88e6393x_port_set_cmode(struct mv8
+ phy_interface_t mode);
+ int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
+ int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
++#ifdef CONFIG_NET_DSA_MV88E6XXX_LEDS
++int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port);
++#else
++static inline int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip,
++ int port)
++{
++ return 0;
++}
++#endif
+ int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
+ bool drop_untagged);
+ int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map);
+++ /dev/null
-From 952d7325362ffbefa6ce5619fb4e53c2159ec7a7 Mon Sep 17 00:00:00 2001
-Date: Mon, 17 Feb 2025 17:40:21 +0800
-Subject: [PATCH] net: ethernet: mediatek: add EEE support
-
-Add EEE support to MediaTek SoC Ethernet. The register fields are
-similar to the ones in MT7531, except that the LPI threshold is in
-milliseconds.
-
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 64 +++++++++++++++++++++
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 11 ++++
- 2 files changed, 75 insertions(+)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -782,6 +782,7 @@ static void mtk_mac_link_up(struct phyli
-
- mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
- mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 |
-+ MAC_MCR_EEE100M | MAC_MCR_EEE1G |
- MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC |
- MAC_MCR_FORCE_RX_FC);
-
-@@ -807,6 +808,15 @@ static void mtk_mac_link_up(struct phyli
- if (rx_pause)
- mcr |= MAC_MCR_FORCE_RX_FC;
-
-+ if (mode == MLO_AN_PHY && phy && mac->tx_lpi_enabled && phy_init_eee(phy, false) >= 0) {
-+ mcr |= MAC_MCR_EEE100M | MAC_MCR_EEE1G;
-+ mtk_w32(mac->hw,
-+ FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) |
-+ FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36) |
-+ FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, mac->txidle_thd_ms),
-+ MTK_MAC_EEECR(mac->id));
-+ }
-+
- mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK;
- mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
- }
-@@ -4506,6 +4516,61 @@ static int mtk_set_pauseparam(struct net
- return phylink_ethtool_set_pauseparam(mac->phylink, pause);
- }
-
-+static int mtk_get_eee(struct net_device *dev, struct ethtool_keee *eee)
-+{
-+ struct mtk_mac *mac = netdev_priv(dev);
-+ u32 reg;
-+ int ret;
-+
-+ ret = phylink_ethtool_get_eee(mac->phylink, eee);
-+ if (ret)
-+ return ret;
-+
-+ reg = mtk_r32(mac->hw, MTK_MAC_EEECR(mac->id));
-+ eee->tx_lpi_enabled = mac->tx_lpi_enabled;
-+ eee->tx_lpi_timer = FIELD_GET(MAC_EEE_LPI_TXIDLE_THD, reg) * 1000;
-+
-+ return 0;
-+}
-+
-+static int mtk_set_eee(struct net_device *dev, struct ethtool_keee *eee)
-+{
-+ struct mtk_mac *mac = netdev_priv(dev);
-+ u32 txidle_thd_ms, reg;
-+ int ret;
-+
-+ /* Tx idle timer in ms */
-+ txidle_thd_ms = DIV_ROUND_UP(eee->tx_lpi_timer, 1000);
-+ if (!FIELD_FIT(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms))
-+ return -EINVAL;
-+
-+ reg = FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms);
-+
-+ /* PHY Wake-up time, this field does not have a reset value, so use the
-+ * reset value from MT7531 (36us for 100BaseT and 17us for 1000BaseT).
-+ */
-+ reg |= FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) |
-+ FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36);
-+
-+ if (!txidle_thd_ms)
-+ /* Force LPI Mode without a delay */
-+ reg |= MAC_EEE_LPI_MODE;
-+
-+ ret = phylink_ethtool_set_eee(mac->phylink, eee);
-+ if (ret)
-+ return ret;
-+
-+ mac->tx_lpi_enabled = eee->tx_lpi_enabled;
-+ mac->txidle_thd_ms = txidle_thd_ms;
-+ mtk_w32(mac->hw, reg, MTK_MAC_EEECR(mac->id));
-+ if (eee->eee_enabled && eee->eee_active && eee->tx_lpi_enabled)
-+ mtk_m32(mac->hw, 0, MAC_MCR_EEE100M | MAC_MCR_EEE1G, MTK_MAC_MCR(mac->id));
-+ else
-+ mtk_m32(mac->hw, MAC_MCR_EEE100M | MAC_MCR_EEE1G, 0, MTK_MAC_MCR(mac->id));
-+
-+ return 0;
-+}
-+
- static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
- struct net_device *sb_dev)
- {
-@@ -4538,6 +4603,8 @@ static const struct ethtool_ops mtk_etht
- .set_pauseparam = mtk_set_pauseparam,
- .get_rxnfc = mtk_get_rxnfc,
- .set_rxnfc = mtk_set_rxnfc,
-+ .get_eee = mtk_get_eee,
-+ .set_eee = mtk_set_eee,
- };
-
- static const struct net_device_ops mtk_netdev_ops = {
-@@ -4598,6 +4665,8 @@ static int mtk_add_mac(struct mtk_eth *e
- }
- mac = netdev_priv(eth->netdev[id]);
- eth->mac[id] = mac;
-+ mac->tx_lpi_enabled = true;
-+ mac->txidle_thd_ms = 1;
- mac->id = id;
- mac->hw = eth;
- mac->of_node = np;
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -461,6 +461,8 @@
- #define MAC_MCR_RX_FIFO_CLR_DIS BIT(12)
- #define MAC_MCR_BACKOFF_EN BIT(9)
- #define MAC_MCR_BACKPR_EN BIT(8)
-+#define MAC_MCR_EEE1G BIT(7)
-+#define MAC_MCR_EEE100M BIT(6)
- #define MAC_MCR_FORCE_RX_FC BIT(5)
- #define MAC_MCR_FORCE_TX_FC BIT(4)
- #define MAC_MCR_SPEED_1000 BIT(3)
-@@ -469,6 +471,15 @@
- #define MAC_MCR_FORCE_LINK BIT(0)
- #define MAC_MCR_FORCE_LINK_DOWN (MAC_MCR_FORCE_MODE)
-
-+/* Mac EEE control registers */
-+#define MTK_MAC_EEECR(x) (0x10104 + (x * 0x100))
-+#define MAC_EEE_WAKEUP_TIME_1000 GENMASK(31, 24)
-+#define MAC_EEE_WAKEUP_TIME_100 GENMASK(23, 16)
-+#define MAC_EEE_LPI_TXIDLE_THD GENMASK(15, 8)
-+#define MAC_EEE_CKG_TXIDLE BIT(3)
-+#define MAC_EEE_CKG_RXLPI BIT(2)
-+#define MAC_EEE_LPI_MODE BIT(0)
-+
- /* Mac status registers */
- #define MTK_MAC_MSR(x) (0x10108 + (x * 0x100))
- #define MAC_MSR_EEE1G BIT(7)
-@@ -1316,6 +1327,8 @@ struct mtk_mac {
- int id;
- phy_interface_t interface;
- u8 ppe_idx;
-+ bool tx_lpi_enabled;
-+ u8 txidle_thd_ms;
- int speed;
- struct device_node *of_node;
- struct phylink *phylink;
+++ /dev/null
-From 8cae5a0d91fea01d90ce7c1827e26934a22ca2fa Mon Sep 17 00:00:00 2001
-Date: Wed, 5 Mar 2025 11:53:56 +0000
-Subject: [PATCH] igc: enable HW vlan tag insertion/stripping by default
-
-This is enabled by default in other Intel drivers I've checked (e1000, e1000e,
-iavf, igb and ice). Fixes an out-of-the-box performance issue when running
-OpenWrt on typical mini-PCs with igc-supported Ethernet controllers and 802.1Q
-VLAN configurations, as ethtool isn't part of the default packages and sane
-defaults are expected.
-
-In my specific case, with an Intel N100-based machine with four I226-V Ethernet
-controllers, my upload performance increased from under 30 Mb/s to the expected
-~1 Gb/s.
-
----
- drivers/net/ethernet/intel/igc/igc_main.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/net/ethernet/intel/igc/igc_main.c
-+++ b/drivers/net/ethernet/intel/igc/igc_main.c
-@@ -7066,6 +7066,9 @@ static int igc_probe(struct pci_dev *pde
- netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
- NETDEV_XDP_ACT_XSK_ZEROCOPY;
-
-+ /* enable HW vlan tag insertion/stripping by default */
-+ netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
-+
- /* MTU range: 68 - 9216 */
- netdev->min_mtu = ETH_MIN_MTU;
- netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE;
+++ /dev/null
-From 77f5bb150132bbbcd6bc37ffdc80c9e140e373a4 Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Apr 2025 15:27:41 -0700
-Subject: [PATCH] power: supply: sysfs: Remove duplicate NUL termination
-
-GCC 15's new -Wunterminated-string-initialization notices that one of
-the sysfs attr strings would lack the implicit trailing NUL byte during
-initialization:
-
-drivers/power/supply/power_supply_sysfs.c:183:57: warning: initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute (32 chars into 31 available) [-Wunterminated-string-initialization]
- 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
- | ^
-drivers/power/supply/power_supply_sysfs.c:36:23: note: in definition of macro '_POWER_SUPPLY_ATTR'
- 36 | .attr_name = #_name "\0", \
- | ^~~~~
-drivers/power/supply/power_supply_sysfs.c:183:9: note: in expansion of macro 'POWER_SUPPLY_ATTR'
- 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
- | ^~~~~~~~~~~~~~~~~
-
-However, the macro used was explicitly adding a trailing NUL byte (which
-is not needed). Remove this to avoid the GCC warning. No binary
-differences are seen after this change (there was always run for a NUL
-byte, it's just that the _second_ NUL byte was getting truncated).
-
-
---- a/drivers/power/supply/power_supply_sysfs.c
-+++ b/drivers/power/supply/power_supply_sysfs.c
-@@ -33,7 +33,7 @@ struct power_supply_attr {
- [POWER_SUPPLY_PROP_ ## _name] = \
- { \
- .prop_name = #_name, \
-- .attr_name = #_name "\0", \
-+ .attr_name = #_name, \
- .text_values = _text, \
- .text_values_len = _len, \
- }
--- /dev/null
+From b0fa00fe38f673c986633c11087274deeb7ce7b0 Mon Sep 17 00:00:00 2001
+Date: Tue, 7 Jan 2025 21:16:20 +0100
+Subject: [PATCH] gpio: regmap: Use generic request/free ops
+
+Set the gpiochip request and free ops to the generic implementations.
+This way a user can provide a gpio-ranges property defined for a pinmux,
+easing muxing of gpio functions. Provided that the pin controller
+implementents the pinmux op .gpio_request_enable(), pins will
+automatically be muxed to their GPIO function when requested.
+
+---
+ drivers/gpio/gpio-regmap.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/gpio/gpio-regmap.c
++++ b/drivers/gpio/gpio-regmap.c
+@@ -262,6 +262,8 @@ struct gpio_regmap *gpio_regmap_register
+ chip->label = config->label ?: dev_name(config->parent);
+ chip->can_sleep = regmap_might_sleep(config->regmap);
+
++ chip->request = gpiochip_generic_request;
++ chip->free = gpiochip_generic_free;
+ chip->get = gpio_regmap_get;
+ if (gpio->reg_set_base && gpio->reg_clr_base)
+ chip->set = gpio_regmap_set_with_clear;
--- /dev/null
+From 77f5bb150132bbbcd6bc37ffdc80c9e140e373a4 Mon Sep 17 00:00:00 2001
+Date: Wed, 16 Apr 2025 15:27:41 -0700
+Subject: [PATCH] power: supply: sysfs: Remove duplicate NUL termination
+
+GCC 15's new -Wunterminated-string-initialization notices that one of
+the sysfs attr strings would lack the implicit trailing NUL byte during
+initialization:
+
+drivers/power/supply/power_supply_sysfs.c:183:57: warning: initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute (32 chars into 31 available) [-Wunterminated-string-initialization]
+ 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
+ | ^
+drivers/power/supply/power_supply_sysfs.c:36:23: note: in definition of macro '_POWER_SUPPLY_ATTR'
+ 36 | .attr_name = #_name "\0", \
+ | ^~~~~
+drivers/power/supply/power_supply_sysfs.c:183:9: note: in expansion of macro 'POWER_SUPPLY_ATTR'
+ 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
+ | ^~~~~~~~~~~~~~~~~
+
+However, the macro used was explicitly adding a trailing NUL byte (which
+is not needed). Remove this to avoid the GCC warning. No binary
+differences are seen after this change (there was always run for a NUL
+byte, it's just that the _second_ NUL byte was getting truncated).
+
+
+--- a/drivers/power/supply/power_supply_sysfs.c
++++ b/drivers/power/supply/power_supply_sysfs.c
+@@ -33,7 +33,7 @@ struct power_supply_attr {
+ [POWER_SUPPLY_PROP_ ## _name] = \
+ { \
+ .prop_name = #_name, \
+- .attr_name = #_name "\0", \
++ .attr_name = #_name, \
+ .text_values = _text, \
+ .text_values_len = _len, \
+ }
+++ /dev/null
-From a2e1ba275eae96a8171deb19e9c7c2f5978fee7b Mon Sep 17 00:00:00 2001
-Date: Fri, 4 Oct 2024 17:18:16 +0100
-Subject: [PATCH] net: phy: aquantia: allow forcing order of MDI pairs
-
-Despite supporting Auto MDI-X, it looks like Aquantia only supports
-swapping pair (1,2) with pair (3,6) like it used to be for MDI-X on
-100MBit/s networks.
-
-When all 4 pairs are in use (for 1000MBit/s or faster) the link does not
-come up with pair order is not configured correctly, either using
-MDI_CFG pin or using the "PMA Receive Reserved Vendor Provisioning 1"
-register.
-
-Normally, the order of MDI pairs being either ABCD or DCBA is configured
-by pulling the MDI_CFG pin.
-
-However, some hardware designs require overriding the value configured
-by that bootstrap pin. The PHY allows doing that by setting a bit in
-"PMA Receive Reserved Vendor Provisioning 1" register which allows
-ignoring the state of the MDI_CFG pin and another bit configuring
-whether the order of MDI pairs should be normal (ABCD) or reverse
-(DCBA). Pair polarity is not affected and remains identical in both
-settings.
-
-Introduce property "marvell,mdi-cfg-order" which allows forcing either
-normal or reverse order of the MDI pairs from DT.
-
-If the property isn't present, the behavior is unchanged and MDI pair
-order configuration is untouched (ie. either the result of MDI_CFG pin
-pull-up/pull-down, or pair order override already configured by the
-bootloader before Linux is started).
-
-Forcing normal pair order is required on the Adtran SDG-8733A Wi-Fi 7
-residential gateway.
-
-Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org
----
- drivers/net/phy/aquantia/aquantia_main.c | 33 ++++++++++++++++++++++++
- 1 file changed, 33 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -11,6 +11,7 @@
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/bitfield.h>
-+#include <linux/of.h>
- #include <linux/phy.h>
-
- #include "aquantia.h"
-@@ -71,6 +72,11 @@
- #define MDIO_AN_TX_VEND_INT_MASK2 0xd401
- #define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0)
-
-+#define PMAPMD_RSVD_VEND_PROV 0xe400
-+#define PMAPMD_RSVD_VEND_PROV_MDI_CONF GENMASK(1, 0)
-+#define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE BIT(0)
-+#define PMAPMD_RSVD_VEND_PROV_MDI_FORCE BIT(1)
-+
- #define MDIO_AN_RX_LP_STAT1 0xe820
- #define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15)
- #define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14)
-@@ -485,6 +491,29 @@ static void aqr107_chip_info(struct phy_
- fw_major, fw_minor, build_id, prov_id);
- }
-
-+static int aqr107_config_mdi(struct phy_device *phydev)
-+{
-+ struct device_node *np = phydev->mdio.dev.of_node;
-+ u32 mdi_conf;
-+ int ret;
-+
-+ ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf);
-+
-+ /* Do nothing in case property "marvell,mdi-cfg-order" is not present */
-+ if (ret == -ENOENT)
-+ return 0;
-+
-+ if (ret)
-+ return ret;
-+
-+ if (mdi_conf & ~PMAPMD_RSVD_VEND_PROV_MDI_REVERSE)
-+ return -EINVAL;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV,
-+ PMAPMD_RSVD_VEND_PROV_MDI_CONF,
-+ mdi_conf | PMAPMD_RSVD_VEND_PROV_MDI_FORCE);
-+}
-+
- static int aqr107_config_init(struct phy_device *phydev)
- {
- struct aqr107_priv *priv = phydev->priv;
-@@ -514,6 +543,10 @@ static int aqr107_config_init(struct phy
- if (ret)
- return ret;
-
-+ ret = aqr107_config_mdi(phydev);
-+ if (ret)
-+ return ret;
-+
- /* Restore LED polarity state after reset */
- for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
- ret = aqr_phy_led_active_low_set(phydev, led_active_low, true);
+++ /dev/null
-From ce21b8fb255ebf0b49913fb4c62741d7eb05c6f6 Mon Sep 17 00:00:00 2001
-Date: Fri, 11 Oct 2024 22:28:43 +0100
-Subject: [PATCH] net: phy: aquantia: fix return value check in
- aqr107_config_mdi()
-
-of_property_read_u32() returns -EINVAL in case the property cannot be
-found rather than -ENOENT. Fix the check to not abort probing in case
-of the property being missing, and also in case CONFIG_OF is not set
-which will result in -ENOSYS.
-
-Fixes: a2e1ba275eae ("net: phy: aquantia: allow forcing order of MDI pairs")
----
- drivers/net/phy/aquantia/aquantia_main.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -500,7 +500,7 @@ static int aqr107_config_mdi(struct phy_
- ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf);
-
- /* Do nothing in case property "marvell,mdi-cfg-order" is not present */
-- if (ret == -ENOENT)
-+ if (ret == -EINVAL || ret == -ENOSYS)
- return 0;
-
- if (ret)
+++ /dev/null
-From a274465cc3bef2dfd9c9ea5100848dda0a8641e1 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 13:54:19 +0100
-Subject: [PATCH 1/4] net: phy: support 'active-high' property for PHY LEDs
-
-In addition to 'active-low' and 'inactive-high-impedance' also
-support 'active-high' property for PHY LED pin configuration.
-As only either 'active-high' or 'active-low' can be set at the
-same time, WARN and return an error in case both are set.
-
-Link: https://patch.msgid.link/91598487773d768f254d5faf06cf65b13e972f0e.1728558223.git.daniel@makrotopia.org
----
- drivers/net/phy/phy_device.c | 6 ++++++
- include/linux/phy.h | 5 +++--
- 2 files changed, 9 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -3385,11 +3385,17 @@ static int of_phy_led(struct phy_device
- if (index > U8_MAX)
- return -EINVAL;
-
-+ if (of_property_read_bool(led, "active-high"))
-+ set_bit(PHY_LED_ACTIVE_HIGH, &modes);
- if (of_property_read_bool(led, "active-low"))
- set_bit(PHY_LED_ACTIVE_LOW, &modes);
- if (of_property_read_bool(led, "inactive-high-impedance"))
- set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
-
-+ if (WARN_ON(modes & BIT(PHY_LED_ACTIVE_LOW) &&
-+ modes & BIT(PHY_LED_ACTIVE_HIGH)))
-+ return -EINVAL;
-+
- if (modes) {
- /* Return error if asked to set polarity modes but not supported */
- if (!phydev->drv->led_polarity_set)
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -877,8 +877,9 @@ struct phy_plca_status {
-
- /* Modes for PHY LED configuration */
- enum phy_led_modes {
-- PHY_LED_ACTIVE_LOW = 0,
-- PHY_LED_INACTIVE_HIGH_IMPEDANCE = 1,
-+ PHY_LED_ACTIVE_HIGH = 0,
-+ PHY_LED_ACTIVE_LOW = 1,
-+ PHY_LED_INACTIVE_HIGH_IMPEDANCE = 2,
-
- /* keep it last */
- __PHY_LED_MODES_NUM,
+++ /dev/null
-From 9d55e68b19f222e6334ef4021c5527998f5ab537 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 13:55:00 +0100
-Subject: [PATCH 2/4] net: phy: aquantia: correctly describe LED polarity
- override
-
-Use newly defined 'active-high' property to set the
-VEND1_GLOBAL_LED_DRIVE_VDD bit and let 'active-low' clear that bit. This
-reflects the technical reality which was inverted in the previous
-description in which the 'active-low' property was used to actually set
-the VEND1_GLOBAL_LED_DRIVE_VDD bit, which means that VDD (ie. supply
-voltage) of the LED is driven rather than GND.
-
-Link: https://patch.msgid.link/86a413b4387c42dcb54f587cc2433a06f16aae83.1728558223.git.daniel@makrotopia.org
----
- drivers/net/phy/aquantia/aquantia.h | 1 +
- drivers/net/phy/aquantia/aquantia_leds.c | 19 ++++++++++++++-----
- drivers/net/phy/aquantia/aquantia_main.c | 12 +++++++++---
- 3 files changed, 24 insertions(+), 8 deletions(-)
-
---- a/drivers/net/phy/aquantia/aquantia.h
-+++ b/drivers/net/phy/aquantia/aquantia.h
-@@ -177,6 +177,7 @@ static const struct aqr107_hw_stat aqr10
- struct aqr107_priv {
- u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
- unsigned long leds_active_low;
-+ unsigned long leds_active_high;
- };
-
- #if IS_REACHABLE(CONFIG_HWMON)
---- a/drivers/net/phy/aquantia/aquantia_leds.c
-+++ b/drivers/net/phy/aquantia/aquantia_leds.c
-@@ -121,13 +121,13 @@ int aqr_phy_led_active_low_set(struct ph
- {
- return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
- VEND1_GLOBAL_LED_DRIVE_VDD,
-- enable ? VEND1_GLOBAL_LED_DRIVE_VDD : 0);
-+ enable ? 0 : VEND1_GLOBAL_LED_DRIVE_VDD);
- }
-
- int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
- {
-+ bool force_active_low = false, force_active_high = false;
- struct aqr107_priv *priv = phydev->priv;
-- bool active_low = false;
- u32 mode;
-
- if (index >= AQR_MAX_LEDS)
-@@ -136,7 +136,10 @@ int aqr_phy_led_polarity_set(struct phy_
- for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
- switch (mode) {
- case PHY_LED_ACTIVE_LOW:
-- active_low = true;
-+ force_active_low = true;
-+ break;
-+ case PHY_LED_ACTIVE_HIGH:
-+ force_active_high = true;
- break;
- default:
- return -EINVAL;
-@@ -144,8 +147,14 @@ int aqr_phy_led_polarity_set(struct phy_
- }
-
- /* Save LED driver vdd state to restore on SW reset */
-- if (active_low)
-+ if (force_active_low)
- priv->leds_active_low |= BIT(index);
-
-- return aqr_phy_led_active_low_set(phydev, index, active_low);
-+ if (force_active_high)
-+ priv->leds_active_high |= BIT(index);
-+
-+ if (force_active_high || force_active_low)
-+ return aqr_phy_led_active_low_set(phydev, index, force_active_low);
-+
-+ unreachable();
- }
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -517,7 +517,7 @@ static int aqr107_config_mdi(struct phy_
- static int aqr107_config_init(struct phy_device *phydev)
- {
- struct aqr107_priv *priv = phydev->priv;
-- u32 led_active_low;
-+ u32 led_idx;
- int ret;
-
- /* Check that the PHY interface type is compatible */
-@@ -548,8 +548,14 @@ static int aqr107_config_init(struct phy
- return ret;
-
- /* Restore LED polarity state after reset */
-- for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
-- ret = aqr_phy_led_active_low_set(phydev, led_active_low, true);
-+ for_each_set_bit(led_idx, &priv->leds_active_low, AQR_MAX_LEDS) {
-+ ret = aqr_phy_led_active_low_set(phydev, led_idx, true);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ for_each_set_bit(led_idx, &priv->leds_active_high, AQR_MAX_LEDS) {
-+ ret = aqr_phy_led_active_low_set(phydev, led_idx, false);
- if (ret)
- return ret;
- }
+++ /dev/null
-From 78997e9a5e4d8a4df561e083a92c91ae23010e07 Mon Sep 17 00:00:00 2001
-Date: Tue, 1 Oct 2024 01:17:18 +0100
-Subject: [PATCH] net: phy: mxl-gpy: add basic LED support
-
-Add basic support for LEDs connected to MaxLinear GPY2xx and GPY115 PHYs.
-The PHYs allow up to 4 LEDs to be connected.
-Implement controlling LEDs in software as well as netdev trigger offloading
-and LED polarity setup.
-
-The hardware claims to support 16 PWM brightness levels but there is no
-documentation on how to use that feature, hence this is not supported.
-
-Link: https://patch.msgid.link/b6ec9050339f8244ff898898a1cecc33b13a48fc.1727741563.git.daniel@makrotopia.org
----
- drivers/net/phy/mxl-gpy.c | 218 ++++++++++++++++++++++++++++++++++++++
- 1 file changed, 218 insertions(+)
-
---- a/drivers/net/phy/mxl-gpy.c
-+++ b/drivers/net/phy/mxl-gpy.c
-@@ -38,6 +38,7 @@
- #define PHY_MIISTAT 0x18 /* MII state */
- #define PHY_IMASK 0x19 /* interrupt mask */
- #define PHY_ISTAT 0x1A /* interrupt status */
-+#define PHY_LED 0x1B /* LEDs */
- #define PHY_FWV 0x1E /* firmware version */
-
- #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
-@@ -61,6 +62,11 @@
- PHY_IMASK_ADSC | \
- PHY_IMASK_ANC)
-
-+#define GPY_MAX_LEDS 4
-+#define PHY_LED_POLARITY(idx) BIT(12 + (idx))
-+#define PHY_LED_HWCONTROL(idx) BIT(8 + (idx))
-+#define PHY_LED_ON(idx) BIT(idx)
-+
- #define PHY_FWV_REL_MASK BIT(15)
- #define PHY_FWV_MAJOR_MASK GENMASK(11, 8)
- #define PHY_FWV_MINOR_MASK GENMASK(7, 0)
-@@ -72,6 +78,23 @@
- #define PHY_MDI_MDI_X_CD 0x1
- #define PHY_MDI_MDI_X_CROSS 0x0
-
-+/* LED */
-+#define VSPEC1_LED(idx) (1 + (idx))
-+#define VSPEC1_LED_BLINKS GENMASK(15, 12)
-+#define VSPEC1_LED_PULSE GENMASK(11, 8)
-+#define VSPEC1_LED_CON GENMASK(7, 4)
-+#define VSPEC1_LED_BLINKF GENMASK(3, 0)
-+
-+#define VSPEC1_LED_LINK10 BIT(0)
-+#define VSPEC1_LED_LINK100 BIT(1)
-+#define VSPEC1_LED_LINK1000 BIT(2)
-+#define VSPEC1_LED_LINK2500 BIT(3)
-+
-+#define VSPEC1_LED_TXACT BIT(0)
-+#define VSPEC1_LED_RXACT BIT(1)
-+#define VSPEC1_LED_COL BIT(2)
-+#define VSPEC1_LED_NO_CON BIT(3)
-+
- /* SGMII */
- #define VSPEC1_SGMII_CTRL 0x08
- #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */
-@@ -835,6 +858,156 @@ static int gpy115_loopback(struct phy_de
- return genphy_soft_reset(phydev);
- }
-
-+static int gpy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ int ret;
-+
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ /* clear HWCONTROL and set manual LED state */
-+ ret = phy_modify(phydev, PHY_LED,
-+ ((value == LED_OFF) ? PHY_LED_HWCONTROL(index) : 0) |
-+ PHY_LED_ON(index),
-+ (value == LED_OFF) ? 0 : PHY_LED_ON(index));
-+ if (ret)
-+ return ret;
-+
-+ /* ToDo: set PWM brightness */
-+
-+ /* clear HW LED setup */
-+ if (value == LED_OFF)
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), 0);
-+ else
-+ return 0;
-+}
-+
-+static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
-+ 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 gpy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ /* All combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+
-+static int gpy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int val;
-+
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index));
-+ if (val < 0)
-+ return val;
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK10)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK2500)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) == (VSPEC1_LED_LINK10 |
-+ VSPEC1_LED_LINK100 |
-+ VSPEC1_LED_LINK1000 |
-+ VSPEC1_LED_LINK2500))
-+ *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+ if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_TXACT)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_RXACT)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ return 0;
-+}
-+
-+static int gpy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 val = 0;
-+ int ret;
-+
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_10))
-+ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK10);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_100))
-+ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK100);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_1000))
-+ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK1000);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_2500))
-+ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK2500);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX))
-+ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_TXACT);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX))
-+ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_RXACT);
-+
-+ /* allow RX/TX pulse without link indication */
-+ if ((rules & BIT(TRIGGER_NETDEV_TX) || rules & BIT(TRIGGER_NETDEV_RX)) &&
-+ !(val & VSPEC1_LED_CON))
-+ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_NO_CON) | VSPEC1_LED_CON;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), val);
-+ if (ret)
-+ return ret;
-+
-+ return phy_set_bits(phydev, PHY_LED, PHY_LED_HWCONTROL(index));
-+}
-+
-+static int gpy_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes)
-+{
-+ bool active_low = false;
-+ u32 mode;
-+
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ active_low = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index),
-+ active_low ? 0 : PHY_LED_POLARITY(index));
-+}
-+
- static struct phy_driver gpy_drivers[] = {
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx),
-@@ -852,6 +1025,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- .phy_id = PHY_ID_GPY115B,
-@@ -870,6 +1048,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy115_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY115C),
-@@ -887,6 +1070,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy115_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- .phy_id = PHY_ID_GPY211B,
-@@ -905,6 +1093,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY211C),
-@@ -922,6 +1115,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- .phy_id = PHY_ID_GPY212B,
-@@ -940,6 +1138,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY212C),
-@@ -957,6 +1160,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- .phy_id = PHY_ID_GPY215B,
-@@ -975,6 +1183,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY215C),
-@@ -992,6 +1205,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY241B),
+++ /dev/null
-From f95b4725e796b12e5f347a0d161e1d3843142aa8 Mon Sep 17 00:00:00 2001
-Date: Fri, 4 Oct 2024 16:56:35 +0100
-Subject: [PATCH] net: phy: mxl-gpy: add missing support for
- TRIGGER_NETDEV_LINK_10
-
-The PHY also support 10MBit/s links as well as the corresponding link
-indication trigger to be offloaded. Add TRIGGER_NETDEV_LINK_10 to the
-supported triggers.
-
-Link: https://patch.msgid.link/cc5da0a989af8b0d49d823656d88053c4de2ab98.1728057367.git.daniel@makrotopia.org
----
- drivers/net/phy/mxl-gpy.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/phy/mxl-gpy.c
-+++ b/drivers/net/phy/mxl-gpy.c
-@@ -884,6 +884,7 @@ static int gpy_led_brightness_set(struct
- }
-
- static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
- BIT(TRIGGER_NETDEV_LINK_100) |
- BIT(TRIGGER_NETDEV_LINK_1000) |
- BIT(TRIGGER_NETDEV_LINK_2500) |
+++ /dev/null
-From eb89c79c1b8f17fc1611540768678e60df89ac42 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 13:55:17 +0100
-Subject: [PATCH 3/4] net: phy: mxl-gpy: correctly describe LED polarity
-
-According the datasheet covering the LED (0x1b) register:
-0B Active High LEDx pin driven high when activated
-1B Active Low LEDx pin driven low when activated
-
-Make use of the now available 'active-high' property and correctly
-reflect the polarity setting which was previously inverted.
-
-Link: https://patch.msgid.link/180ccafa837f09908b852a8a874a3808c5ecd2d0.1728558223.git.daniel@makrotopia.org
----
- drivers/net/phy/mxl-gpy.c | 16 ++++++++++++----
- 1 file changed, 12 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/mxl-gpy.c
-+++ b/drivers/net/phy/mxl-gpy.c
-@@ -989,7 +989,7 @@ static int gpy_led_hw_control_set(struct
- static int gpy_led_polarity_set(struct phy_device *phydev, int index,
- unsigned long modes)
- {
-- bool active_low = false;
-+ bool force_active_low = false, force_active_high = false;
- u32 mode;
-
- if (index >= GPY_MAX_LEDS)
-@@ -998,15 +998,23 @@ static int gpy_led_polarity_set(struct p
- for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
- switch (mode) {
- case PHY_LED_ACTIVE_LOW:
-- active_low = true;
-+ force_active_low = true;
-+ break;
-+ case PHY_LED_ACTIVE_HIGH:
-+ force_active_high = true;
- break;
- default:
- return -EINVAL;
- }
- }
-
-- return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index),
-- active_low ? 0 : PHY_LED_POLARITY(index));
-+ if (force_active_low)
-+ return phy_set_bits(phydev, PHY_LED, PHY_LED_POLARITY(index));
-+
-+ if (force_active_high)
-+ return phy_clear_bits(phydev, PHY_LED, PHY_LED_POLARITY(index));
-+
-+ unreachable();
- }
-
- static struct phy_driver gpy_drivers[] = {
+++ /dev/null
-From 1758af47b98c17da464cb45f476875150955dd48 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 13:55:29 +0100
-Subject: [PATCH 4/4] net: phy: intel-xway: add support for PHY LEDs
-
-The intel-xway PHY driver predates the PHY LED framework and currently
-initializes all LED pins to equal default values.
-
-Add PHY LED functions to the drivers and don't set default values if
-LEDs are defined in device tree.
-
-According the datasheets 3 LEDs are supported on all Intel XWAY PHYs.
-
-Link: https://patch.msgid.link/81f4717ab9acf38f3239727a4540ae96fd01109b.1728558223.git.daniel@makrotopia.org
----
- drivers/net/phy/intel-xway.c | 253 +++++++++++++++++++++++++++++++++--
- 1 file changed, 244 insertions(+), 9 deletions(-)
-
---- a/drivers/net/phy/intel-xway.c
-+++ b/drivers/net/phy/intel-xway.c
-@@ -151,6 +151,13 @@
- #define XWAY_MMD_LED3H 0x01E8
- #define XWAY_MMD_LED3L 0x01E9
-
-+#define XWAY_GPHY_MAX_LEDS 3
-+#define XWAY_GPHY_LED_INV(idx) BIT(12 + (idx))
-+#define XWAY_GPHY_LED_EN(idx) BIT(8 + (idx))
-+#define XWAY_GPHY_LED_DA(idx) BIT(idx)
-+#define XWAY_MMD_LEDxH(idx) (XWAY_MMD_LED0H + 2 * (idx))
-+#define XWAY_MMD_LEDxL(idx) (XWAY_MMD_LED0L + 2 * (idx))
-+
- #define PHY_ID_PHY11G_1_3 0x030260D1
- #define PHY_ID_PHY22F_1_3 0x030260E1
- #define PHY_ID_PHY11G_1_4 0xD565A400
-@@ -229,20 +236,12 @@ static int xway_gphy_rgmii_init(struct p
- XWAY_MDIO_MIICTRL_TXSKEW_MASK, val);
- }
-
--static int xway_gphy_config_init(struct phy_device *phydev)
-+static int xway_gphy_init_leds(struct phy_device *phydev)
- {
- int err;
- u32 ledxh;
- u32 ledxl;
-
-- /* Mask all interrupts */
-- err = phy_write(phydev, XWAY_MDIO_IMASK, 0);
-- if (err)
-- return err;
--
-- /* Clear all pending interrupts */
-- phy_read(phydev, XWAY_MDIO_ISTAT);
--
- /* Ensure that integrated led function is enabled for all leds */
- err = phy_write(phydev, XWAY_MDIO_LED,
- XWAY_MDIO_LED_LED0_EN |
-@@ -276,6 +275,26 @@ static int xway_gphy_config_init(struct
- phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh);
- phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl);
-
-+ return 0;
-+}
-+
-+static int xway_gphy_config_init(struct phy_device *phydev)
-+{
-+ struct device_node *np = phydev->mdio.dev.of_node;
-+ int err;
-+
-+ /* Mask all interrupts */
-+ err = phy_write(phydev, XWAY_MDIO_IMASK, 0);
-+ if (err)
-+ return err;
-+
-+ /* Use default LED configuration if 'leds' node isn't defined */
-+ if (!of_get_child_by_name(np, "leds"))
-+ xway_gphy_init_leds(phydev);
-+
-+ /* Clear all pending interrupts */
-+ phy_read(phydev, XWAY_MDIO_ISTAT);
-+
- err = xway_gphy_rgmii_init(phydev);
- if (err)
- return err;
-@@ -347,6 +366,172 @@ static irqreturn_t xway_gphy_handle_inte
- return IRQ_HANDLED;
- }
-
-+static int xway_gphy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ int ret;
-+
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ /* clear EN and set manual LED state */
-+ ret = phy_modify(phydev, XWAY_MDIO_LED,
-+ ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) |
-+ XWAY_GPHY_LED_DA(index),
-+ (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index));
-+ if (ret)
-+ return ret;
-+
-+ /* clear HW LED setup */
-+ if (value == LED_OFF) {
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0);
-+ if (ret)
-+ return ret;
-+
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0);
-+ } else {
-+ return 0;
-+ }
-+}
-+
-+static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX));
-+
-+static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ /* activity triggers are not possible without combination with a link
-+ * trigger.
-+ */
-+ if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) &&
-+ !(rules & (BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000))))
-+ return -EOPNOTSUPP;
-+
-+ /* All other combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+
-+static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int lval, hval;
-+
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index));
-+ if (hval < 0)
-+ return hval;
-+
-+ lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index));
-+ if (lval < 0)
-+ return lval;
-+
-+ if (hval & XWAY_MMD_LEDxH_CON_LINK10)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+ if (hval & XWAY_MMD_LEDxH_CON_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (hval & XWAY_MMD_LEDxH_CON_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if ((hval & XWAY_MMD_LEDxH_CON_LINK10) &&
-+ (hval & XWAY_MMD_LEDxH_CON_LINK100) &&
-+ (hval & XWAY_MMD_LEDxH_CON_LINK1000))
-+ *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+ if (lval & XWAY_MMD_LEDxL_PULSE_TXACT)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ if (lval & XWAY_MMD_LEDxL_PULSE_RXACT)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ return 0;
-+}
-+
-+static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 hval = 0, lval = 0;
-+ int ret;
-+
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_10))
-+ hval |= XWAY_MMD_LEDxH_CON_LINK10;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_100))
-+ hval |= XWAY_MMD_LEDxH_CON_LINK100;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_1000))
-+ hval |= XWAY_MMD_LEDxH_CON_LINK1000;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX))
-+ lval |= XWAY_MMD_LEDxL_PULSE_TXACT;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX))
-+ lval |= XWAY_MMD_LEDxL_PULSE_RXACT;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval);
-+ if (ret)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval);
-+ if (ret)
-+ return ret;
-+
-+ return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index));
-+}
-+
-+static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes)
-+{
-+ bool force_active_low = false, force_active_high = false;
-+ u32 mode;
-+
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ force_active_low = true;
-+ break;
-+ case PHY_LED_ACTIVE_HIGH:
-+ force_active_high = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ if (force_active_low)
-+ return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
-+
-+ if (force_active_high)
-+ return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
-+
-+ unreachable();
-+}
-+
- static struct phy_driver xway_gphy[] = {
- {
- .phy_id = PHY_ID_PHY11G_1_3,
-@@ -359,6 +544,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_1_3,
- .phy_id_mask = 0xffffffff,
-@@ -370,6 +560,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY11G_1_4,
- .phy_id_mask = 0xffffffff,
-@@ -381,6 +576,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_1_4,
- .phy_id_mask = 0xffffffff,
-@@ -392,6 +592,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY11G_1_5,
- .phy_id_mask = 0xffffffff,
-@@ -402,6 +607,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_1_5,
- .phy_id_mask = 0xffffffff,
-@@ -412,6 +622,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY11G_VR9_1_1,
- .phy_id_mask = 0xffffffff,
-@@ -422,6 +637,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_VR9_1_1,
- .phy_id_mask = 0xffffffff,
-@@ -432,6 +652,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY11G_VR9_1_2,
- .phy_id_mask = 0xffffffff,
-@@ -442,6 +667,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_VR9_1_2,
- .phy_id_mask = 0xffffffff,
-@@ -452,6 +682,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- },
- };
- module_phy_driver(xway_gphy);
+++ /dev/null
-From b0fa00fe38f673c986633c11087274deeb7ce7b0 Mon Sep 17 00:00:00 2001
-Date: Tue, 7 Jan 2025 21:16:20 +0100
-Subject: [PATCH] gpio: regmap: Use generic request/free ops
-
-Set the gpiochip request and free ops to the generic implementations.
-This way a user can provide a gpio-ranges property defined for a pinmux,
-easing muxing of gpio functions. Provided that the pin controller
-implementents the pinmux op .gpio_request_enable(), pins will
-automatically be muxed to their GPIO function when requested.
-
----
- drivers/gpio/gpio-regmap.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/gpio/gpio-regmap.c
-+++ b/drivers/gpio/gpio-regmap.c
-@@ -262,6 +262,8 @@ struct gpio_regmap *gpio_regmap_register
- chip->label = config->label ?: dev_name(config->parent);
- chip->can_sleep = regmap_might_sleep(config->regmap);
-
-+ chip->request = gpiochip_generic_request;
-+ chip->free = gpiochip_generic_free;
- chip->get = gpio_regmap_get;
- if (gpio->reg_set_base && gpio->reg_clr_base)
- chip->set = gpio_regmap_set_with_clear;
+++ /dev/null
-From 7b590490e3aa6bfa38bf6e2069a529017fd3c1d2 Mon Sep 17 00:00:00 2001
-Date: Fri, 13 Oct 2023 00:08:35 +0200
-Subject: [PATCH] net: dsa: mv88e6xxx: Support LED control
-
-This adds control over the hardware LEDs in the Marvell
-MV88E6xxx DSA switch and enables it for MV88E6352.
-
-This fixes an imminent problem on the Inteno XG6846 which
-has a WAN LED that simply do not work with hardware
-defaults: driver amendment is necessary.
-
-The patch is modeled after Christian Marangis LED support
-code for the QCA8k DSA switch, I got help with the register
-definitions from Tim Harvey.
-
-After this patch it is possible to activate hardware link
-indication like this (or with a similar script):
-
- cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
- echo netdev > trigger
- echo 1 > link
-
-This makes the green link indicator come up on any link
-speed. It is also possible to be more elaborate, like this:
-
- cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
- echo netdev > trigger
- echo 1 > link_1000
- cd /sys/class/leds/Marvell\ 88E6352:05:01:amber:wan/
- echo netdev > trigger
- echo 1 > link_100
-
-Making the green LED come on for a gigabit link and the
-amber LED come on for a 100 mbit link.
-
-Each port has 2 LED slots (the hardware may use just one or
-none) and the hardware triggers are specified in four bits per
-LED, and some of the hardware triggers are only available on the
-SFP (fiber) uplink. The restrictions are described in the
-port.h header file where the registers are described. For
-example, selector 1 set for LED 1 on port 5 or 6 will indicate
-Fiber 1000 (gigabit) and activity with a blinking LED, but
-ONLY for an SFP connection. If port 5/6 is used with something
-not SFP, this selector is a noop: something else need to be
-selected.
-
-After the previous series rewriting the MV88E6xxx DT
-bindings to use YAML a "leds" subnode is already valid
-for each port, in my scratch device tree it looks like
-this:
-
- leds {
- #address-cells = <1>;
- #size-cells = <0>;
-
- led@0 {
- reg = <0>;
- color = <LED_COLOR_ID_GREEN>;
- function = LED_FUNCTION_LAN;
- default-state = "off";
- linux,default-trigger = "netdev";
- };
- led@1 {
- reg = <1>;
- color = <LED_COLOR_ID_AMBER>;
- function = LED_FUNCTION_LAN;
- default-state = "off";
- };
- };
-
-This DT config is not yet configuring everything: when the netdev
-default trigger is assigned the hw acceleration callbacks are
-not called, and there is no way to set the netdev sub-trigger
-type (such as link_1000) from the device tree, such as if you want
-a gigabit link indicator. This has to be done from userspace at
-this point.
-
-We add LED operations to all switches in the 6352 family:
-6172, 6176, 6240 and 6352.
-
----
- drivers/net/dsa/mv88e6xxx/Kconfig | 10 +
- drivers/net/dsa/mv88e6xxx/Makefile | 1 +
- drivers/net/dsa/mv88e6xxx/chip.c | 38 +-
- drivers/net/dsa/mv88e6xxx/chip.h | 11 +
- drivers/net/dsa/mv88e6xxx/leds.c | 839 +++++++++++++++++++++++++++++
- drivers/net/dsa/mv88e6xxx/port.c | 1 +
- drivers/net/dsa/mv88e6xxx/port.h | 133 +++++
- 7 files changed, 1031 insertions(+), 2 deletions(-)
- create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c
-
---- a/drivers/net/dsa/mv88e6xxx/Kconfig
-+++ b/drivers/net/dsa/mv88e6xxx/Kconfig
-@@ -17,3 +17,13 @@ config NET_DSA_MV88E6XXX_PTP
- help
- Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch
- chips that support it.
-+
-+config NET_DSA_MV88E6XXX_LEDS
-+ bool "LED support for Marvell 88E6xxx"
-+ default y
-+ depends on NET_DSA_MV88E6XXX
-+ depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_MV88E6XXX
-+ depends on LEDS_TRIGGERS
-+ help
-+ This enabled support for controlling the LEDs attached to the
-+ Marvell 88E6xxx switch chips.
---- a/drivers/net/dsa/mv88e6xxx/Makefile
-+++ b/drivers/net/dsa/mv88e6xxx/Makefile
-@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
- mv88e6xxx-objs += global2_avb.o
- mv88e6xxx-objs += global2_scratch.o
- mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
-+mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_LEDS) += leds.o
- mv88e6xxx-objs += pcs-6185.o
- mv88e6xxx-objs += pcs-6352.o
- mv88e6xxx-objs += pcs-639x.o
---- a/drivers/net/dsa/mv88e6xxx/chip.c
-+++ b/drivers/net/dsa/mv88e6xxx/chip.c
-@@ -27,6 +27,7 @@
- #include <linux/of_irq.h>
- #include <linux/of_mdio.h>
- #include <linux/platform_data/mv88e6xxx.h>
-+#include <linux/property.h>
- #include <linux/netdevice.h>
- #include <linux/gpio/consumer.h>
- #include <linux/phylink.h>
-@@ -3412,14 +3413,43 @@ static int mv88e6xxx_setup_upstream_port
- static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
- {
- struct device_node *phy_handle = NULL;
-+ struct fwnode_handle *ports_fwnode;
-+ struct fwnode_handle *port_fwnode;
- struct dsa_switch *ds = chip->ds;
-+ struct mv88e6xxx_port *p;
- struct dsa_port *dp;
- int tx_amp;
- int err;
- u16 reg;
-+ u32 val;
-
-- chip->ports[port].chip = chip;
-- chip->ports[port].port = port;
-+ p = &chip->ports[port];
-+ p->chip = chip;
-+ p->port = port;
-+
-+ /* Look up corresponding fwnode if any */
-+ ports_fwnode = device_get_named_child_node(chip->dev, "ethernet-ports");
-+ if (!ports_fwnode)
-+ ports_fwnode = device_get_named_child_node(chip->dev, "ports");
-+ if (ports_fwnode) {
-+ fwnode_for_each_child_node(ports_fwnode, port_fwnode) {
-+ if (fwnode_property_read_u32(port_fwnode, "reg", &val))
-+ continue;
-+ if (val == port) {
-+ p->fwnode = port_fwnode;
-+ p->fiber = fwnode_property_present(port_fwnode, "sfp");
-+ break;
-+ }
-+ }
-+ } else {
-+ dev_dbg(chip->dev, "no ethernet ports node defined for the device\n");
-+ }
-+
-+ if (chip->info->ops->port_setup_leds) {
-+ err = chip->info->ops->port_setup_leds(chip, port);
-+ if (err && err != -EOPNOTSUPP)
-+ return err;
-+ }
-
- err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
- SPEED_UNFORCED, DUPLEX_UNFORCED,
-@@ -4653,6 +4683,7 @@ static const struct mv88e6xxx_ops mv88e6
- .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
- .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
- .port_get_cmode = mv88e6352_port_get_cmode,
-+ .port_setup_leds = mv88e6xxx_port_setup_leds,
- .port_setup_message_port = mv88e6xxx_setup_message_port,
- .stats_snapshot = mv88e6320_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
-@@ -4755,6 +4786,7 @@ static const struct mv88e6xxx_ops mv88e6
- .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
- .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
- .port_get_cmode = mv88e6352_port_get_cmode,
-+ .port_setup_leds = mv88e6xxx_port_setup_leds,
- .port_setup_message_port = mv88e6xxx_setup_message_port,
- .stats_snapshot = mv88e6320_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
-@@ -5030,6 +5062,7 @@ static const struct mv88e6xxx_ops mv88e6
- .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
- .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
- .port_get_cmode = mv88e6352_port_get_cmode,
-+ .port_setup_leds = mv88e6xxx_port_setup_leds,
- .port_setup_message_port = mv88e6xxx_setup_message_port,
- .stats_snapshot = mv88e6320_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
-@@ -5460,6 +5493,7 @@ static const struct mv88e6xxx_ops mv88e6
- .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
- .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
- .port_get_cmode = mv88e6352_port_get_cmode,
-+ .port_setup_leds = mv88e6xxx_port_setup_leds,
- .port_setup_message_port = mv88e6xxx_setup_message_port,
- .stats_snapshot = mv88e6320_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
---- a/drivers/net/dsa/mv88e6xxx/chip.h
-+++ b/drivers/net/dsa/mv88e6xxx/chip.h
-@@ -13,7 +13,9 @@
- #include <linux/irq.h>
- #include <linux/gpio/consumer.h>
- #include <linux/kthread.h>
-+#include <linux/leds.h>
- #include <linux/phy.h>
-+#include <linux/property.h>
- #include <linux/ptp_clock_kernel.h>
- #include <linux/timecounter.h>
- #include <net/dsa.h>
-@@ -276,6 +278,7 @@ struct mv88e6xxx_vlan {
- struct mv88e6xxx_port {
- struct mv88e6xxx_chip *chip;
- int port;
-+ struct fwnode_handle *fwnode;
- struct mv88e6xxx_vlan bridge_pvid;
- u64 serdes_stats[2];
- u64 atu_member_violation;
-@@ -290,6 +293,11 @@ struct mv88e6xxx_port {
- struct devlink_region *region;
- void *pcs_private;
-
-+ /* LED related information */
-+ bool fiber;
-+ struct led_classdev led0;
-+ struct led_classdev led1;
-+
- /* MacAuth Bypass control flag */
- bool mab;
- };
-@@ -574,6 +582,9 @@ struct mv88e6xxx_ops {
- phy_interface_t mode);
- int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
-
-+ /* LED control */
-+ int (*port_setup_leds)(struct mv88e6xxx_chip *chip, int port);
-+
- /* Some devices have a per port register indicating what is
- * the upstream port this port should forward to.
- */
---- /dev/null
-+++ b/drivers/net/dsa/mv88e6xxx/leds.c
-@@ -0,0 +1,839 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+#include <linux/bitfield.h>
-+#include <linux/leds.h>
-+#include <linux/property.h>
-+
-+#include "chip.h"
-+#include "global2.h"
-+#include "port.h"
-+
-+/* Offset 0x16: LED control */
-+
-+static int mv88e6xxx_port_led_write(struct mv88e6xxx_chip *chip, int port, u16 reg)
-+{
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_UPDATE;
-+
-+ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, reg);
-+}
-+
-+static int mv88e6xxx_port_led_read(struct mv88e6xxx_chip *chip, int port,
-+ u16 ptr, u16 *val)
-+{
-+ int err;
-+
-+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, ptr);
-+ if (err)
-+ return err;
-+
-+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_LED_CONTROL, val);
-+ *val &= 0x3ff;
-+
-+ return err;
-+}
-+
-+static int mv88e6xxx_led_brightness_set(struct mv88e6xxx_port *p, int led,
-+ int brightness)
-+{
-+ u16 reg;
-+ int err;
-+
-+ err = mv88e6xxx_port_led_read(p->chip, p->port,
-+ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
-+ ®);
-+ if (err)
-+ return err;
-+
-+ if (led == 1)
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
-+ else
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
-+
-+ if (brightness) {
-+ /* Selector 0x0f == Force LED ON */
-+ if (led == 1)
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELF;
-+ else
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELF;
-+ } else {
-+ /* Selector 0x0e == Force LED OFF */
-+ if (led == 1)
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE;
-+ else
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE;
-+ }
-+
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
-+
-+ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
-+}
-+
-+static int mv88e6xxx_led0_brightness_set_blocking(struct led_classdev *ldev,
-+ enum led_brightness brightness)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_brightness_set(p, 0, brightness);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int mv88e6xxx_led1_brightness_set_blocking(struct led_classdev *ldev,
-+ enum led_brightness brightness)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_brightness_set(p, 1, brightness);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+struct mv88e6xxx_led_hwconfig {
-+ int led;
-+ u8 portmask;
-+ unsigned long rules;
-+ bool fiber;
-+ bool blink_activity;
-+ u16 selector;
-+};
-+
-+/* The following is a lookup table to check what rules we can support on a
-+ * certain LED given restrictions such as that some rules only work with fiber
-+ * (SFP) connections and some blink on activity by default.
-+ */
-+#define MV88E6XXX_PORTS_0_3 (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-+#define MV88E6XXX_PORTS_4_5 (BIT(4) | BIT(5))
-+#define MV88E6XXX_PORT_4 BIT(4)
-+#define MV88E6XXX_PORT_5 BIT(5)
-+
-+/* Entries are listed in selector order.
-+ *
-+ * These configurations vary across different switch families, list
-+ * different tables per-family here.
-+ */
-+static const struct mv88e6xxx_led_hwconfig mv88e6352_led_hwconfigs[] = {
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORT_4,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORT_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORT_4,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORT_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORT_4,
-+ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORT_5,
-+ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORT_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELA,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELA,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELB,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELB,
-+ },
-+};
-+
-+/* mv88e6xxx_led_match_selector() - look up the appropriate LED mode selector
-+ * @p: port state container
-+ * @led: LED number, 0 or 1
-+ * @blink_activity: blink the LED (usually blink on indicated activity)
-+ * @fiber: the link is connected to fiber such as SFP
-+ * @rules: LED status flags from the LED classdev core
-+ * @selector: fill in the selector in this parameter with an OR operation
-+ */
-+static int mv88e6xxx_led_match_selector(struct mv88e6xxx_port *p, int led, bool blink_activity,
-+ bool fiber, unsigned long rules, u16 *selector)
-+{
-+ const struct mv88e6xxx_led_hwconfig *conf;
-+ int i;
-+
-+ /* No rules means we turn the LED off */
-+ if (!rules) {
-+ if (led == 1)
-+ *selector |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE;
-+ else
-+ *selector |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE;
-+ return 0;
-+ }
-+
-+ /* TODO: these rules are for MV88E6352, when adding other families,
-+ * think about making sure you select the table that match the
-+ * specific switch family.
-+ */
-+ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
-+ conf = &mv88e6352_led_hwconfigs[i];
-+
-+ if (conf->led != led)
-+ continue;
-+
-+ if (!(conf->portmask & BIT(p->port)))
-+ continue;
-+
-+ if (conf->blink_activity != blink_activity)
-+ continue;
-+
-+ if (conf->fiber != fiber)
-+ continue;
-+
-+ if (conf->rules == rules) {
-+ dev_dbg(p->chip->dev, "port%d LED %d set selector %04x for rules %08lx\n",
-+ p->port, led, conf->selector, rules);
-+ *selector |= conf->selector;
-+ return 0;
-+ }
-+ }
-+
-+ return -EOPNOTSUPP;
-+}
-+
-+/* mv88e6xxx_led_match_selector() - find Linux netdev rules from a selector value
-+ * @p: port state container
-+ * @selector: the selector value from the LED actity register
-+ * @led: LED number, 0 or 1
-+ * @rules: Linux netdev activity rules found from selector
-+ */
-+static int
-+mv88e6xxx_led_match_rule(struct mv88e6xxx_port *p, u16 selector, int led, unsigned long *rules)
-+{
-+ const struct mv88e6xxx_led_hwconfig *conf;
-+ int i;
-+
-+ /* Find the selector in the table, we just look for the right selector
-+ * and ignore if the activity has special properties such as blinking
-+ * or is fiber-only.
-+ */
-+ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
-+ conf = &mv88e6352_led_hwconfigs[i];
-+
-+ if (conf->led != led)
-+ continue;
-+
-+ if (!(conf->portmask & BIT(p->port)))
-+ continue;
-+
-+ if (conf->selector == selector) {
-+ dev_dbg(p->chip->dev, "port%d LED %d has selector %04x, rules %08lx\n",
-+ p->port, led, selector, conf->rules);
-+ *rules = conf->rules;
-+ return 0;
-+ }
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+/* mv88e6xxx_led_get_selector() - get the appropriate LED mode selector
-+ * @p: port state container
-+ * @led: LED number, 0 or 1
-+ * @fiber: the link is connected to fiber such as SFP
-+ * @rules: LED status flags from the LED classdev core
-+ * @selector: fill in the selector in this parameter with an OR operation
-+ */
-+static int mv88e6xxx_led_get_selector(struct mv88e6xxx_port *p, int led,
-+ bool fiber, unsigned long rules, u16 *selector)
-+{
-+ int err;
-+
-+ /* What happens here is that we first try to locate a trigger with solid
-+ * indicator (such as LED is on for a 1000 link) else we try a second
-+ * sweep to find something suitable with a trigger that will blink on
-+ * activity.
-+ */
-+ err = mv88e6xxx_led_match_selector(p, led, false, fiber, rules, selector);
-+ if (err)
-+ return mv88e6xxx_led_match_selector(p, led, true, fiber, rules, selector);
-+
-+ return 0;
-+}
-+
-+/* Sets up the hardware blinking period */
-+static int mv88e6xxx_led_set_blinking_period(struct mv88e6xxx_port *p, int led,
-+ unsigned long delay_on, unsigned long delay_off)
-+{
-+ unsigned long period;
-+ u16 reg;
-+
-+ period = delay_on + delay_off;
-+
-+ reg = 0;
-+
-+ switch (period) {
-+ case 21:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS;
-+ break;
-+ case 42:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS;
-+ break;
-+ case 84:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS;
-+ break;
-+ case 168:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS;
-+ break;
-+ case 336:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS;
-+ break;
-+ case 672:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS;
-+ break;
-+ default:
-+ /* Fall back to software blinking */
-+ return -EINVAL;
-+ }
-+
-+ /* This is essentially PWM duty cycle: how long time of the period
-+ * will the LED be on. Zero isn't great in most cases.
-+ */
-+ switch (delay_on) {
-+ case 0:
-+ /* This is usually pretty useless and will make the LED look OFF */
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE;
-+ break;
-+ case 21:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS;
-+ break;
-+ case 42:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS;
-+ break;
-+ case 84:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS;
-+ break;
-+ case 168:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS;
-+ break;
-+ default:
-+ /* Just use something non-zero */
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS;
-+ break;
-+ }
-+
-+ /* Set up blink rate */
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK;
-+
-+ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
-+}
-+
-+static int mv88e6xxx_led_blink_set(struct mv88e6xxx_port *p, int led,
-+ unsigned long *delay_on, unsigned long *delay_off)
-+{
-+ u16 reg;
-+ int err;
-+
-+ /* Choose a sensible default 336 ms (~3 Hz) */
-+ if ((*delay_on == 0) && (*delay_off == 0)) {
-+ *delay_on = 168;
-+ *delay_off = 168;
-+ }
-+
-+ /* No off delay is just on */
-+ if (*delay_off == 0)
-+ return mv88e6xxx_led_brightness_set(p, led, 1);
-+
-+ err = mv88e6xxx_led_set_blinking_period(p, led, *delay_on, *delay_off);
-+ if (err)
-+ return err;
-+
-+ err = mv88e6xxx_port_led_read(p->chip, p->port,
-+ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
-+ ®);
-+ if (err)
-+ return err;
-+
-+ if (led == 1)
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
-+ else
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
-+
-+ /* This will select the forced blinking status */
-+ if (led == 1)
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELD;
-+ else
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELD;
-+
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
-+
-+ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
-+}
-+
-+static int mv88e6xxx_led0_blink_set(struct led_classdev *ldev,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_blink_set(p, 0, delay_on, delay_off);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int mv88e6xxx_led1_blink_set(struct led_classdev *ldev,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_blink_set(p, 1, delay_on, delay_off);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int
-+mv88e6xxx_led0_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+ u16 selector = 0;
-+
-+ return mv88e6xxx_led_get_selector(p, 0, p->fiber, rules, &selector);
-+}
-+
-+static int
-+mv88e6xxx_led1_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+ u16 selector = 0;
-+
-+ return mv88e6xxx_led_get_selector(p, 1, p->fiber, rules, &selector);
-+}
-+
-+static int mv88e6xxx_led_hw_control_set(struct mv88e6xxx_port *p,
-+ int led, unsigned long rules)
-+{
-+ u16 reg;
-+ int err;
-+
-+ err = mv88e6xxx_port_led_read(p->chip, p->port,
-+ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
-+ ®);
-+ if (err)
-+ return err;
-+
-+ if (led == 1)
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
-+ else
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
-+
-+ err = mv88e6xxx_led_get_selector(p, led, p->fiber, rules, ®);
-+ if (err)
-+ return err;
-+
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
-+
-+ if (led == 0)
-+ dev_dbg(p->chip->dev, "LED 0 hw control on port %d trigger selector 0x%02x\n",
-+ p->port,
-+ (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK));
-+ else
-+ dev_dbg(p->chip->dev, "LED 1 hw control on port %d trigger selector 0x%02x\n",
-+ p->port,
-+ (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK) >> 4);
-+
-+ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
-+}
-+
-+static int
-+mv88e6xxx_led_hw_control_get(struct mv88e6xxx_port *p, int led, unsigned long *rules)
-+{
-+ u16 val;
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_port_led_read(p->chip, p->port,
-+ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, &val);
-+ mv88e6xxx_reg_unlock(p->chip);
-+ if (err)
-+ return err;
-+
-+ /* Mask out the selector bits for this port */
-+ if (led == 1) {
-+ val &= MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
-+ /* It's forced blinking/OFF/ON */
-+ if (val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELD ||
-+ val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELE ||
-+ val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELF) {
-+ *rules = 0;
-+ return 0;
-+ }
-+ } else {
-+ val &= MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
-+ /* It's forced blinking/OFF/ON */
-+ if (val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELD ||
-+ val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELE ||
-+ val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELF) {
-+ *rules = 0;
-+ return 0;
-+ }
-+ }
-+
-+ err = mv88e6xxx_led_match_rule(p, val, led, rules);
-+ if (!err)
-+ return 0;
-+
-+ dev_dbg(p->chip->dev, "couldn't find matching selector for %04x\n", val);
-+ *rules = 0;
-+ return 0;
-+}
-+
-+static int
-+mv88e6xxx_led0_hw_control_set(struct led_classdev *ldev, unsigned long rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_hw_control_set(p, 0, rules);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int
-+mv88e6xxx_led1_hw_control_set(struct led_classdev *ldev, unsigned long rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_hw_control_set(p, 1, rules);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int
-+mv88e6xxx_led0_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+
-+ return mv88e6xxx_led_hw_control_get(p, 0, rules);
-+}
-+
-+static int
-+mv88e6xxx_led1_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+
-+ return mv88e6xxx_led_hw_control_get(p, 1, rules);
-+}
-+
-+static struct device *mv88e6xxx_led_hw_control_get_device(struct mv88e6xxx_port *p)
-+{
-+ struct dsa_port *dp;
-+
-+ dp = dsa_to_port(p->chip->ds, p->port);
-+ if (!dp)
-+ return NULL;
-+ if (dp->user)
-+ return &dp->user->dev;
-+ return NULL;
-+}
-+
-+static struct device *
-+mv88e6xxx_led0_hw_control_get_device(struct led_classdev *ldev)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+
-+ return mv88e6xxx_led_hw_control_get_device(p);
-+}
-+
-+static struct device *
-+mv88e6xxx_led1_hw_control_get_device(struct led_classdev *ldev)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+
-+ return mv88e6xxx_led_hw_control_get_device(p);
-+}
-+
-+int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port)
-+{
-+ struct fwnode_handle *led = NULL, *leds = NULL;
-+ struct led_init_data init_data = { };
-+ enum led_default_state state;
-+ struct mv88e6xxx_port *p;
-+ struct led_classdev *l;
-+ struct device *dev;
-+ u32 led_num;
-+ int ret;
-+
-+ /* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */
-+ if (port > 5)
-+ return -EOPNOTSUPP;
-+
-+ p = &chip->ports[port];
-+ if (!p->fwnode)
-+ return 0;
-+
-+ dev = chip->dev;
-+
-+ leds = fwnode_get_named_child_node(p->fwnode, "leds");
-+ if (!leds) {
-+ dev_dbg(dev, "No Leds node specified in device tree for port %d!\n",
-+ port);
-+ return 0;
-+ }
-+
-+ fwnode_for_each_child_node(leds, led) {
-+ /* Reg represent the led number of the port, max 2
-+ * LEDs can be connected to each port, in some designs
-+ * only one LED is connected.
-+ */
-+ if (fwnode_property_read_u32(led, "reg", &led_num))
-+ continue;
-+ if (led_num > 1) {
-+ dev_err(dev, "invalid LED specified port %d\n", port);
-+ return -EINVAL;
-+ }
-+
-+ if (led_num == 0)
-+ l = &p->led0;
-+ else
-+ l = &p->led1;
-+
-+ state = led_init_default_state_get(led);
-+ switch (state) {
-+ case LEDS_DEFSTATE_ON:
-+ l->brightness = 1;
-+ mv88e6xxx_led_brightness_set(p, led_num, 1);
-+ break;
-+ case LEDS_DEFSTATE_KEEP:
-+ break;
-+ default:
-+ l->brightness = 0;
-+ mv88e6xxx_led_brightness_set(p, led_num, 0);
-+ }
-+
-+ l->max_brightness = 1;
-+ if (led_num == 0) {
-+ l->brightness_set_blocking = mv88e6xxx_led0_brightness_set_blocking;
-+ l->blink_set = mv88e6xxx_led0_blink_set;
-+ l->hw_control_is_supported = mv88e6xxx_led0_hw_control_is_supported;
-+ l->hw_control_set = mv88e6xxx_led0_hw_control_set;
-+ l->hw_control_get = mv88e6xxx_led0_hw_control_get;
-+ l->hw_control_get_device = mv88e6xxx_led0_hw_control_get_device;
-+ } else {
-+ l->brightness_set_blocking = mv88e6xxx_led1_brightness_set_blocking;
-+ l->blink_set = mv88e6xxx_led1_blink_set;
-+ l->hw_control_is_supported = mv88e6xxx_led1_hw_control_is_supported;
-+ l->hw_control_set = mv88e6xxx_led1_hw_control_set;
-+ l->hw_control_get = mv88e6xxx_led1_hw_control_get;
-+ l->hw_control_get_device = mv88e6xxx_led1_hw_control_get_device;
-+ }
-+ l->hw_control_trigger = "netdev";
-+
-+ init_data.default_label = ":port";
-+ init_data.fwnode = led;
-+ init_data.devname_mandatory = true;
-+ init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name,
-+ port, led_num);
-+ if (!init_data.devicename)
-+ return -ENOMEM;
-+
-+ ret = devm_led_classdev_register_ext(dev, l, &init_data);
-+ kfree(init_data.devicename);
-+
-+ if (ret) {
-+ dev_err(dev, "Failed to init LED %d for port %d", led_num, port);
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
---- a/drivers/net/dsa/mv88e6xxx/port.c
-+++ b/drivers/net/dsa/mv88e6xxx/port.c
-@@ -12,6 +12,7 @@
- #include <linux/if_bridge.h>
- #include <linux/phy.h>
- #include <linux/phylink.h>
-+#include <linux/property.h>
-
- #include "chip.h"
- #include "global2.h"
---- a/drivers/net/dsa/mv88e6xxx/port.h
-+++ b/drivers/net/dsa/mv88e6xxx/port.h
-@@ -309,6 +309,130 @@
- /* Offset 0x13: OutFiltered Counter */
- #define MV88E6XXX_PORT_OUT_FILTERED 0x13
-
-+/* Offset 0x16: LED Control */
-+#define MV88E6XXX_PORT_LED_CONTROL 0x16
-+#define MV88E6XXX_PORT_LED_CONTROL_UPDATE BIT(15)
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_MASK GENMASK(14, 12)
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL (0x00 << 12) /* Control for LED 0 and 1 */
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK (0x06 << 12) /* Stetch and Blink Rate */
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_CNTL_SPECIAL (0x07 << 12) /* Control for the Port's Special LED */
-+#define MV88E6XXX_PORT_LED_CONTROL_DATA_MASK GENMASK(10, 0)
-+/* Selection masks valid for either port 1,2,3,4 or 5 */
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK GENMASK(3, 0)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK GENMASK(7, 4)
-+/* Selection control for LED 0 and 1, ports 5 and 6 only has LED 0
-+ * Bits Function
-+ * 0..3 LED 0 control selector on ports 1-5
-+ * 4..7 LED 1 control selector on ports 1-4 on port 5 this controls LED 0 of port 6
-+ *
-+ * Sel Port LED Function for the 6352 family:
-+ * 0 1-4 0 Link/Act/Speed by Blink Rate (off=no link, on=link, blink=activity, blink speed=link speed)
-+ * 1-4 1 Port 2's Special LED
-+ * 5-6 0 Port 5 Link/Act (off=no link, on=link, blink=activity)
-+ * 5-6 1 Port 6 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 1 1-4 0 100/1000 Link/Act (off=no link, on=100 or 1000 link, blink=activity)
-+ * 1-4 1 10/100 Link Act (off=no link, on=10 or 100 link, blink=activity)
-+ * 5-6 0 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
-+ * 5-6 1 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 2 1-4 0 1000 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 1-4 1 10/100 Link/Act (off=no link, on=10 or 100 link, blink=activity)
-+ * 5-6 0 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 5-6 1 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
-+ * 3 1-4 0 Link/Act (off=no link, on=link, blink=activity)
-+ * 1-4 1 1000 Link (off=no link, on=1000 link)
-+ * 5-6 0 Port 0's Special LED
-+ * 5-6 1 Fiber Link (off=no link, on=link)
-+ * 4 1-4 0 Port 0's Special LED
-+ * 1-4 1 Port 1's Special LED
-+ * 5-6 0 Port 1's Special LED
-+ * 5-6 1 Port 5 Link/Act (off=no link, on=link, blink=activity)
-+ * 5 1-4 0 Reserved
-+ * 1-4 1 Reserved
-+ * 5-6 0 Port 2's Special LED
-+ * 5-6 1 Port 6 Link (off=no link, on=link)
-+ * 6 1-4 0 Duplex/Collision (off=half-duplex,on=full-duplex,blink=collision)
-+ * 1-4 1 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
-+ * 5-6 0 Port 5 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
-+ * 5-6 1 Port 6 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
-+ * 7 1-4 0 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
-+ * 1-4 1 10/1000 Link (off=no link, on=10 or 1000 link)
-+ * 5-6 0 Port 5 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed)
-+ * 5-6 1 Port 6 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed)
-+ * 8 1-4 0 Link (off=no link, on=link)
-+ * 1-4 1 Activity (off=no link, blink on=activity)
-+ * 5-6 0 Port 6 Link/Act (off=no link, on=link, blink=activity)
-+ * 5-6 1 Port 0's Special LED
-+ * 9 1-4 0 10 Link (off=no link, on=10 link)
-+ * 1-4 1 100 Link (off=no link, on=100 link)
-+ * 5-6 0 Reserved
-+ * 5-6 1 Port 1's Special LED
-+ * a 1-4 0 10 Link/Act (off=no link, on=10 link, blink=activity)
-+ * 1-4 1 100 Link/Act (off=no link, on=100 link, blink=activity)
-+ * 5-6 0 Reserved
-+ * 5-6 1 Port 2's Special LED
-+ * b 1-4 0 100/1000 Link (off=no link, on=100 or 1000 link)
-+ * 1-4 1 10/100 Link (off=no link, on=100 link, blink=activity)
-+ * 5-6 0 Reserved
-+ * 5-6 1 Reserved
-+ * c * * PTP Act (blink on=PTP activity)
-+ * d * * Force Blink
-+ * e * * Force Off
-+ * f * * Force On
-+ */
-+/* Select LED0 output */
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0 0x0
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1 0x1
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2 0x2
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3 0x3
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL4 0x4
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL5 0x5
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6 0x6
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7 0x7
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8 0x8
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9 0x9
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELA 0xa
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELB 0xb
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELC 0xc
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELD 0xd
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELE 0xe
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELF 0xf
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0 (0x0 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1 (0x1 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2 (0x2 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3 (0x3 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4 (0x4 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5 (0x5 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6 (0x6 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7 (0x7 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8 (0x8 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9 (0x9 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELA (0xa << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELB (0xb << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELC (0xc << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELD (0xd << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELE (0xe << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELF (0xf << 4)
-+/* Stretch and Blink Rate Control (Index 0x06 of LED Control) */
-+/* Pulse Stretch Selection for all LED's on this port */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE (0 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS (1 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS (2 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS (3 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS (4 << 4)
-+/* Blink Rate Selection for all LEDs on this port */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS 0
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS 1
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS 2
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS 3
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS 4
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS 5
-+ /* Control for Special LED (Index 0x7 of LED Control on Port0) */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x07_P0_LAN_LINKACT_SHIFT 0 /* bits 6:0 LAN Link Activity LED */
-+/* Control for Special LED (Index 0x7 of LED Control on Port 1) */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x07_P1_WAN_LINKACT_SHIFT 0 /* bits 6:0 WAN Link Activity LED */
-+/* Control for Special LED (Index 0x7 of LED Control on Port 2) */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x07_P2_PTP_ACT 0 /* bits 6:0 PTP Activity */
-+
- /* Offset 0x18: IEEE Priority Mapping Table */
- #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18
- #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000
-@@ -457,6 +581,15 @@ int mv88e6393x_port_set_cmode(struct mv8
- phy_interface_t mode);
- int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
- int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
-+#ifdef CONFIG_NET_DSA_MV88E6XXX_LEDS
-+int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port);
-+#else
-+static inline int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip,
-+ int port)
-+{
-+ return 0;
-+}
-+#endif
- int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
- bool drop_untagged);
- int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map);
+++ /dev/null
-From 239d87327dcd361b0098038995f8908f3296864f Mon Sep 17 00:00:00 2001
-Date: Thu, 12 Dec 2024 17:28:06 -0800
-Subject: fortify: Hide run-time copy size from value range tracking
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-GCC performs value range tracking for variables as a way to provide better
-diagnostics. One place this is regularly seen is with warnings associated
-with bounds-checking, e.g. -Wstringop-overflow, -Wstringop-overread,
--Warray-bounds, etc. In order to keep the signal-to-noise ratio high,
-warnings aren't emitted when a value range spans the entire value range
-representable by a given variable. For example:
-
- unsigned int len;
- char dst[8];
- ...
- memcpy(dst, src, len);
-
-If len's value is unknown, it has the full "unsigned int" range of [0,
-UINT_MAX], and GCC's compile-time bounds checks against memcpy() will
-be ignored. However, when a code path has been able to narrow the range:
-
- if (len > 16)
- return;
- memcpy(dst, src, len);
-
-Then the range will be updated for the execution path. Above, len is
-now [0, 16] when reading memcpy(), so depending on other optimizations,
-we might see a -Wstringop-overflow warning like:
-
- error: '__builtin_memcpy' writing between 9 and 16 bytes into region of size 8 [-Werror=stringop-overflow]
-
-When building with CONFIG_FORTIFY_SOURCE, the fortified run-time bounds
-checking can appear to narrow value ranges of lengths for memcpy(),
-depending on how the compiler constructs the execution paths during
-optimization passes, due to the checks against the field sizes. For
-example:
-
- if (p_size_field != SIZE_MAX &&
- p_size != p_size_field && p_size_field < size)
-
-As intentionally designed, these checks only affect the kernel warnings
-emitted at run-time and do not block the potentially overflowing memcpy(),
-so GCC thinks it needs to produce a warning about the resulting value
-range that might be reaching the memcpy().
-
-We have seen this manifest a few times now, with the most recent being
-with cpumasks:
-
-In function ‘bitmap_copy’,
- inlined from ‘cpumask_copy’ at ./include/linux/cpumask.h:839:2,
- inlined from ‘__padata_set_cpumasks’ at kernel/padata.c:730:2:
-./include/linux/fortify-string.h:114:33: error: ‘__builtin_memcpy’ reading between 257 and 536870904 bytes from a region of size 256 [-Werror=stringop-overread]
- 114 | #define __underlying_memcpy __builtin_memcpy
- | ^
-./include/linux/fortify-string.h:633:9: note: in expansion of macro ‘__underlying_memcpy’
- 633 | __underlying_##op(p, q, __fortify_size); \
- | ^~~~~~~~~~~~~
-./include/linux/fortify-string.h:678:26: note: in expansion of macro ‘__fortify_memcpy_chk’
- 678 | #define memcpy(p, q, s) __fortify_memcpy_chk(p, q, s, \
- | ^~~~~~~~~~~~~~~~~~~~
-./include/linux/bitmap.h:259:17: note: in expansion of macro ‘memcpy’
- 259 | memcpy(dst, src, len);
- | ^~~~~~
-kernel/padata.c: In function ‘__padata_set_cpumasks’:
-kernel/padata.c:713:48: note: source object ‘pcpumask’ of size [0, 256]
- 713 | cpumask_var_t pcpumask,
- | ~~~~~~~~~~~~~~^~~~~~~~
-
-This warning is _not_ emitted when CONFIG_FORTIFY_SOURCE is disabled,
-and with the recent -fdiagnostics-details we can confirm the origin of
-the warning is due to FORTIFY's bounds checking:
-
-../include/linux/bitmap.h:259:17: note: in expansion of macro 'memcpy'
- 259 | memcpy(dst, src, len);
- | ^~~~~~
- '__padata_set_cpumasks': events 1-2
-../include/linux/fortify-string.h:613:36:
- 612 | if (p_size_field != SIZE_MAX &&
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 613 | p_size != p_size_field && p_size_field < size)
- | ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
- | |
- | (1) when the condition is evaluated to false
- | (2) when the condition is evaluated to true
- '__padata_set_cpumasks': event 3
- 114 | #define __underlying_memcpy __builtin_memcpy
- | ^
- | |
- | (3) out of array bounds here
-
-Note that the cpumask warning started appearing since bitmap functions
-were recently marked __always_inline in commit ed8cd2b3bd9f ("bitmap:
-Switch from inline to __always_inline"), which allowed GCC to gain
-visibility into the variables as they passed through the FORTIFY
-implementation.
-
-In order to silence these false positives but keep otherwise deterministic
-compile-time warnings intact, hide the length variable from GCC with
-OPTIMIZE_HIDE_VAR() before calling the builtin memcpy.
-
-Additionally add a comment about why all the macro args have copies with
-const storage.
-
----
- include/linux/fortify-string.h | 14 +++++++++++++-
- 1 file changed, 13 insertions(+), 1 deletion(-)
-
---- a/include/linux/fortify-string.h
-+++ b/include/linux/fortify-string.h
-@@ -616,6 +616,12 @@ __FORTIFY_INLINE bool fortify_memcpy_chk
- return false;
- }
-
-+/*
-+ * To work around what seems to be an optimizer bug, the macro arguments
-+ * need to have const copies or the values end up changed by the time they
-+ * reach fortify_warn_once(). See commit 6f7630b1b5bc ("fortify: Capture
-+ * __bos() results in const temp vars") for more details.
-+ */
- #define __fortify_memcpy_chk(p, q, size, p_size, q_size, \
- p_size_field, q_size_field, op) ({ \
- const size_t __fortify_size = (size_t)(size); \
-@@ -623,6 +629,8 @@ __FORTIFY_INLINE bool fortify_memcpy_chk
- const size_t __q_size = (q_size); \
- const size_t __p_size_field = (p_size_field); \
- const size_t __q_size_field = (q_size_field); \
-+ /* Keep a mutable version of the size for the final copy. */ \
-+ size_t __copy_size = __fortify_size; \
- fortify_warn_once(fortify_memcpy_chk(__fortify_size, __p_size, \
- __q_size, __p_size_field, \
- __q_size_field, FORTIFY_FUNC_ ##op), \
-@@ -630,7 +638,11 @@ __FORTIFY_INLINE bool fortify_memcpy_chk
- __fortify_size, \
- "field \"" #p "\" at " FILE_LINE, \
- __p_size_field); \
-- __underlying_##op(p, q, __fortify_size); \
-+ /* Hide only the run-time size from value range tracking to */ \
-+ /* silence compile-time false positive bounds warnings. */ \
-+ if (!__builtin_constant_p(__copy_size)) \
-+ OPTIMIZER_HIDE_VAR(__copy_size); \
-+ __underlying_##op(p, q, __copy_size); \
- })
-
- /*