From: Álvaro Fernández Rojas Date: Sat, 7 Jun 2025 08:38:55 +0000 (+0200) Subject: generic: 6.12: reorganize backports X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=83648084cc150d94be9dda6c0a1fb854b7831ace;p=openwrt%2Fopenwrt.git generic: 6.12: reorganize backports Reorganize backported 6.12 generic patches, grouping them by following a standard naming XXX-XX-v6.x-patch-file-name.patch. Signed-off-by: Álvaro Fernández Rojas --- diff --git a/target/linux/generic/backport-6.12/200-01-v6.13-jiffies-Define-secs_to_jiffies.patch b/target/linux/generic/backport-6.12/200-01-v6.13-jiffies-Define-secs_to_jiffies.patch new file mode 100644 index 0000000000..ad9af1d4bb --- /dev/null +++ b/target/linux/generic/backport-6.12/200-01-v6.13-jiffies-Define-secs_to_jiffies.patch @@ -0,0 +1,60 @@ +From b35108a51cf7bab58d7eace1267d7965978bcdb8 Mon Sep 17 00:00:00 2001 +From: Easwar Hariharan +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. + +Suggested-by: Michael Kelley +Signed-off-by: Easwar Hariharan +Signed-off-by: Thomas Gleixner +Reviewed-by: Luiz Augusto von Dentz +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, diff --git a/target/linux/generic/backport-6.12/200-02-v6.14-jiffies-Cast-to-unsigned-long-in-secs_to_jiffies-con.patch b/target/linux/generic/backport-6.12/200-02-v6.14-jiffies-Cast-to-unsigned-long-in-secs_to_jiffies-con.patch new file mode 100644 index 0000000000..cddd558dee --- /dev/null +++ b/target/linux/generic/backport-6.12/200-02-v6.14-jiffies-Cast-to-unsigned-long-in-secs_to_jiffies-con.patch @@ -0,0 +1,35 @@ +From bb2784d9ab49587ba4fbff37a319fff2924db289 Mon Sep 17 00:00:00 2001 +From: Easwar Hariharan +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()") +Reported-by: kernel test robot +Signed-off-by: Easwar Hariharan +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/all/20250130192701.99626-1-eahariha@linux.microsoft.com +Closes: https://lore.kernel.org/oe-kbuild-all/202501301334.NB6NszQR-lkp@intel.com/ +--- + 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) diff --git a/target/linux/generic/backport-6.12/201-v6.16-mips-Add-std-flag-specified.patch b/target/linux/generic/backport-6.12/201-v6.16-mips-Add-std-flag-specified.patch deleted file mode 100644 index a0d2273837..0000000000 --- a/target/linux/generic/backport-6.12/201-v6.16-mips-Add-std-flag-specified.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0f4ae7c6ecb89bfda026d210dcf8216fb67d2333 Mon Sep 17 00:00:00 2001 -From: Khem Raj -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. - -Signed-off-by: Khem Raj -Cc: stable@vger.kernel.org -Signed-off-by: Thomas Bogendoerfer ---- - 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 \ diff --git a/target/linux/generic/backport-6.12/210-v6.13-fortify-Hide-run-time-copy-size-from-value-range-tracking.patch b/target/linux/generic/backport-6.12/210-v6.13-fortify-Hide-run-time-copy-size-from-value-range-tracking.patch new file mode 100644 index 0000000000..8dca649866 --- /dev/null +++ b/target/linux/generic/backport-6.12/210-v6.13-fortify-Hide-run-time-copy-size-from-value-range-tracking.patch @@ -0,0 +1,155 @@ +From 239d87327dcd361b0098038995f8908f3296864f Mon Sep 17 00:00:00 2001 +From: Kees Cook +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. + +Reported-by: "Thomas Weißschuh" +Closes: https://lore.kernel.org/all/db7190c8-d17f-4a0d-bc2f-5903c79f36c2@t-8ch.de/ +Reported-by: Nilay Shroff +Closes: https://lore.kernel.org/all/20241112124127.1666300-1-nilay@linux.ibm.com/ +Tested-by: Nilay Shroff +Acked-by: Yury Norov +Acked-by: Greg Kroah-Hartman +Signed-off-by: Kees Cook +--- + 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); \ + }) + + /* diff --git a/target/linux/generic/backport-6.12/300-v6.16-mips-Add-std-flag-specified.patch b/target/linux/generic/backport-6.12/300-v6.16-mips-Add-std-flag-specified.patch new file mode 100644 index 0000000000..a0d2273837 --- /dev/null +++ b/target/linux/generic/backport-6.12/300-v6.16-mips-Add-std-flag-specified.patch @@ -0,0 +1,44 @@ +From 0f4ae7c6ecb89bfda026d210dcf8216fb67d2333 Mon Sep 17 00:00:00 2001 +From: Khem Raj +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. + +Signed-off-by: Khem Raj +Cc: stable@vger.kernel.org +Signed-off-by: Thomas Bogendoerfer +--- + 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 \ diff --git a/target/linux/generic/backport-6.12/330-v6.13-jiffies-Define-secs_to_jiffies.patch b/target/linux/generic/backport-6.12/330-v6.13-jiffies-Define-secs_to_jiffies.patch deleted file mode 100644 index ad9af1d4bb..0000000000 --- a/target/linux/generic/backport-6.12/330-v6.13-jiffies-Define-secs_to_jiffies.patch +++ /dev/null @@ -1,60 +0,0 @@ -From b35108a51cf7bab58d7eace1267d7965978bcdb8 Mon Sep 17 00:00:00 2001 -From: Easwar Hariharan -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. - -Suggested-by: Michael Kelley -Signed-off-by: Easwar Hariharan -Signed-off-by: Thomas Gleixner -Reviewed-by: Luiz Augusto von Dentz -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, diff --git a/target/linux/generic/backport-6.12/331-v6.14-jiffies-Cast-to-unsigned-long-in-secs_to_jiffies-con.patch b/target/linux/generic/backport-6.12/331-v6.14-jiffies-Cast-to-unsigned-long-in-secs_to_jiffies-con.patch deleted file mode 100644 index cddd558dee..0000000000 --- a/target/linux/generic/backport-6.12/331-v6.14-jiffies-Cast-to-unsigned-long-in-secs_to_jiffies-con.patch +++ /dev/null @@ -1,35 +0,0 @@ -From bb2784d9ab49587ba4fbff37a319fff2924db289 Mon Sep 17 00:00:00 2001 -From: Easwar Hariharan -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()") -Reported-by: kernel test robot -Signed-off-by: Easwar Hariharan -Signed-off-by: Thomas Gleixner -Cc: stable@vger.kernel.org -Link: https://lore.kernel.org/all/20250130192701.99626-1-eahariha@linux.microsoft.com -Closes: https://lore.kernel.org/oe-kbuild-all/202501301334.NB6NszQR-lkp@intel.com/ ---- - 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) diff --git a/target/linux/generic/backport-6.12/400-v6.14-mtd-spinand-add-support-for-FORESEE-F35SQA001G.patch b/target/linux/generic/backport-6.12/400-v6.14-mtd-spinand-add-support-for-FORESEE-F35SQA001G.patch new file mode 100644 index 0000000000..84b3b2afee --- /dev/null +++ b/target/linux/generic/backport-6.12/400-v6.14-mtd-spinand-add-support-for-FORESEE-F35SQA001G.patch @@ -0,0 +1,38 @@ +From ae461cde5c559675fc4c0ba351c7c31ace705f56 Mon Sep 17 00:00:00 2001 +From: Bohdan Chubuk +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. + +Signed-off-by: Bohdan Chubuk +Signed-off-by: Miquel Raynal +--- + 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 = { diff --git a/target/linux/generic/backport-6.12/410-01-v6.14-mtd-rawnand-qcom-cleanup-qcom_nandc-driver.patch b/target/linux/generic/backport-6.12/410-01-v6.14-mtd-rawnand-qcom-cleanup-qcom_nandc-driver.patch new file mode 100644 index 0000000000..8c5457a507 --- /dev/null +++ b/target/linux/generic/backport-6.12/410-01-v6.14-mtd-rawnand-qcom-cleanup-qcom_nandc-driver.patch @@ -0,0 +1,1013 @@ +From 8c52932da5e6756fa66f52f0720da283fba13aa6 Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +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 + +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + 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, + }; + diff --git a/target/linux/generic/backport-6.12/410-02-v6.14-mtd-rawnand-qcom-Add-qcom-prefix-to-common-api.patch b/target/linux/generic/backport-6.12/410-02-v6.14-mtd-rawnand-qcom-Add-qcom-prefix-to-common-api.patch new file mode 100644 index 0000000000..078a56cf16 --- /dev/null +++ b/target/linux/generic/backport-6.12/410-02-v6.14-mtd-rawnand-qcom-Add-qcom-prefix-to-common-api.patch @@ -0,0 +1,880 @@ +From 1d479f5b345e0c3650fec4dddeef9fc6fab30c8b Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +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. + +Reviewed-by: Konrad Dybcio +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + 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"); diff --git a/target/linux/generic/backport-6.12/410-03-v6.14-mtd-nand-Add-qpic_common-API-file.patch b/target/linux/generic/backport-6.12/410-03-v6.14-mtd-nand-Add-qpic_common-API-file.patch new file mode 100644 index 0000000000..26211461c1 --- /dev/null +++ b/target/linux/generic/backport-6.12/410-03-v6.14-mtd-nand-Add-qpic_common-API-file.patch @@ -0,0 +1,2436 @@ +From fdf3ee5c6e5278dab4f60b998b47ed2d510bf80f Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +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. + +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * 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 + #include + #include +- +-/* 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 + + /* + * 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. ++ * Authors: Md sadre Alam ++ * ++ */ ++#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 ++ diff --git a/target/linux/generic/backport-6.12/410-04-v6.14-mtd-rawnand-qcom-use-FIELD_PREP-and-GENMASK.patch b/target/linux/generic/backport-6.12/410-04-v6.14-mtd-rawnand-qcom-use-FIELD_PREP-and-GENMASK.patch new file mode 100644 index 0000000000..b37507409a --- /dev/null +++ b/target/linux/generic/backport-6.12/410-04-v6.14-mtd-rawnand-qcom-use-FIELD_PREP-and-GENMASK.patch @@ -0,0 +1,198 @@ +From 0c08080fd71cd5dd59643104b39d3c89d793ab3c Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +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. + +Reviewed-by: Konrad Dybcio +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + 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 diff --git a/target/linux/generic/backport-6.12/410-05-v6.14-mtd-rawnand-qcom-fix-broken-config-in-qcom_param_pag.patch b/target/linux/generic/backport-6.12/410-05-v6.14-mtd-rawnand-qcom-fix-broken-config-in-qcom_param_pag.patch new file mode 100644 index 0000000000..a6a4db229f --- /dev/null +++ b/target/linux/generic/backport-6.12/410-05-v6.14-mtd-rawnand-qcom-fix-broken-config-in-qcom_param_pag.patch @@ -0,0 +1,64 @@ +From 9d4ffbcfde283f2a87ea45128ddf7e6651facdd9 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +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. + +Cc: stable@vger.kernel.org +Fixes: 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK") +Signed-off-by: Christian Marangi +--- + 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); diff --git a/target/linux/generic/backport-6.12/410-06-v6.14-mtd-rawnand-qcom-Fix-build-issue-on-x86-architecture.patch b/target/linux/generic/backport-6.12/410-06-v6.14-mtd-rawnand-qcom-Fix-build-issue-on-x86-architecture.patch new file mode 100644 index 0000000000..67beed38d5 --- /dev/null +++ b/target/linux/generic/backport-6.12/410-06-v6.14-mtd-rawnand-qcom-Fix-build-issue-on-x86-architecture.patch @@ -0,0 +1,77 @@ +From b9371866799d67a80be0ea9e01bd41987db22f26 Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +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") +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + 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; ++ ++ ); + }; + + /* diff --git a/target/linux/generic/backport-6.12/410-07-v6.15-spi-spi-qpic-add-driver-for-QCOM-SPI-NAND-flash-Inte.patch b/target/linux/generic/backport-6.12/410-07-v6.15-spi-spi-qpic-add-driver-for-QCOM-SPI-NAND-flash-Inte.patch new file mode 100644 index 0000000000..310d90233f --- /dev/null +++ b/target/linux/generic/backport-6.12/410-07-v6.15-spi-spi-qpic-add-driver-for-QCOM-SPI-NAND-flash-Inte.patch @@ -0,0 +1,1737 @@ +From 7304d1909080ef0c9da703500a97f46c98393fcd Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +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. + +Co-developed-by: Sricharan Ramabadhran +Signed-off-by: Sricharan Ramabadhran +Co-developed-by: Varadarajan Narayanan +Signed-off-by: Varadarajan Narayanan +Signed-off-by: Md Sadre Alam +Link: https://patch.msgid.link/20250224111414.2809669-3-quic_mdalam@quicinc.com +Signed-off-by: Mark Brown +--- + 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: ++ * Md Sadre Alam ++ * Sricharan R ++ * Varadarajan Narayanan ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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_AUTHOR("Md Sadre Alam "); ++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 { diff --git a/target/linux/generic/backport-6.12/410-08-v6.15-spi-spi-qpic-snand-Fix-ECC_CFG_ECC_DISABLE-shift-in-.patch b/target/linux/generic/backport-6.12/410-08-v6.15-spi-spi-qpic-snand-Fix-ECC_CFG_ECC_DISABLE-shift-in-.patch new file mode 100644 index 0000000000..ad43f8dff1 --- /dev/null +++ b/target/linux/generic/backport-6.12/410-08-v6.15-spi-spi-qpic-snand-Fix-ECC_CFG_ECC_DISABLE-shift-in-.patch @@ -0,0 +1,28 @@ +From cf1ba3cb245020459f2ca446b7a7b199839f5d83 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +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") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/2f4b0a0b-2c03-41c0-8a4a-3d789a83832d@stanley.mountain +Signed-off-by: Mark Brown +--- + 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); diff --git a/target/linux/generic/backport-6.12/410-09-v6.15-spi-spi-qpic-snand-avoid-memleak-in-qcom_spi_ecc_ini.patch b/target/linux/generic/backport-6.12/410-09-v6.15-spi-spi-qpic-snand-avoid-memleak-in-qcom_spi_ecc_ini.patch new file mode 100644 index 0000000000..1e2a3b0298 --- /dev/null +++ b/target/linux/generic/backport-6.12/410-09-v6.15-spi-spi-qpic-snand-avoid-memleak-in-qcom_spi_ecc_ini.patch @@ -0,0 +1,35 @@ +From d450cdd9c4398add1f2aa7200f2c95f1e3b9f9fa Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +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") +Signed-off-by: Gabor Juhos +Link: https://patch.msgid.link/20250313-qpic-snand-memleak-fix-v1-1-e54e78d1da3a@gmail.com +Signed-off-by: Mark Brown +--- + 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); + diff --git a/target/linux/generic/backport-6.12/410-10-v6.15-spi-SPI_QPIC_SNAND-should-be-tristate-and-depend-on-.patch b/target/linux/generic/backport-6.12/410-10-v6.15-spi-SPI_QPIC_SNAND-should-be-tristate-and-depend-on-.patch new file mode 100644 index 0000000000..5e92048438 --- /dev/null +++ b/target/linux/generic/backport-6.12/410-10-v6.15-spi-SPI_QPIC_SNAND-should-be-tristate-and-depend-on-.patch @@ -0,0 +1,49 @@ +From d32c4e58545f17caaa854415f854691e32d42075 Mon Sep 17 00:00:00 2001 +From: Geert Uytterhoeven +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") +Signed-off-by: Geert Uytterhoeven +Link: https://patch.msgid.link/b63db431cbf35223a4400e44c296293d32c4543c.1742998909.git.geert+renesas@glider.be +Signed-off-by: Mark Brown +--- + 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 = { diff --git a/target/linux/generic/backport-6.12/410-11-v6.15-spi-spi-qpic-snand-propagate-errors-from-qcom_spi_block_erase.patch b/target/linux/generic/backport-6.12/410-11-v6.15-spi-spi-qpic-snand-propagate-errors-from-qcom_spi_block_erase.patch new file mode 100644 index 0000000000..9da531bed1 --- /dev/null +++ b/target/linux/generic/backport-6.12/410-11-v6.15-spi-spi-qpic-snand-propagate-errors-from-qcom_spi_block_erase.patch @@ -0,0 +1,36 @@ +From: Gabor Juhos +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") +Signed-off-by: Gabor Juhos +Reviewed-by: Abel Vesa +Reviewed-by: Md Sadre Alam +--- + 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; + } diff --git a/target/linux/generic/backport-6.12/410-12-v6.15-spi-spi-qpic-snand-fix-NAND_READ_LOCATION_2-register-handling.patch b/target/linux/generic/backport-6.12/410-12-v6.15-spi-spi-qpic-snand-fix-NAND_READ_LOCATION_2-register-handling.patch new file mode 100644 index 0000000000..a2cd636fee --- /dev/null +++ b/target/linux/generic/backport-6.12/410-12-v6.15-spi-spi-qpic-snand-fix-NAND_READ_LOCATION_2-register-handling.patch @@ -0,0 +1,35 @@ +From: Gabor Juhos +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") +Signed-off-by: Gabor Juhos +Reviewed-by: Md Sadre Alam +--- + 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; + } diff --git a/target/linux/generic/backport-6.12/410-13-v6.15-spi-spi-qpic-snand-use-kmalloc-for-OOB-buffer-alloca.patch b/target/linux/generic/backport-6.12/410-13-v6.15-spi-spi-qpic-snand-use-kmalloc-for-OOB-buffer-alloca.patch new file mode 100644 index 0000000000..5a3d498bcb --- /dev/null +++ b/target/linux/generic/backport-6.12/410-13-v6.15-spi-spi-qpic-snand-use-kmalloc-for-OOB-buffer-alloca.patch @@ -0,0 +1,29 @@ +From f48d80503504257682e493dc17408f2f0b47bcfa Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +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. + +Signed-off-by: Gabor Juhos +Link: https://patch.msgid.link/20250320-qpic-snand-kmalloc-v1-1-94e267550675@gmail.com +Signed-off-by: Mark Brown +--- + 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); diff --git a/target/linux/generic/backport-6.12/410-14-v6.16-spi-spi-qpic-snand-remove-unused-wlen-member-of-struct-qpic_spi_nand.patch b/target/linux/generic/backport-6.12/410-14-v6.16-spi-spi-qpic-snand-remove-unused-wlen-member-of-struct-qpic_spi_nand.patch new file mode 100644 index 0000000000..55e84daf09 --- /dev/null +++ b/target/linux/generic/backport-6.12/410-14-v6.16-spi-spi-qpic-snand-remove-unused-wlen-member-of-struct-qpic_spi_nand.patch @@ -0,0 +1,30 @@ +From: Gabor Juhos +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. + +Signed-off-by: Gabor Juhos +--- + 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; diff --git a/target/linux/generic/backport-6.12/410-v6.13-01-block-add-support-for-defining-read-only-partitions.patch b/target/linux/generic/backport-6.12/410-v6.13-01-block-add-support-for-defining-read-only-partitions.patch deleted file mode 100644 index 7dd0031264..0000000000 --- a/target/linux/generic/backport-6.12/410-v6.13-01-block-add-support-for-defining-read-only-partitions.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 03cb793b26834ddca170ba87057c8f883772dd45 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -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. - -Signed-off-by: Christian Marangi -Reviewed-by: Christoph Hellwig -Link: https://lore.kernel.org/r/20241002221306.4403-2-ansuelsmth@gmail.com -Signed-off-by: Jens Axboe ---- - 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) diff --git a/target/linux/generic/backport-6.12/410-v6.13-03-block-introduce-add_disk_fwnode.patch b/target/linux/generic/backport-6.12/410-v6.13-03-block-introduce-add_disk_fwnode.patch deleted file mode 100644 index b9fabe6742..0000000000 --- a/target/linux/generic/backport-6.12/410-v6.13-03-block-introduce-add_disk_fwnode.patch +++ /dev/null @@ -1,94 +0,0 @@ -From e5f587242b6072ffab4f4a084a459a59f3035873 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -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. - -Signed-off-by: Christian Marangi -Reviewed-by: Christoph Hellwig -Link: https://lore.kernel.org/r/20241002221306.4403-4-ansuelsmth@gmail.com -Signed-off-by: Jens Axboe ---- - 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) diff --git a/target/linux/generic/backport-6.12/410-v6.13-04-mmc-block-attach-partitions-fwnode-if-found-in-mmc-c.patch b/target/linux/generic/backport-6.12/410-v6.13-04-mmc-block-attach-partitions-fwnode-if-found-in-mmc-c.patch deleted file mode 100644 index 0bdeaa85e4..0000000000 --- a/target/linux/generic/backport-6.12/410-v6.13-04-mmc-block-attach-partitions-fwnode-if-found-in-mmc-c.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 45ff6c340ddfc2dade74d5b7a8962c778ab7042c Mon Sep 17 00:00:00 2001 -From: Christian Marangi -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. - -Signed-off-by: Christian Marangi -Reviewed-by: Linus Walleij -Link: https://lore.kernel.org/r/20241002221306.4403-5-ansuelsmth@gmail.com -Signed-off-by: Jens Axboe ---- - 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; diff --git a/target/linux/generic/backport-6.12/410-v6.13-05-block-add-support-for-partition-table-defined-in-OF.patch b/target/linux/generic/backport-6.12/410-v6.13-05-block-add-support-for-partition-table-defined-in-OF.patch deleted file mode 100644 index d260be168c..0000000000 --- a/target/linux/generic/backport-6.12/410-v6.13-05-block-add-support-for-partition-table-defined-in-OF.patch +++ /dev/null @@ -1,200 +0,0 @@ -From 884555b557e5e6d41c866e2cd8d7b32f50ec974b Mon Sep 17 00:00:00 2001 -From: Christian Marangi -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. - -Signed-off-by: Christian Marangi -Reviewed-by: Christoph Hellwig -Link: https://lore.kernel.org/r/20241002221306.4403-6-ansuelsmth@gmail.com -Signed-off-by: Jens Axboe ---- - 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 -+#include -+#include -+#include -+#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; -+} diff --git a/target/linux/generic/backport-6.12/412-v6.14-mtd-spinand-add-support-for-FORESEE-F35SQA001G.patch b/target/linux/generic/backport-6.12/412-v6.14-mtd-spinand-add-support-for-FORESEE-F35SQA001G.patch deleted file mode 100644 index 84b3b2afee..0000000000 --- a/target/linux/generic/backport-6.12/412-v6.14-mtd-spinand-add-support-for-FORESEE-F35SQA001G.patch +++ /dev/null @@ -1,38 +0,0 @@ -From ae461cde5c559675fc4c0ba351c7c31ace705f56 Mon Sep 17 00:00:00 2001 -From: Bohdan Chubuk -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. - -Signed-off-by: Bohdan Chubuk -Signed-off-by: Miquel Raynal ---- - 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 = { diff --git a/target/linux/generic/backport-6.12/413-01-v6.14-mtd-rawnand-qcom-cleanup-qcom_nandc-driver.patch b/target/linux/generic/backport-6.12/413-01-v6.14-mtd-rawnand-qcom-cleanup-qcom_nandc-driver.patch deleted file mode 100644 index 8c5457a507..0000000000 --- a/target/linux/generic/backport-6.12/413-01-v6.14-mtd-rawnand-qcom-cleanup-qcom_nandc-driver.patch +++ /dev/null @@ -1,1013 +0,0 @@ -From 8c52932da5e6756fa66f52f0720da283fba13aa6 Mon Sep 17 00:00:00 2001 -From: Md Sadre Alam -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 - -Signed-off-by: Md Sadre Alam -Signed-off-by: Miquel Raynal ---- - 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, - }; - diff --git a/target/linux/generic/backport-6.12/413-02-v6.14-mtd-rawnand-qcom-Add-qcom-prefix-to-common-api.patch b/target/linux/generic/backport-6.12/413-02-v6.14-mtd-rawnand-qcom-Add-qcom-prefix-to-common-api.patch deleted file mode 100644 index 078a56cf16..0000000000 --- a/target/linux/generic/backport-6.12/413-02-v6.14-mtd-rawnand-qcom-Add-qcom-prefix-to-common-api.patch +++ /dev/null @@ -1,880 +0,0 @@ -From 1d479f5b345e0c3650fec4dddeef9fc6fab30c8b Mon Sep 17 00:00:00 2001 -From: Md Sadre Alam -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. - -Reviewed-by: Konrad Dybcio -Signed-off-by: Md Sadre Alam -Signed-off-by: Miquel Raynal ---- - 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"); diff --git a/target/linux/generic/backport-6.12/413-03-v6.14-mtd-nand-Add-qpic_common-API-file.patch b/target/linux/generic/backport-6.12/413-03-v6.14-mtd-nand-Add-qpic_common-API-file.patch deleted file mode 100644 index 26211461c1..0000000000 --- a/target/linux/generic/backport-6.12/413-03-v6.14-mtd-nand-Add-qpic_common-API-file.patch +++ /dev/null @@ -1,2436 +0,0 @@ -From fdf3ee5c6e5278dab4f60b998b47ed2d510bf80f Mon Sep 17 00:00:00 2001 -From: Md Sadre Alam -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. - -Signed-off-by: Md Sadre Alam -Signed-off-by: Miquel Raynal ---- - 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/** -+ * 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 - #include - #include -- --/* 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 - - /* - * 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. -+ * Authors: Md sadre Alam -+ * -+ */ -+#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 -+ diff --git a/target/linux/generic/backport-6.12/413-04-v6.14-mtd-rawnand-qcom-use-FIELD_PREP-and-GENMASK.patch b/target/linux/generic/backport-6.12/413-04-v6.14-mtd-rawnand-qcom-use-FIELD_PREP-and-GENMASK.patch deleted file mode 100644 index b37507409a..0000000000 --- a/target/linux/generic/backport-6.12/413-04-v6.14-mtd-rawnand-qcom-use-FIELD_PREP-and-GENMASK.patch +++ /dev/null @@ -1,198 +0,0 @@ -From 0c08080fd71cd5dd59643104b39d3c89d793ab3c Mon Sep 17 00:00:00 2001 -From: Md Sadre Alam -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. - -Reviewed-by: Konrad Dybcio -Signed-off-by: Md Sadre Alam -Signed-off-by: Miquel Raynal ---- - 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 diff --git a/target/linux/generic/backport-6.12/414-v6.14-mtd-rawnand-qcom-fix-broken-config-in-qcom_param_pag.patch b/target/linux/generic/backport-6.12/414-v6.14-mtd-rawnand-qcom-fix-broken-config-in-qcom_param_pag.patch deleted file mode 100644 index a6a4db229f..0000000000 --- a/target/linux/generic/backport-6.12/414-v6.14-mtd-rawnand-qcom-fix-broken-config-in-qcom_param_pag.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 9d4ffbcfde283f2a87ea45128ddf7e6651facdd9 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -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. - -Cc: stable@vger.kernel.org -Fixes: 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK") -Signed-off-by: Christian Marangi ---- - 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); diff --git a/target/linux/generic/backport-6.12/415-v6.14-mtd-rawnand-qcom-Fix-build-issue-on-x86-architecture.patch b/target/linux/generic/backport-6.12/415-v6.14-mtd-rawnand-qcom-Fix-build-issue-on-x86-architecture.patch deleted file mode 100644 index 67beed38d5..0000000000 --- a/target/linux/generic/backport-6.12/415-v6.14-mtd-rawnand-qcom-Fix-build-issue-on-x86-architecture.patch +++ /dev/null @@ -1,77 +0,0 @@ -From b9371866799d67a80be0ea9e01bd41987db22f26 Mon Sep 17 00:00:00 2001 -From: Md Sadre Alam -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") -Signed-off-by: Md Sadre Alam -Signed-off-by: Miquel Raynal ---- - 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; -+ -+ ); - }; - - /* diff --git a/target/linux/generic/backport-6.12/416-v6.15-01-spi-spi-qpic-add-driver-for-QCOM-SPI-NAND-flash-Inte.patch b/target/linux/generic/backport-6.12/416-v6.15-01-spi-spi-qpic-add-driver-for-QCOM-SPI-NAND-flash-Inte.patch deleted file mode 100644 index 310d90233f..0000000000 --- a/target/linux/generic/backport-6.12/416-v6.15-01-spi-spi-qpic-add-driver-for-QCOM-SPI-NAND-flash-Inte.patch +++ /dev/null @@ -1,1737 +0,0 @@ -From 7304d1909080ef0c9da703500a97f46c98393fcd Mon Sep 17 00:00:00 2001 -From: Md Sadre Alam -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. - -Co-developed-by: Sricharan Ramabadhran -Signed-off-by: Sricharan Ramabadhran -Co-developed-by: Varadarajan Narayanan -Signed-off-by: Varadarajan Narayanan -Signed-off-by: Md Sadre Alam -Link: https://patch.msgid.link/20250224111414.2809669-3-quic_mdalam@quicinc.com -Signed-off-by: Mark Brown ---- - 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: -+ * Md Sadre Alam -+ * Sricharan R -+ * Varadarajan Narayanan -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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_AUTHOR("Md Sadre Alam "); -+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 { diff --git a/target/linux/generic/backport-6.12/416-v6.15-02-spi-spi-qpic-snand-Fix-ECC_CFG_ECC_DISABLE-shift-in-.patch b/target/linux/generic/backport-6.12/416-v6.15-02-spi-spi-qpic-snand-Fix-ECC_CFG_ECC_DISABLE-shift-in-.patch deleted file mode 100644 index ad43f8dff1..0000000000 --- a/target/linux/generic/backport-6.12/416-v6.15-02-spi-spi-qpic-snand-Fix-ECC_CFG_ECC_DISABLE-shift-in-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From cf1ba3cb245020459f2ca446b7a7b199839f5d83 Mon Sep 17 00:00:00 2001 -From: Dan Carpenter -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") -Signed-off-by: Dan Carpenter -Link: https://patch.msgid.link/2f4b0a0b-2c03-41c0-8a4a-3d789a83832d@stanley.mountain -Signed-off-by: Mark Brown ---- - 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); diff --git a/target/linux/generic/backport-6.12/416-v6.15-03-spi-spi-qpic-snand-avoid-memleak-in-qcom_spi_ecc_ini.patch b/target/linux/generic/backport-6.12/416-v6.15-03-spi-spi-qpic-snand-avoid-memleak-in-qcom_spi_ecc_ini.patch deleted file mode 100644 index 1e2a3b0298..0000000000 --- a/target/linux/generic/backport-6.12/416-v6.15-03-spi-spi-qpic-snand-avoid-memleak-in-qcom_spi_ecc_ini.patch +++ /dev/null @@ -1,35 +0,0 @@ -From d450cdd9c4398add1f2aa7200f2c95f1e3b9f9fa Mon Sep 17 00:00:00 2001 -From: Gabor Juhos -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") -Signed-off-by: Gabor Juhos -Link: https://patch.msgid.link/20250313-qpic-snand-memleak-fix-v1-1-e54e78d1da3a@gmail.com -Signed-off-by: Mark Brown ---- - 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); - diff --git a/target/linux/generic/backport-6.12/416-v6.15-04-spi-SPI_QPIC_SNAND-should-be-tristate-and-depend-on-.patch b/target/linux/generic/backport-6.12/416-v6.15-04-spi-SPI_QPIC_SNAND-should-be-tristate-and-depend-on-.patch deleted file mode 100644 index 5e92048438..0000000000 --- a/target/linux/generic/backport-6.12/416-v6.15-04-spi-SPI_QPIC_SNAND-should-be-tristate-and-depend-on-.patch +++ /dev/null @@ -1,49 +0,0 @@ -From d32c4e58545f17caaa854415f854691e32d42075 Mon Sep 17 00:00:00 2001 -From: Geert Uytterhoeven -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") -Signed-off-by: Geert Uytterhoeven -Link: https://patch.msgid.link/b63db431cbf35223a4400e44c296293d32c4543c.1742998909.git.geert+renesas@glider.be -Signed-off-by: Mark Brown ---- - 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 = { diff --git a/target/linux/generic/backport-6.12/416-v6.15-05-spi-spi-qpic-snand-propagate-errors-from-qcom_spi_block_erase.patch b/target/linux/generic/backport-6.12/416-v6.15-05-spi-spi-qpic-snand-propagate-errors-from-qcom_spi_block_erase.patch deleted file mode 100644 index 9da531bed1..0000000000 --- a/target/linux/generic/backport-6.12/416-v6.15-05-spi-spi-qpic-snand-propagate-errors-from-qcom_spi_block_erase.patch +++ /dev/null @@ -1,36 +0,0 @@ -From: Gabor Juhos -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") -Signed-off-by: Gabor Juhos -Reviewed-by: Abel Vesa -Reviewed-by: Md Sadre Alam ---- - 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; - } diff --git a/target/linux/generic/backport-6.12/416-v6.15-06-spi-spi-qpic-snand-fix-NAND_READ_LOCATION_2-register-handling.patch b/target/linux/generic/backport-6.12/416-v6.15-06-spi-spi-qpic-snand-fix-NAND_READ_LOCATION_2-register-handling.patch deleted file mode 100644 index a2cd636fee..0000000000 --- a/target/linux/generic/backport-6.12/416-v6.15-06-spi-spi-qpic-snand-fix-NAND_READ_LOCATION_2-register-handling.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: Gabor Juhos -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") -Signed-off-by: Gabor Juhos -Reviewed-by: Md Sadre Alam ---- - 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; - } diff --git a/target/linux/generic/backport-6.12/416-v6.15-07-spi-spi-qpic-snand-use-kmalloc-for-OOB-buffer-alloca.patch b/target/linux/generic/backport-6.12/416-v6.15-07-spi-spi-qpic-snand-use-kmalloc-for-OOB-buffer-alloca.patch deleted file mode 100644 index 5a3d498bcb..0000000000 --- a/target/linux/generic/backport-6.12/416-v6.15-07-spi-spi-qpic-snand-use-kmalloc-for-OOB-buffer-alloca.patch +++ /dev/null @@ -1,29 +0,0 @@ -From f48d80503504257682e493dc17408f2f0b47bcfa Mon Sep 17 00:00:00 2001 -From: Gabor Juhos -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. - -Signed-off-by: Gabor Juhos -Link: https://patch.msgid.link/20250320-qpic-snand-kmalloc-v1-1-94e267550675@gmail.com -Signed-off-by: Mark Brown ---- - 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); diff --git a/target/linux/generic/backport-6.12/416-v6.16-08-spi-spi-qpic-snand-remove-unused-wlen-member-of-struct-qpic_spi_nand.patch b/target/linux/generic/backport-6.12/416-v6.16-08-spi-spi-qpic-snand-remove-unused-wlen-member-of-struct-qpic_spi_nand.patch deleted file mode 100644 index 55e84daf09..0000000000 --- a/target/linux/generic/backport-6.12/416-v6.16-08-spi-spi-qpic-snand-remove-unused-wlen-member-of-struct-qpic_spi_nand.patch +++ /dev/null @@ -1,30 +0,0 @@ -From: Gabor Juhos -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. - -Signed-off-by: Gabor Juhos ---- - 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; diff --git a/target/linux/generic/backport-6.12/500-01-v6.13-block-add-support-for-defining-read-only-partitions.patch b/target/linux/generic/backport-6.12/500-01-v6.13-block-add-support-for-defining-read-only-partitions.patch new file mode 100644 index 0000000000..7dd0031264 --- /dev/null +++ b/target/linux/generic/backport-6.12/500-01-v6.13-block-add-support-for-defining-read-only-partitions.patch @@ -0,0 +1,53 @@ +From 03cb793b26834ddca170ba87057c8f883772dd45 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +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. + +Signed-off-by: Christian Marangi +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/20241002221306.4403-2-ansuelsmth@gmail.com +Signed-off-by: Jens Axboe +--- + 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) diff --git a/target/linux/generic/backport-6.12/500-02-v6.13-block-introduce-add_disk_fwnode.patch b/target/linux/generic/backport-6.12/500-02-v6.13-block-introduce-add_disk_fwnode.patch new file mode 100644 index 0000000000..b9fabe6742 --- /dev/null +++ b/target/linux/generic/backport-6.12/500-02-v6.13-block-introduce-add_disk_fwnode.patch @@ -0,0 +1,94 @@ +From e5f587242b6072ffab4f4a084a459a59f3035873 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +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. + +Signed-off-by: Christian Marangi +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/20241002221306.4403-4-ansuelsmth@gmail.com +Signed-off-by: Jens Axboe +--- + 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) diff --git a/target/linux/generic/backport-6.12/500-03-v6.13-mmc-block-attach-partitions-fwnode-if-found-in-mmc-c.patch b/target/linux/generic/backport-6.12/500-03-v6.13-mmc-block-attach-partitions-fwnode-if-found-in-mmc-c.patch new file mode 100644 index 0000000000..0bdeaa85e4 --- /dev/null +++ b/target/linux/generic/backport-6.12/500-03-v6.13-mmc-block-attach-partitions-fwnode-if-found-in-mmc-c.patch @@ -0,0 +1,104 @@ +From 45ff6c340ddfc2dade74d5b7a8962c778ab7042c Mon Sep 17 00:00:00 2001 +From: Christian Marangi +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. + +Signed-off-by: Christian Marangi +Reviewed-by: Linus Walleij +Link: https://lore.kernel.org/r/20241002221306.4403-5-ansuelsmth@gmail.com +Signed-off-by: Jens Axboe +--- + 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; diff --git a/target/linux/generic/backport-6.12/500-04-v6.13-block-add-support-for-partition-table-defined-in-OF.patch b/target/linux/generic/backport-6.12/500-04-v6.13-block-add-support-for-partition-table-defined-in-OF.patch new file mode 100644 index 0000000000..d260be168c --- /dev/null +++ b/target/linux/generic/backport-6.12/500-04-v6.13-block-add-support-for-partition-table-defined-in-OF.patch @@ -0,0 +1,200 @@ +From 884555b557e5e6d41c866e2cd8d7b32f50ec974b Mon Sep 17 00:00:00 2001 +From: Christian Marangi +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. + +Signed-off-by: Christian Marangi +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/20241002221306.4403-6-ansuelsmth@gmail.com +Signed-off-by: Jens Axboe +--- + 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 ++#include ++#include ++#include ++#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; ++} diff --git a/target/linux/generic/backport-6.12/600-01-v6.14-net-dsa-add-hook-to-determine-whether-EEE-is-support.patch b/target/linux/generic/backport-6.12/600-01-v6.14-net-dsa-add-hook-to-determine-whether-EEE-is-support.patch new file mode 100644 index 0000000000..446f918fa0 --- /dev/null +++ b/target/linux/generic/backport-6.12/600-01-v6.14-net-dsa-add-hook-to-determine-whether-EEE-is-support.patch @@ -0,0 +1,54 @@ +From 9723a77318b7c0cfd06ea207e52a042f8c815318 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +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. + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Florian Fainelli +Reviewed-by: Vladimir Oltean +Link: https://patch.msgid.link/E1tL144-006cZD-El@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + 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; diff --git a/target/linux/generic/backport-6.12/600-02-v6.14-net-dsa-provide-implementation-of-.support_eee.patch b/target/linux/generic/backport-6.12/600-02-v6.14-net-dsa-provide-implementation-of-.support_eee.patch new file mode 100644 index 0000000000..d7342daa0b --- /dev/null +++ b/target/linux/generic/backport-6.12/600-02-v6.14-net-dsa-provide-implementation-of-.support_eee.patch @@ -0,0 +1,53 @@ +From 99379f587278c818777cb4778e2c79c6c1440c65 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +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. + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Florian Fainelli +Reviewed-by: Vladimir Oltean +Link: https://patch.msgid.link/E1tL149-006cZJ-JJ@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + 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) diff --git a/target/linux/generic/backport-6.12/610-01-v6.13-net-dsa-use-ethtool-string-helpers.patch b/target/linux/generic/backport-6.12/610-01-v6.13-net-dsa-use-ethtool-string-helpers.patch new file mode 100644 index 0000000000..003a896f30 --- /dev/null +++ b/target/linux/generic/backport-6.12/610-01-v6.13-net-dsa-use-ethtool-string-helpers.patch @@ -0,0 +1,30 @@ +From f12b363887c706c40611fba645265527a8415832 Mon Sep 17 00:00:00 2001 +From: Rosen Penev +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. + +Signed-off-by: Rosen Penev +(for hellcreek driver) +Reviewed-by: Kurt Kanzenbach +Link: https://patch.msgid.link/20241028044828.1639668-1-rosenp@gmail.com +Signed-off-by: Jakub Kicinski +--- + 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) diff --git a/target/linux/generic/backport-6.12/610-02-v6.14-net-dsa-b53-bcm_sf2-implement-.support_eee-method.patch b/target/linux/generic/backport-6.12/610-02-v6.14-net-dsa-b53-bcm_sf2-implement-.support_eee-method.patch new file mode 100644 index 0000000000..ca0f61013c --- /dev/null +++ b/target/linux/generic/backport-6.12/610-02-v6.14-net-dsa-b53-bcm_sf2-implement-.support_eee-method.patch @@ -0,0 +1,69 @@ +From c86692fc2cb77d94dd8c166c2b9017f196d02a84 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +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. + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Florian Fainelli +Reviewed-by: Vladimir Oltean +Link: https://patch.msgid.link/E1tL14E-006cZU-Nc@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + 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); + diff --git a/target/linux/generic/backport-6.12/610-03-v6.15-net-dsa-b53-mdio-add-support-for-BCM53101.patch b/target/linux/generic/backport-6.12/610-03-v6.15-net-dsa-b53-mdio-add-support-for-BCM53101.patch new file mode 100644 index 0000000000..900117af5e --- /dev/null +++ b/target/linux/generic/backport-6.12/610-03-v6.15-net-dsa-b53-mdio-add-support-for-BCM53101.patch @@ -0,0 +1,76 @@ +From c4f873c2b65c839ff5e7c996bd9ef5a1e7eae11a Mon Sep 17 00:00:00 2001 +From: Torben Nielsen +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. + +Signed-off-by: Torben Nielsen +Signed-off-by: Claus Stovgaard +Link: https://patch.msgid.link/20250217080503.1390282-1-claus.stovgaard@gmail.com +Signed-off-by: Jakub Kicinski +--- + 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; + } diff --git a/target/linux/generic/backport-6.12/610-04-v6.16-net-dsa-b53-implement-setting-ageing-time.patch b/target/linux/generic/backport-6.12/610-04-v6.16-net-dsa-b53-implement-setting-ageing-time.patch new file mode 100644 index 0000000000..75b5b040fd --- /dev/null +++ b/target/linux/generic/backport-6.12/610-04-v6.16-net-dsa-b53-implement-setting-ageing-time.patch @@ -0,0 +1,105 @@ +From e39d14a760c039af0653e3df967e7525413924a0 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +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. + +Signed-off-by: Jonas Gorski +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250510092211.276541-1-jonas.gorski@gmail.com +Signed-off-by: Jakub Kicinski +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 diff --git a/target/linux/generic/backport-6.12/610-05-v6.16-net-dsa-b53-do-not-enable-EEE-on-bcm63xx.patch b/target/linux/generic/backport-6.12/610-05-v6.16-net-dsa-b53-do-not-enable-EEE-on-bcm63xx.patch new file mode 100644 index 0000000000..9a53b709af --- /dev/null +++ b/target/linux/generic/backport-6.12/610-05-v6.16-net-dsa-b53-do-not-enable-EEE-on-bcm63xx.patch @@ -0,0 +1,47 @@ +From 1237c2d4a8db79dfd4369bff6930b0e385ed7d5c Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +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") +Reviewed-by: Florian Fainelli +Tested-by: Álvaro Fernández Rojas +Signed-off-by: Jonas Gorski +Link: https://patch.msgid.link/20250602193953.1010487-2-jonas.gorski@gmail.com +Signed-off-by: Paolo Abeni +--- + 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); + diff --git a/target/linux/generic/backport-6.12/610-06-v6.16-net-dsa-b53-do-not-enable-RGMII-delay-on-bcm63xx.patch b/target/linux/generic/backport-6.12/610-06-v6.16-net-dsa-b53-do-not-enable-RGMII-delay-on-bcm63xx.patch new file mode 100644 index 0000000000..6f15ea3cdc --- /dev/null +++ b/target/linux/generic/backport-6.12/610-06-v6.16-net-dsa-b53-do-not-enable-RGMII-delay-on-bcm63xx.patch @@ -0,0 +1,49 @@ +From 4af523551d876ab8b8057d1e5303a860fd736fcb Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +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") +Signed-off-by: Jonas Gorski +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250602193953.1010487-3-jonas.gorski@gmail.com +Signed-off-by: Paolo Abeni +--- + 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)) diff --git a/target/linux/generic/backport-6.12/610-07-v6.16-net-dsa-b53-do-not-configure-bcm63xx-s-IMP-port-inte.patch b/target/linux/generic/backport-6.12/610-07-v6.16-net-dsa-b53-do-not-configure-bcm63xx-s-IMP-port-inte.patch new file mode 100644 index 0000000000..739e1b7030 --- /dev/null +++ b/target/linux/generic/backport-6.12/610-07-v6.16-net-dsa-b53-do-not-configure-bcm63xx-s-IMP-port-inte.patch @@ -0,0 +1,70 @@ +From 75f4f7b2b13008803f84768ff90396f9d7553221 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +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") +Signed-off-by: Jonas Gorski +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250602193953.1010487-4-jonas.gorski@gmail.com +Signed-off-by: Paolo Abeni +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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) { diff --git a/target/linux/generic/backport-6.12/610-08-v6.16-net-dsa-b53-allow-RGMII-for-bcm63xx-RGMII-ports.patch b/target/linux/generic/backport-6.12/610-08-v6.16-net-dsa-b53-allow-RGMII-for-bcm63xx-RGMII-ports.patch new file mode 100644 index 0000000000..9b74dd177e --- /dev/null +++ b/target/linux/generic/backport-6.12/610-08-v6.16-net-dsa-b53-allow-RGMII-for-bcm63xx-RGMII-ports.patch @@ -0,0 +1,36 @@ +From 5ea0d42c1980e6d10e5cb56a78021db5bfcebaaf Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +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") +Reviewed-by: Florian Fainelli +Signed-off-by: Jonas Gorski +Link: https://patch.msgid.link/20250602193953.1010487-5-jonas.gorski@gmail.com +Signed-off-by: Paolo Abeni +--- + 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; + diff --git a/target/linux/generic/backport-6.12/610-09-v6.16-net-dsa-b53-do-not-touch-DLL_IQQD-on-bcm53115.patch b/target/linux/generic/backport-6.12/610-09-v6.16-net-dsa-b53-do-not-touch-DLL_IQQD-on-bcm53115.patch new file mode 100644 index 0000000000..9f2143d816 --- /dev/null +++ b/target/linux/generic/backport-6.12/610-09-v6.16-net-dsa-b53-do-not-touch-DLL_IQQD-on-bcm53115.patch @@ -0,0 +1,59 @@ +From bc1a65eb81a21e2aa3c3dca058ee8adf687b6ef5 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +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") +Signed-off-by: Jonas Gorski +Link: https://patch.msgid.link/20250602193953.1010487-6-jonas.gorski@gmail.com +Signed-off-by: Paolo Abeni +--- + 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, diff --git a/target/linux/generic/backport-6.12/611-v6.16-net-dsa-tag_brcm-legacy-fix-pskb_may_pull-length.patch b/target/linux/generic/backport-6.12/611-v6.16-net-dsa-tag_brcm-legacy-fix-pskb_may_pull-length.patch new file mode 100644 index 0000000000..9fa88d2d3f --- /dev/null +++ b/target/linux/generic/backport-6.12/611-v6.16-net-dsa-tag_brcm-legacy-fix-pskb_may_pull-length.patch @@ -0,0 +1,31 @@ +From efdddc4484859082da6c7877ed144c8121c8ea55 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +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") +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250529124406.2513779-1-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + 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); diff --git a/target/linux/generic/backport-6.12/700-01-v6.14-net-dsa-add-hook-to-determine-whether-EEE-is-support.patch b/target/linux/generic/backport-6.12/700-01-v6.14-net-dsa-add-hook-to-determine-whether-EEE-is-support.patch deleted file mode 100644 index 446f918fa0..0000000000 --- a/target/linux/generic/backport-6.12/700-01-v6.14-net-dsa-add-hook-to-determine-whether-EEE-is-support.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 9723a77318b7c0cfd06ea207e52a042f8c815318 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -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. - -Signed-off-by: Russell King (Oracle) -Reviewed-by: Florian Fainelli -Reviewed-by: Vladimir Oltean -Link: https://patch.msgid.link/E1tL144-006cZD-El@rmk-PC.armlinux.org.uk -Signed-off-by: Jakub Kicinski ---- - 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; diff --git a/target/linux/generic/backport-6.12/700-02-v6.14-net-dsa-provide-implementation-of-.support_eee.patch b/target/linux/generic/backport-6.12/700-02-v6.14-net-dsa-provide-implementation-of-.support_eee.patch deleted file mode 100644 index d7342daa0b..0000000000 --- a/target/linux/generic/backport-6.12/700-02-v6.14-net-dsa-provide-implementation-of-.support_eee.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 99379f587278c818777cb4778e2c79c6c1440c65 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -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. - -Signed-off-by: Russell King (Oracle) -Reviewed-by: Florian Fainelli -Reviewed-by: Vladimir Oltean -Link: https://patch.msgid.link/E1tL149-006cZJ-JJ@rmk-PC.armlinux.org.uk -Signed-off-by: Jakub Kicinski ---- - 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) diff --git a/target/linux/generic/backport-6.12/710-01-v6.13-net-dsa-use-ethtool-string-helpers.patch b/target/linux/generic/backport-6.12/710-01-v6.13-net-dsa-use-ethtool-string-helpers.patch deleted file mode 100644 index 003a896f30..0000000000 --- a/target/linux/generic/backport-6.12/710-01-v6.13-net-dsa-use-ethtool-string-helpers.patch +++ /dev/null @@ -1,30 +0,0 @@ -From f12b363887c706c40611fba645265527a8415832 Mon Sep 17 00:00:00 2001 -From: Rosen Penev -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. - -Signed-off-by: Rosen Penev -(for hellcreek driver) -Reviewed-by: Kurt Kanzenbach -Link: https://patch.msgid.link/20241028044828.1639668-1-rosenp@gmail.com -Signed-off-by: Jakub Kicinski ---- - 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) diff --git a/target/linux/generic/backport-6.12/710-02-v6.14-net-dsa-b53-bcm_sf2-implement-.support_eee-method.patch b/target/linux/generic/backport-6.12/710-02-v6.14-net-dsa-b53-bcm_sf2-implement-.support_eee-method.patch deleted file mode 100644 index ca0f61013c..0000000000 --- a/target/linux/generic/backport-6.12/710-02-v6.14-net-dsa-b53-bcm_sf2-implement-.support_eee-method.patch +++ /dev/null @@ -1,69 +0,0 @@ -From c86692fc2cb77d94dd8c166c2b9017f196d02a84 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -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. - -Signed-off-by: Russell King (Oracle) -Reviewed-by: Florian Fainelli -Reviewed-by: Vladimir Oltean -Link: https://patch.msgid.link/E1tL14E-006cZU-Nc@rmk-PC.armlinux.org.uk -Signed-off-by: Jakub Kicinski ---- - 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); - diff --git a/target/linux/generic/backport-6.12/710-03-v6.15-net-dsa-b53-mdio-add-support-for-BCM53101.patch b/target/linux/generic/backport-6.12/710-03-v6.15-net-dsa-b53-mdio-add-support-for-BCM53101.patch deleted file mode 100644 index 900117af5e..0000000000 --- a/target/linux/generic/backport-6.12/710-03-v6.15-net-dsa-b53-mdio-add-support-for-BCM53101.patch +++ /dev/null @@ -1,76 +0,0 @@ -From c4f873c2b65c839ff5e7c996bd9ef5a1e7eae11a Mon Sep 17 00:00:00 2001 -From: Torben Nielsen -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. - -Signed-off-by: Torben Nielsen -Signed-off-by: Claus Stovgaard -Link: https://patch.msgid.link/20250217080503.1390282-1-claus.stovgaard@gmail.com -Signed-off-by: Jakub Kicinski ---- - 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; - } diff --git a/target/linux/generic/backport-6.12/710-04-v6.16-net-dsa-b53-implement-setting-ageing-time.patch b/target/linux/generic/backport-6.12/710-04-v6.16-net-dsa-b53-implement-setting-ageing-time.patch deleted file mode 100644 index 75b5b040fd..0000000000 --- a/target/linux/generic/backport-6.12/710-04-v6.16-net-dsa-b53-implement-setting-ageing-time.patch +++ /dev/null @@ -1,105 +0,0 @@ -From e39d14a760c039af0653e3df967e7525413924a0 Mon Sep 17 00:00:00 2001 -From: Jonas Gorski -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. - -Signed-off-by: Jonas Gorski -Reviewed-by: Florian Fainelli -Link: https://patch.msgid.link/20250510092211.276541-1-jonas.gorski@gmail.com -Signed-off-by: Jakub Kicinski ---- - 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 - #include - #include -+#include - #include - #include - #include -@@ -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 diff --git a/target/linux/generic/backport-6.12/710-05-v6.16-net-dsa-b53-do-not-enable-EEE-on-bcm63xx.patch b/target/linux/generic/backport-6.12/710-05-v6.16-net-dsa-b53-do-not-enable-EEE-on-bcm63xx.patch deleted file mode 100644 index 9a53b709af..0000000000 --- a/target/linux/generic/backport-6.12/710-05-v6.16-net-dsa-b53-do-not-enable-EEE-on-bcm63xx.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 1237c2d4a8db79dfd4369bff6930b0e385ed7d5c Mon Sep 17 00:00:00 2001 -From: Jonas Gorski -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") -Reviewed-by: Florian Fainelli -Tested-by: Álvaro Fernández Rojas -Signed-off-by: Jonas Gorski -Link: https://patch.msgid.link/20250602193953.1010487-2-jonas.gorski@gmail.com -Signed-off-by: Paolo Abeni ---- - 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); - diff --git a/target/linux/generic/backport-6.12/710-06-v6.16-net-dsa-b53-do-not-enable-RGMII-delay-on-bcm63xx.patch b/target/linux/generic/backport-6.12/710-06-v6.16-net-dsa-b53-do-not-enable-RGMII-delay-on-bcm63xx.patch deleted file mode 100644 index 6f15ea3cdc..0000000000 --- a/target/linux/generic/backport-6.12/710-06-v6.16-net-dsa-b53-do-not-enable-RGMII-delay-on-bcm63xx.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 4af523551d876ab8b8057d1e5303a860fd736fcb Mon Sep 17 00:00:00 2001 -From: Jonas Gorski -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") -Signed-off-by: Jonas Gorski -Reviewed-by: Florian Fainelli -Link: https://patch.msgid.link/20250602193953.1010487-3-jonas.gorski@gmail.com -Signed-off-by: Paolo Abeni ---- - 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)) diff --git a/target/linux/generic/backport-6.12/710-07-v6.16-net-dsa-b53-do-not-configure-bcm63xx-s-IMP-port-inte.patch b/target/linux/generic/backport-6.12/710-07-v6.16-net-dsa-b53-do-not-configure-bcm63xx-s-IMP-port-inte.patch deleted file mode 100644 index 739e1b7030..0000000000 --- a/target/linux/generic/backport-6.12/710-07-v6.16-net-dsa-b53-do-not-configure-bcm63xx-s-IMP-port-inte.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 75f4f7b2b13008803f84768ff90396f9d7553221 Mon Sep 17 00:00:00 2001 -From: Jonas Gorski -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") -Signed-off-by: Jonas Gorski -Reviewed-by: Florian Fainelli -Link: https://patch.msgid.link/20250602193953.1010487-4-jonas.gorski@gmail.com -Signed-off-by: Paolo Abeni ---- - 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 - #include - #include -+#include - #include - #include - #include -@@ -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) { diff --git a/target/linux/generic/backport-6.12/710-08-v6.16-net-dsa-b53-allow-RGMII-for-bcm63xx-RGMII-ports.patch b/target/linux/generic/backport-6.12/710-08-v6.16-net-dsa-b53-allow-RGMII-for-bcm63xx-RGMII-ports.patch deleted file mode 100644 index 9b74dd177e..0000000000 --- a/target/linux/generic/backport-6.12/710-08-v6.16-net-dsa-b53-allow-RGMII-for-bcm63xx-RGMII-ports.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 5ea0d42c1980e6d10e5cb56a78021db5bfcebaaf Mon Sep 17 00:00:00 2001 -From: Jonas Gorski -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") -Reviewed-by: Florian Fainelli -Signed-off-by: Jonas Gorski -Link: https://patch.msgid.link/20250602193953.1010487-5-jonas.gorski@gmail.com -Signed-off-by: Paolo Abeni ---- - 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; - diff --git a/target/linux/generic/backport-6.12/710-09-v6.16-net-dsa-b53-do-not-touch-DLL_IQQD-on-bcm53115.patch b/target/linux/generic/backport-6.12/710-09-v6.16-net-dsa-b53-do-not-touch-DLL_IQQD-on-bcm53115.patch deleted file mode 100644 index 9f2143d816..0000000000 --- a/target/linux/generic/backport-6.12/710-09-v6.16-net-dsa-b53-do-not-touch-DLL_IQQD-on-bcm53115.patch +++ /dev/null @@ -1,59 +0,0 @@ -From bc1a65eb81a21e2aa3c3dca058ee8adf687b6ef5 Mon Sep 17 00:00:00 2001 -From: Jonas Gorski -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") -Signed-off-by: Jonas Gorski -Link: https://patch.msgid.link/20250602193953.1010487-6-jonas.gorski@gmail.com -Signed-off-by: Paolo Abeni ---- - 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, diff --git a/target/linux/generic/backport-6.12/710-v6.16-igc-enable-HW-vlan-tag-insertion-stripping-by-defaul.patch b/target/linux/generic/backport-6.12/710-v6.16-igc-enable-HW-vlan-tag-insertion-stripping-by-defaul.patch new file mode 100644 index 0000000000..e231bc8d49 --- /dev/null +++ b/target/linux/generic/backport-6.12/710-v6.16-igc-enable-HW-vlan-tag-insertion-stripping-by-defaul.patch @@ -0,0 +1,32 @@ +From 8cae5a0d91fea01d90ce7c1827e26934a22ca2fa Mon Sep 17 00:00:00 2001 +From: Rui Salvaterra +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. + +Signed-off-by: Rui Salvaterra +--- + 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; diff --git a/target/linux/generic/backport-6.12/711-01-v6.16-net-dsa-tag_brcm-legacy-fix-pskb_may_pull-length.patch b/target/linux/generic/backport-6.12/711-01-v6.16-net-dsa-tag_brcm-legacy-fix-pskb_may_pull-length.patch deleted file mode 100644 index 9fa88d2d3f..0000000000 --- a/target/linux/generic/backport-6.12/711-01-v6.16-net-dsa-tag_brcm-legacy-fix-pskb_may_pull-length.patch +++ /dev/null @@ -1,31 +0,0 @@ -From efdddc4484859082da6c7877ed144c8121c8ea55 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= -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") -Signed-off-by: Álvaro Fernández Rojas -Reviewed-by: Florian Fainelli -Link: https://patch.msgid.link/20250529124406.2513779-1-noltari@gmail.com -Signed-off-by: Jakub Kicinski ---- - 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); diff --git a/target/linux/generic/backport-6.12/720-01-v6.13-net-phy-mediatek-ge-soc-Fix-coding-style.patch b/target/linux/generic/backport-6.12/720-01-v6.13-net-phy-mediatek-ge-soc-Fix-coding-style.patch new file mode 100644 index 0000000000..25bd96fa1f --- /dev/null +++ b/target/linux/generic/backport-6.12/720-01-v6.13-net-phy-mediatek-ge-soc-Fix-coding-style.patch @@ -0,0 +1,88 @@ +From 277f96c1f3f71d6e1d3bcf650d7cd84c1442210f Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +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. + +Signed-off-by: SkyLake.Huang +Reviewed-by: Simon Horman +Signed-off-by: Andrew Lunn +--- + 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 diff --git a/target/linux/generic/backport-6.12/720-02-v6.13-net-phy-mediatek-ge-soc-Shrink-line-wrapping-to-80-c.patch b/target/linux/generic/backport-6.12/720-02-v6.13-net-phy-mediatek-ge-soc-Shrink-line-wrapping-to-80-c.patch new file mode 100644 index 0000000000..fbf3a99bd7 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-02-v6.13-net-phy-mediatek-ge-soc-Shrink-line-wrapping-to-80-c.patch @@ -0,0 +1,271 @@ +From c0dc1b412f9d840c51c5ee8927bf066e15a59550 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +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. + +Signed-off-by: SkyLake.Huang +Reviewed-by: Simon Horman +Signed-off-by: Andrew Lunn +--- + 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; + } diff --git a/target/linux/generic/backport-6.12/720-03-v6.13-net-phy-mediatek-ge-soc-Propagate-error-code-correct.patch b/target/linux/generic/backport-6.12/720-03-v6.13-net-phy-mediatek-ge-soc-Propagate-error-code-correct.patch new file mode 100644 index 0000000000..1f6f5f5df6 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-03-v6.13-net-phy-mediatek-ge-soc-Propagate-error-code-correct.patch @@ -0,0 +1,40 @@ +From bcbbfb4f62c4ba35783cc617997a2e92d91e3940 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +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(). + +Signed-off-by: SkyLake.Huang +Reviewed-by: Simon Horman +Signed-off-by: Andrew Lunn +--- + 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; diff --git a/target/linux/generic/backport-6.12/720-04-v6.13-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch b/target/linux/generic/backport-6.12/720-04-v6.13-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch new file mode 100644 index 0000000000..7161ffe069 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-04-v6.13-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch @@ -0,0 +1,3565 @@ +From e062f073dc0df4fcd338043cb0b69b6bcd31e4af Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +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 + +Reviewed-by: Andrew Lunn +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + 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 +@@ -14427,8 +14427,8 @@ M: Qingfang Deng + M: SkyLake Huang + L: netdev@vger.kernel.org + 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 +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#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_AUTHOR("Daniel Golle "); +-MODULE_AUTHOR("SkyLake Huang "); +-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 +-#include +-#include +- +-#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_AUTHOR("DENG, Qingfang "); +-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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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_AUTHOR("Daniel Golle "); ++MODULE_AUTHOR("SkyLake Huang "); ++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 ++#include ++#include ++ ++#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_AUTHOR("DENG, Qingfang "); ++MODULE_LICENSE("GPL"); ++ ++MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl); diff --git a/target/linux/generic/backport-6.12/720-05-v6.13-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch b/target/linux/generic/backport-6.12/720-05-v6.13-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch new file mode 100644 index 0000000000..63407ac55c --- /dev/null +++ b/target/linux/generic/backport-6.12/720-05-v6.13-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch @@ -0,0 +1,774 @@ +From 71d88c7409b91c853d7f9c933f5e27933d656e5e Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +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. + +Reviewed-by: Andrew Lunn +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + 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 + #include + ++#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 ++#include ++ ++#include ++ ++#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_AUTHOR("Sky Huang "); ++MODULE_AUTHOR("Daniel Golle "); ++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 ++ * Author: SkyLake Huang ++ * 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_ */ diff --git a/target/linux/generic/backport-6.12/720-06-v6.13-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch b/target/linux/generic/backport-6.12/720-06-v6.13-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch new file mode 100644 index 0000000000..19f3a84ad9 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-06-v6.13-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch @@ -0,0 +1,72 @@ +From 3efd0595fc7aaae300f5d9f4f0ae86f432c8d2c7 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +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. + +Reviewed-by: Andrew Lunn +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + 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) diff --git a/target/linux/generic/backport-6.12/720-07-v6.13-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch b/target/linux/generic/backport-6.12/720-07-v6.13-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch new file mode 100644 index 0000000000..a5828bc759 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-07-v6.13-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch @@ -0,0 +1,153 @@ +From 50a97d716105a5f35aaecca0bdfe8e23cba0e87f Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +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. + +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + 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 + #include + ++#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); diff --git a/target/linux/generic/backport-6.12/720-08-v6.13-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch b/target/linux/generic/backport-6.12/720-08-v6.13-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch new file mode 100644 index 0000000000..1c8738408b --- /dev/null +++ b/target/linux/generic/backport-6.12/720-08-v6.13-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch @@ -0,0 +1,56 @@ +From e6579df175d5b1baa605c82f8e759542262637cf Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +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. + +Reviewed-by: Andrew Lunn +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + 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) }, + { } + }; + diff --git a/target/linux/generic/backport-6.12/720-09-v6.14-net-phy-Constify-struct-mdio_device_id.patch b/target/linux/generic/backport-6.12/720-09-v6.14-net-phy-Constify-struct-mdio_device_id.patch new file mode 100644 index 0000000000..669b58d22a --- /dev/null +++ b/target/linux/generic/backport-6.12/720-09-v6.14-net-phy-Constify-struct-mdio_device_id.patch @@ -0,0 +1,700 @@ +From e127f7380aaf2cd1614961d826a4af7ab297d37f Mon Sep 17 00:00:00 2001 +From: Christophe JAILLET +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 + +Signed-off-by: Christophe JAILLET +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/403c381b7d9156b67ad68ffc44b8eee70c5e86a9.1736691226.git.christophe.jaillet@wanadoo.fr +Signed-off-by: Jakub Kicinski +--- + 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 }, diff --git a/target/linux/generic/backport-6.12/720-10-v6.15-net-phy-mediatek-Change-to-more-meaningful-macros.patch b/target/linux/generic/backport-6.12/720-10-v6.15-net-phy-mediatek-Change-to-more-meaningful-macros.patch new file mode 100644 index 0000000000..545e92987f --- /dev/null +++ b/target/linux/generic/backport-6.12/720-10-v6.15-net-phy-mediatek-Change-to-more-meaningful-macros.patch @@ -0,0 +1,146 @@ +From 7e06c3dbfa5f1e39eba92eb79d854fab2a7ad5fe Mon Sep 17 00:00:00 2001 +From: Sky Huang +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. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-2-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + 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 diff --git a/target/linux/generic/backport-6.12/720-11-v6.15-net-phy-mediatek-Add-token-ring-access-helper-functi.patch b/target/linux/generic/backport-6.12/720-11-v6.15-net-phy-mediatek-Add-token-ring-access-helper-functi.patch new file mode 100644 index 0000000000..40ce29fc51 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-11-v6.15-net-phy-mediatek-Add-token-ring-access-helper-functi.patch @@ -0,0 +1,448 @@ +From 6e7370079669b0d55c9464bb7c3fb8fb7368b912 Mon Sep 17 00:00:00 2001 +From: Sky Huang +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. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-3-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + 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); + diff --git a/target/linux/generic/backport-6.12/720-12-v6.15-net-phy-mediatek-Add-token-ring-set-bit-operation-su.patch b/target/linux/generic/backport-6.12/720-12-v6.15-net-phy-mediatek-Add-token-ring-set-bit-operation-su.patch new file mode 100644 index 0000000000..972a9c0a7e --- /dev/null +++ b/target/linux/generic/backport-6.12/720-12-v6.15-net-phy-mediatek-Add-token-ring-set-bit-operation-su.patch @@ -0,0 +1,73 @@ +From c7e2fb3421ef5ebbb4c91f44bd735ab10edd755a Mon Sep 17 00:00:00 2001 +From: Sky Huang +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. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-4-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + 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); diff --git a/target/linux/generic/backport-6.12/720-13-v6.15-net-phy-mediatek-Add-token-ring-clear-bit-operation-.patch b/target/linux/generic/backport-6.12/720-13-v6.15-net-phy-mediatek-Add-token-ring-clear-bit-operation-.patch new file mode 100644 index 0000000000..47d891ea69 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-13-v6.15-net-phy-mediatek-Add-token-ring-clear-bit-operation-.patch @@ -0,0 +1,122 @@ +From 7851c73a416b15aff6f9ada9c88affc5f48ff011 Mon Sep 17 00:00:00 2001 +From: Sky Huang +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. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-5-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + 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); diff --git a/target/linux/generic/backport-6.12/720-14-v6.15-net-phy-mediatek-Move-some-macros-to-phy-lib-for-lat.patch b/target/linux/generic/backport-6.12/720-14-v6.15-net-phy-mediatek-Move-some-macros-to-phy-lib-for-lat.patch new file mode 100644 index 0000000000..858de093a2 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-14-v6.15-net-phy-mediatek-Move-some-macros-to-phy-lib-for-lat.patch @@ -0,0 +1,45 @@ +From bae8c61522c4d5a5250a24dcb57d120ea593fab1 Mon Sep 17 00:00:00 2001 +From: Sky Huang +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. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-6-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + 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 + diff --git a/target/linux/generic/backport-6.12/720-15-v6.16-net-phy-mediatek-permit-to-compile-test-GE-SOC-PHY-d.patch b/target/linux/generic/backport-6.12/720-15-v6.16-net-phy-mediatek-permit-to-compile-test-GE-SOC-PHY-d.patch new file mode 100644 index 0000000000..9778ea158b --- /dev/null +++ b/target/linux/generic/backport-6.12/720-15-v6.16-net-phy-mediatek-permit-to-compile-test-GE-SOC-PHY-d.patch @@ -0,0 +1,37 @@ +From e5566162af8b9690e096d2e6089e4ed955a0d13d Mon Sep 17 00:00:00 2001 +From: Christian Marangi +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") +Acked-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: Christian Marangi +Acked-by: Arnd Bergmann +Link: https://patch.msgid.link/20250410100410.348-1-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + 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. diff --git a/target/linux/generic/backport-6.12/720-16-v6.16-net-phy-mediatek-add-Airoha-PHY-ID-to-SoC-driver.patch b/target/linux/generic/backport-6.12/720-16-v6.16-net-phy-mediatek-add-Airoha-PHY-ID-to-SoC-driver.patch new file mode 100644 index 0000000000..5498ecbd21 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-16-v6.16-net-phy-mediatek-add-Airoha-PHY-ID-to-SoC-driver.patch @@ -0,0 +1,129 @@ +From 4590c8bc10951feee3e439bf7fff1b458c2e6fad Mon Sep 17 00:00:00 2001 +From: Christian Marangi +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. + +Reviewed-by: Andrew Lunn +Signed-off-by: Christian Marangi +Link: https://patch.msgid.link/20250410100410.348-2-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + 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) }, + { } + }; + diff --git a/target/linux/generic/backport-6.12/720-17-v6.16-net-phy-mediatek-init-val-in-.phy_led_polarity_set-f.patch b/target/linux/generic/backport-6.12/720-17-v6.16-net-phy-mediatek-init-val-in-.phy_led_polarity_set-f.patch new file mode 100644 index 0000000000..1b1dda2327 --- /dev/null +++ b/target/linux/generic/backport-6.12/720-17-v6.16-net-phy-mediatek-init-val-in-.phy_led_polarity_set-f.patch @@ -0,0 +1,40 @@ +From 34501d047ac0a6cbb13285ba9d15f75c1deb7da7 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +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. + +Reported-by: Simon Horman +Fixes: 6a325aed130b ("net: phy: mediatek: add Airoha PHY ID to SoC driver") +Signed-off-by: Christian Marangi +Link: https://patch.msgid.link/20250415105313.3409-1-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + 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; diff --git a/target/linux/generic/backport-6.12/720-v6.13-net-phy-mediatek-ge-soc-Fix-coding-style.patch b/target/linux/generic/backport-6.12/720-v6.13-net-phy-mediatek-ge-soc-Fix-coding-style.patch deleted file mode 100644 index 25bd96fa1f..0000000000 --- a/target/linux/generic/backport-6.12/720-v6.13-net-phy-mediatek-ge-soc-Fix-coding-style.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 277f96c1f3f71d6e1d3bcf650d7cd84c1442210f Mon Sep 17 00:00:00 2001 -From: "SkyLake.Huang" -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. - -Signed-off-by: SkyLake.Huang -Reviewed-by: Simon Horman -Signed-off-by: Andrew Lunn ---- - 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 diff --git a/target/linux/generic/backport-6.12/721-01-v6.15-net-ethernet-mediatek-add-EEE-support.patch b/target/linux/generic/backport-6.12/721-01-v6.15-net-ethernet-mediatek-add-EEE-support.patch new file mode 100644 index 0000000000..2ca3f2ef00 --- /dev/null +++ b/target/linux/generic/backport-6.12/721-01-v6.15-net-ethernet-mediatek-add-EEE-support.patch @@ -0,0 +1,157 @@ +From 952d7325362ffbefa6ce5619fb4e53c2159ec7a7 Mon Sep 17 00:00:00 2001 +From: Qingfang Deng +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. + +Signed-off-by: Qingfang Deng +--- + 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; diff --git a/target/linux/generic/backport-6.12/721-v6.13-net-phy-mediatek-ge-soc-Shrink-line-wrapping-to-80-c.patch b/target/linux/generic/backport-6.12/721-v6.13-net-phy-mediatek-ge-soc-Shrink-line-wrapping-to-80-c.patch deleted file mode 100644 index fbf3a99bd7..0000000000 --- a/target/linux/generic/backport-6.12/721-v6.13-net-phy-mediatek-ge-soc-Shrink-line-wrapping-to-80-c.patch +++ /dev/null @@ -1,271 +0,0 @@ -From c0dc1b412f9d840c51c5ee8927bf066e15a59550 Mon Sep 17 00:00:00 2001 -From: "SkyLake.Huang" -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. - -Signed-off-by: SkyLake.Huang -Reviewed-by: Simon Horman -Signed-off-by: Andrew Lunn ---- - 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; - } diff --git a/target/linux/generic/backport-6.12/722-v6.13-net-phy-mediatek-ge-soc-Propagate-error-code-correct.patch b/target/linux/generic/backport-6.12/722-v6.13-net-phy-mediatek-ge-soc-Propagate-error-code-correct.patch deleted file mode 100644 index 1f6f5f5df6..0000000000 --- a/target/linux/generic/backport-6.12/722-v6.13-net-phy-mediatek-ge-soc-Propagate-error-code-correct.patch +++ /dev/null @@ -1,40 +0,0 @@ -From bcbbfb4f62c4ba35783cc617997a2e92d91e3940 Mon Sep 17 00:00:00 2001 -From: "SkyLake.Huang" -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(). - -Signed-off-by: SkyLake.Huang -Reviewed-by: Simon Horman -Signed-off-by: Andrew Lunn ---- - 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; diff --git a/target/linux/generic/backport-6.12/723-v6.13-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch b/target/linux/generic/backport-6.12/723-v6.13-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch deleted file mode 100644 index 7161ffe069..0000000000 --- a/target/linux/generic/backport-6.12/723-v6.13-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch +++ /dev/null @@ -1,3565 +0,0 @@ -From e062f073dc0df4fcd338043cb0b69b6bcd31e4af Mon Sep 17 00:00:00 2001 -From: "SkyLake.Huang" -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 - -Reviewed-by: Andrew Lunn -Signed-off-by: SkyLake.Huang -Signed-off-by: David S. Miller ---- - 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 -@@ -14427,8 +14427,8 @@ M: Qingfang Deng - M: SkyLake Huang - L: netdev@vger.kernel.org - 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 --#include --#include --#include --#include --#include --#include --#include -- --#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_AUTHOR("Daniel Golle "); --MODULE_AUTHOR("SkyLake Huang "); --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 --#include --#include -- --#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_AUTHOR("DENG, Qingfang "); --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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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_AUTHOR("Daniel Golle "); -+MODULE_AUTHOR("SkyLake Huang "); -+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 -+#include -+#include -+ -+#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_AUTHOR("DENG, Qingfang "); -+MODULE_LICENSE("GPL"); -+ -+MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl); diff --git a/target/linux/generic/backport-6.12/724-v6.13-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch b/target/linux/generic/backport-6.12/724-v6.13-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch deleted file mode 100644 index 63407ac55c..0000000000 --- a/target/linux/generic/backport-6.12/724-v6.13-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch +++ /dev/null @@ -1,774 +0,0 @@ -From 71d88c7409b91c853d7f9c933f5e27933d656e5e Mon Sep 17 00:00:00 2001 -From: "SkyLake.Huang" -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. - -Reviewed-by: Andrew Lunn -Signed-off-by: SkyLake.Huang -Signed-off-by: David S. Miller ---- - 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 - #include - -+#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 -+#include -+ -+#include -+ -+#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_AUTHOR("Sky Huang "); -+MODULE_AUTHOR("Daniel Golle "); -+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 -+ * Author: SkyLake Huang -+ * 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_ */ diff --git a/target/linux/generic/backport-6.12/725-v6.13-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch b/target/linux/generic/backport-6.12/725-v6.13-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch deleted file mode 100644 index 19f3a84ad9..0000000000 --- a/target/linux/generic/backport-6.12/725-v6.13-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch +++ /dev/null @@ -1,72 +0,0 @@ -From 3efd0595fc7aaae300f5d9f4f0ae86f432c8d2c7 Mon Sep 17 00:00:00 2001 -From: "SkyLake.Huang" -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. - -Reviewed-by: Andrew Lunn -Signed-off-by: SkyLake.Huang -Signed-off-by: David S. Miller ---- - 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) diff --git a/target/linux/generic/backport-6.12/726-v6.13-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch b/target/linux/generic/backport-6.12/726-v6.13-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch deleted file mode 100644 index a5828bc759..0000000000 --- a/target/linux/generic/backport-6.12/726-v6.13-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 50a97d716105a5f35aaecca0bdfe8e23cba0e87f Mon Sep 17 00:00:00 2001 -From: "SkyLake.Huang" -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. - -Signed-off-by: SkyLake.Huang -Signed-off-by: David S. Miller ---- - 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 - #include - -+#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); diff --git a/target/linux/generic/backport-6.12/727-v6.13-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch b/target/linux/generic/backport-6.12/727-v6.13-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch deleted file mode 100644 index 1c8738408b..0000000000 --- a/target/linux/generic/backport-6.12/727-v6.13-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch +++ /dev/null @@ -1,56 +0,0 @@ -From e6579df175d5b1baa605c82f8e759542262637cf Mon Sep 17 00:00:00 2001 -From: "SkyLake.Huang" -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. - -Reviewed-by: Andrew Lunn -Signed-off-by: SkyLake.Huang -Signed-off-by: David S. Miller ---- - 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) }, - { } - }; - diff --git a/target/linux/generic/backport-6.12/728-v6.14-net-phy-Constify-struct-mdio_device_id.patch b/target/linux/generic/backport-6.12/728-v6.14-net-phy-Constify-struct-mdio_device_id.patch deleted file mode 100644 index 669b58d22a..0000000000 --- a/target/linux/generic/backport-6.12/728-v6.14-net-phy-Constify-struct-mdio_device_id.patch +++ /dev/null @@ -1,700 +0,0 @@ -From e127f7380aaf2cd1614961d826a4af7ab297d37f Mon Sep 17 00:00:00 2001 -From: Christophe JAILLET -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 - -Signed-off-by: Christophe JAILLET -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/403c381b7d9156b67ad68ffc44b8eee70c5e86a9.1736691226.git.christophe.jaillet@wanadoo.fr -Signed-off-by: Jakub Kicinski ---- - 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 }, diff --git a/target/linux/generic/backport-6.12/729-v6.15-net-phy-mediatek-Change-to-more-meaningful-macros.patch b/target/linux/generic/backport-6.12/729-v6.15-net-phy-mediatek-Change-to-more-meaningful-macros.patch deleted file mode 100644 index 545e92987f..0000000000 --- a/target/linux/generic/backport-6.12/729-v6.15-net-phy-mediatek-Change-to-more-meaningful-macros.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 7e06c3dbfa5f1e39eba92eb79d854fab2a7ad5fe Mon Sep 17 00:00:00 2001 -From: Sky Huang -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. - -Signed-off-by: Sky Huang -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/20250213080553.921434-2-SkyLake.Huang@mediatek.com -Signed-off-by: Jakub Kicinski ---- - 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 diff --git a/target/linux/generic/backport-6.12/730-01-v6.13-net-phy-aquantia-allow-forcing-order-of-MDI-pairs.patch b/target/linux/generic/backport-6.12/730-01-v6.13-net-phy-aquantia-allow-forcing-order-of-MDI-pairs.patch new file mode 100644 index 0000000000..aabaa33e2c --- /dev/null +++ b/target/linux/generic/backport-6.12/730-01-v6.13-net-phy-aquantia-allow-forcing-order-of-MDI-pairs.patch @@ -0,0 +1,107 @@ +From a2e1ba275eae96a8171deb19e9c7c2f5978fee7b Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org +Signed-off-by: Jakub Kicinski +--- + 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 + #include + #include ++#include + #include + + #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); diff --git a/target/linux/generic/backport-6.12/730-02-v6.13-net-phy-aquantia-fix-return-value-check-in-aqr107_co.patch b/target/linux/generic/backport-6.12/730-02-v6.13-net-phy-aquantia-fix-return-value-check-in-aqr107_co.patch new file mode 100644 index 0000000000..565edbd388 --- /dev/null +++ b/target/linux/generic/backport-6.12/730-02-v6.13-net-phy-aquantia-fix-return-value-check-in-aqr107_co.patch @@ -0,0 +1,31 @@ +From ce21b8fb255ebf0b49913fb4c62741d7eb05c6f6 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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") +Reported-by: Jon Hunter +Closes: https://lore.kernel.org/all/114b4c03-5d16-42ed-945d-cf78eabea12b@nvidia.com/ +Suggested-by: Hans-Frieder Vogt +Signed-off-by: Daniel Golle +--- + 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) diff --git a/target/linux/generic/backport-6.12/730-03-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch b/target/linux/generic/backport-6.12/730-03-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch new file mode 100644 index 0000000000..ad1d554531 --- /dev/null +++ b/target/linux/generic/backport-6.12/730-03-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch @@ -0,0 +1,53 @@ +From a274465cc3bef2dfd9c9ea5100848dda0a8641e1 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/91598487773d768f254d5faf06cf65b13e972f0e.1728558223.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + 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, diff --git a/target/linux/generic/backport-6.12/730-04-v6.13-net-phy-aquantia-correctly-describe-LED-polarity-ove.patch b/target/linux/generic/backport-6.12/730-04-v6.13-net-phy-aquantia-correctly-describe-LED-polarity-ove.patch new file mode 100644 index 0000000000..155f796f8c --- /dev/null +++ b/target/linux/generic/backport-6.12/730-04-v6.13-net-phy-aquantia-correctly-describe-LED-polarity-ove.patch @@ -0,0 +1,108 @@ +From 9d55e68b19f222e6334ef4021c5527998f5ab537 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/86a413b4387c42dcb54f587cc2433a06f16aae83.1728558223.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + 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; + } diff --git a/target/linux/generic/backport-6.12/730-05-v6.13-net-phy-mxl-gpy-add-basic-LED-support.patch b/target/linux/generic/backport-6.12/730-05-v6.13-net-phy-mxl-gpy-add-basic-LED-support.patch new file mode 100644 index 0000000000..c785f8a98a --- /dev/null +++ b/target/linux/generic/backport-6.12/730-05-v6.13-net-phy-mxl-gpy-add-basic-LED-support.patch @@ -0,0 +1,332 @@ +From 78997e9a5e4d8a4df561e083a92c91ae23010e07 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/b6ec9050339f8244ff898898a1cecc33b13a48fc.1727741563.git.daniel@makrotopia.org +Signed-off-by: Jakub Kicinski +--- + 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), diff --git a/target/linux/generic/backport-6.12/730-06-v6.13-net-phy-mxl-gpy-add-missing-support-for-TRIGGER_NETD.patch b/target/linux/generic/backport-6.12/730-06-v6.13-net-phy-mxl-gpy-add-missing-support-for-TRIGGER_NETD.patch new file mode 100644 index 0000000000..39bef9b982 --- /dev/null +++ b/target/linux/generic/backport-6.12/730-06-v6.13-net-phy-mxl-gpy-add-missing-support-for-TRIGGER_NETD.patch @@ -0,0 +1,28 @@ +From f95b4725e796b12e5f347a0d161e1d3843142aa8 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/cc5da0a989af8b0d49d823656d88053c4de2ab98.1728057367.git.daniel@makrotopia.org +Signed-off-by: Jakub Kicinski +--- + 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) | diff --git a/target/linux/generic/backport-6.12/730-07-v6.13-net-phy-mxl-gpy-correctly-describe-LED-polarity.patch b/target/linux/generic/backport-6.12/730-07-v6.13-net-phy-mxl-gpy-correctly-describe-LED-polarity.patch new file mode 100644 index 0000000000..5fd3dcc77b --- /dev/null +++ b/target/linux/generic/backport-6.12/730-07-v6.13-net-phy-mxl-gpy-correctly-describe-LED-polarity.patch @@ -0,0 +1,58 @@ +From eb89c79c1b8f17fc1611540768678e60df89ac42 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/180ccafa837f09908b852a8a874a3808c5ecd2d0.1728558223.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + 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[] = { diff --git a/target/linux/generic/backport-6.12/730-08-v6.13-net-phy-intel-xway-add-support-for-PHY-LEDs.patch b/target/linux/generic/backport-6.12/730-08-v6.13-net-phy-intel-xway-add-support-for-PHY-LEDs.patch new file mode 100644 index 0000000000..c57b5777ad --- /dev/null +++ b/target/linux/generic/backport-6.12/730-08-v6.13-net-phy-intel-xway-add-support-for-PHY-LEDs.patch @@ -0,0 +1,379 @@ +From 1758af47b98c17da464cb45f476875150955dd48 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/81f4717ab9acf38f3239727a4540ae96fd01109b.1728558223.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + 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); diff --git a/target/linux/generic/backport-6.12/730-v6.15-net-phy-mediatek-Add-token-ring-access-helper-functi.patch b/target/linux/generic/backport-6.12/730-v6.15-net-phy-mediatek-Add-token-ring-access-helper-functi.patch deleted file mode 100644 index 40ce29fc51..0000000000 --- a/target/linux/generic/backport-6.12/730-v6.15-net-phy-mediatek-Add-token-ring-access-helper-functi.patch +++ /dev/null @@ -1,448 +0,0 @@ -From 6e7370079669b0d55c9464bb7c3fb8fb7368b912 Mon Sep 17 00:00:00 2001 -From: Sky Huang -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. - -Signed-off-by: Sky Huang -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/20250213080553.921434-3-SkyLake.Huang@mediatek.com -Signed-off-by: Jakub Kicinski ---- - 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); - diff --git a/target/linux/generic/backport-6.12/731-v6.15-net-phy-mediatek-Add-token-ring-set-bit-operation-su.patch b/target/linux/generic/backport-6.12/731-v6.15-net-phy-mediatek-Add-token-ring-set-bit-operation-su.patch deleted file mode 100644 index 972a9c0a7e..0000000000 --- a/target/linux/generic/backport-6.12/731-v6.15-net-phy-mediatek-Add-token-ring-set-bit-operation-su.patch +++ /dev/null @@ -1,73 +0,0 @@ -From c7e2fb3421ef5ebbb4c91f44bd735ab10edd755a Mon Sep 17 00:00:00 2001 -From: Sky Huang -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. - -Signed-off-by: Sky Huang -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/20250213080553.921434-4-SkyLake.Huang@mediatek.com -Signed-off-by: Jakub Kicinski ---- - 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); diff --git a/target/linux/generic/backport-6.12/732-v6.15-net-phy-mediatek-Add-token-ring-clear-bit-operation-.patch b/target/linux/generic/backport-6.12/732-v6.15-net-phy-mediatek-Add-token-ring-clear-bit-operation-.patch deleted file mode 100644 index 47d891ea69..0000000000 --- a/target/linux/generic/backport-6.12/732-v6.15-net-phy-mediatek-Add-token-ring-clear-bit-operation-.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 7851c73a416b15aff6f9ada9c88affc5f48ff011 Mon Sep 17 00:00:00 2001 -From: Sky Huang -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. - -Signed-off-by: Sky Huang -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/20250213080553.921434-5-SkyLake.Huang@mediatek.com -Signed-off-by: Jakub Kicinski ---- - 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); diff --git a/target/linux/generic/backport-6.12/733-v6.15-net-phy-mediatek-Move-some-macros-to-phy-lib-for-lat.patch b/target/linux/generic/backport-6.12/733-v6.15-net-phy-mediatek-Move-some-macros-to-phy-lib-for-lat.patch deleted file mode 100644 index 858de093a2..0000000000 --- a/target/linux/generic/backport-6.12/733-v6.15-net-phy-mediatek-Move-some-macros-to-phy-lib-for-lat.patch +++ /dev/null @@ -1,45 +0,0 @@ -From bae8c61522c4d5a5250a24dcb57d120ea593fab1 Mon Sep 17 00:00:00 2001 -From: Sky Huang -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. - -Signed-off-by: Sky Huang -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/20250213080553.921434-6-SkyLake.Huang@mediatek.com -Signed-off-by: Jakub Kicinski ---- - 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 - diff --git a/target/linux/generic/backport-6.12/735-v6.16-net-phy-mediatek-permit-to-compile-test-GE-SOC-PHY-d.patch b/target/linux/generic/backport-6.12/735-v6.16-net-phy-mediatek-permit-to-compile-test-GE-SOC-PHY-d.patch deleted file mode 100644 index 9778ea158b..0000000000 --- a/target/linux/generic/backport-6.12/735-v6.16-net-phy-mediatek-permit-to-compile-test-GE-SOC-PHY-d.patch +++ /dev/null @@ -1,37 +0,0 @@ -From e5566162af8b9690e096d2e6089e4ed955a0d13d Mon Sep 17 00:00:00 2001 -From: Christian Marangi -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") -Acked-by: Daniel Golle -Reviewed-by: Andrew Lunn -Signed-off-by: Christian Marangi -Acked-by: Arnd Bergmann -Link: https://patch.msgid.link/20250410100410.348-1-ansuelsmth@gmail.com -Signed-off-by: Jakub Kicinski ---- - 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. diff --git a/target/linux/generic/backport-6.12/736-v6.16-net-phy-mediatek-add-Airoha-PHY-ID-to-SoC-driver.patch b/target/linux/generic/backport-6.12/736-v6.16-net-phy-mediatek-add-Airoha-PHY-ID-to-SoC-driver.patch deleted file mode 100644 index 5498ecbd21..0000000000 --- a/target/linux/generic/backport-6.12/736-v6.16-net-phy-mediatek-add-Airoha-PHY-ID-to-SoC-driver.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 4590c8bc10951feee3e439bf7fff1b458c2e6fad Mon Sep 17 00:00:00 2001 -From: Christian Marangi -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. - -Reviewed-by: Andrew Lunn -Signed-off-by: Christian Marangi -Link: https://patch.msgid.link/20250410100410.348-2-ansuelsmth@gmail.com -Signed-off-by: Jakub Kicinski ---- - 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) }, - { } - }; - diff --git a/target/linux/generic/backport-6.12/737-v6.16-net-phy-mediatek-init-val-in-.phy_led_polarity_set-f.patch b/target/linux/generic/backport-6.12/737-v6.16-net-phy-mediatek-init-val-in-.phy_led_polarity_set-f.patch deleted file mode 100644 index 1b1dda2327..0000000000 --- a/target/linux/generic/backport-6.12/737-v6.16-net-phy-mediatek-init-val-in-.phy_led_polarity_set-f.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 34501d047ac0a6cbb13285ba9d15f75c1deb7da7 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -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. - -Reported-by: Simon Horman -Fixes: 6a325aed130b ("net: phy: mediatek: add Airoha PHY ID to SoC driver") -Signed-off-by: Christian Marangi -Link: https://patch.msgid.link/20250415105313.3409-1-ansuelsmth@gmail.com -Signed-off-by: Jakub Kicinski ---- - 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; diff --git a/target/linux/generic/backport-6.12/740-v6.13-net-dsa-mv88e6xxx-Support-LED-control.patch b/target/linux/generic/backport-6.12/740-v6.13-net-dsa-mv88e6xxx-Support-LED-control.patch new file mode 100644 index 0000000000..19268cf578 --- /dev/null +++ b/target/linux/generic/backport-6.12/740-v6.13-net-dsa-mv88e6xxx-Support-LED-control.patch @@ -0,0 +1,1250 @@ +From 7b590490e3aa6bfa38bf6e2069a529017fd3c1d2 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +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 = ; + function = LED_FUNCTION_LAN; + default-state = "off"; + linux,default-trigger = "netdev"; + }; + led@1 { + reg = <1>; + color = ; + 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. + +Signed-off-by: Linus Walleij +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 + #include + #include ++#include + #include ++#include + #include + #include + #include +@@ -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 ++#include ++#include ++ ++#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 + #include + #include ++#include + + #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); diff --git a/target/linux/generic/backport-6.12/753-v6.15-net-ethernet-mediatek-add-EEE-support.patch b/target/linux/generic/backport-6.12/753-v6.15-net-ethernet-mediatek-add-EEE-support.patch deleted file mode 100644 index 2ca3f2ef00..0000000000 --- a/target/linux/generic/backport-6.12/753-v6.15-net-ethernet-mediatek-add-EEE-support.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 952d7325362ffbefa6ce5619fb4e53c2159ec7a7 Mon Sep 17 00:00:00 2001 -From: Qingfang Deng -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. - -Signed-off-by: Qingfang Deng ---- - 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; diff --git a/target/linux/generic/backport-6.12/792-v6.16-igc-enable-HW-vlan-tag-insertion-stripping-by-defaul.patch b/target/linux/generic/backport-6.12/792-v6.16-igc-enable-HW-vlan-tag-insertion-stripping-by-defaul.patch deleted file mode 100644 index e231bc8d49..0000000000 --- a/target/linux/generic/backport-6.12/792-v6.16-igc-enable-HW-vlan-tag-insertion-stripping-by-defaul.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 8cae5a0d91fea01d90ce7c1827e26934a22ca2fa Mon Sep 17 00:00:00 2001 -From: Rui Salvaterra -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. - -Signed-off-by: Rui Salvaterra ---- - 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; diff --git a/target/linux/generic/backport-6.12/807-v6.15-power-supply-sysfs-remove-duplicate-nul-termination-to-fix-build-with-GCC15.patch b/target/linux/generic/backport-6.12/807-v6.15-power-supply-sysfs-remove-duplicate-nul-termination-to-fix-build-with-GCC15.patch deleted file mode 100644 index 48f9c1c264..0000000000 --- a/target/linux/generic/backport-6.12/807-v6.15-power-supply-sysfs-remove-duplicate-nul-termination-to-fix-build-with-GCC15.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 77f5bb150132bbbcd6bc37ffdc80c9e140e373a4 Mon Sep 17 00:00:00 2001 -From: Kees Cook -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). - -Signed-off-by: Kees Cook -Link: https://lore.kernel.org/r/20250416222740.work.569-kees@kernel.org -Signed-off-by: Sebastian Reichel - ---- 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, \ - } diff --git a/target/linux/generic/backport-6.12/810-v6.14-gpio-regmap-Use-generic-request-free-ops.patch b/target/linux/generic/backport-6.12/810-v6.14-gpio-regmap-Use-generic-request-free-ops.patch new file mode 100644 index 0000000000..f9299f9733 --- /dev/null +++ b/target/linux/generic/backport-6.12/810-v6.14-gpio-regmap-Use-generic-request-free-ops.patch @@ -0,0 +1,30 @@ +From b0fa00fe38f673c986633c11087274deeb7ce7b0 Mon Sep 17 00:00:00 2001 +From: Sander Vanheule +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. + +Signed-off-by: Sander Vanheule +Acked-by: Michael Walle +Link: https://lore.kernel.org/r/20250107201621.12467-1-sander@svanheule.net +Signed-off-by: Bartosz Golaszewski +--- + 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; diff --git a/target/linux/generic/backport-6.12/820-v6.15-power-supply-sysfs-remove-duplicate-nul-termination-to-fix-build-with-GCC15.patch b/target/linux/generic/backport-6.12/820-v6.15-power-supply-sysfs-remove-duplicate-nul-termination-to-fix-build-with-GCC15.patch new file mode 100644 index 0000000000..48f9c1c264 --- /dev/null +++ b/target/linux/generic/backport-6.12/820-v6.15-power-supply-sysfs-remove-duplicate-nul-termination-to-fix-build-with-GCC15.patch @@ -0,0 +1,39 @@ +From 77f5bb150132bbbcd6bc37ffdc80c9e140e373a4 Mon Sep 17 00:00:00 2001 +From: Kees Cook +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). + +Signed-off-by: Kees Cook +Link: https://lore.kernel.org/r/20250416222740.work.569-kees@kernel.org +Signed-off-by: Sebastian Reichel + +--- 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, \ + } diff --git a/target/linux/generic/backport-6.12/839-v6.13-net-phy-aquantia-allow-forcing-order-of-MDI-pairs.patch b/target/linux/generic/backport-6.12/839-v6.13-net-phy-aquantia-allow-forcing-order-of-MDI-pairs.patch deleted file mode 100644 index aabaa33e2c..0000000000 --- a/target/linux/generic/backport-6.12/839-v6.13-net-phy-aquantia-allow-forcing-order-of-MDI-pairs.patch +++ /dev/null @@ -1,107 +0,0 @@ -From a2e1ba275eae96a8171deb19e9c7c2f5978fee7b Mon Sep 17 00:00:00 2001 -From: Daniel Golle -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. - -Signed-off-by: Daniel Golle -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org -Signed-off-by: Jakub Kicinski ---- - 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 - #include - #include -+#include - #include - - #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); diff --git a/target/linux/generic/backport-6.12/840-v6.13-net-phy-aquantia-fix-return-value-check-in-aqr107_co.patch b/target/linux/generic/backport-6.12/840-v6.13-net-phy-aquantia-fix-return-value-check-in-aqr107_co.patch deleted file mode 100644 index 565edbd388..0000000000 --- a/target/linux/generic/backport-6.12/840-v6.13-net-phy-aquantia-fix-return-value-check-in-aqr107_co.patch +++ /dev/null @@ -1,31 +0,0 @@ -From ce21b8fb255ebf0b49913fb4c62741d7eb05c6f6 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -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") -Reported-by: Jon Hunter -Closes: https://lore.kernel.org/all/114b4c03-5d16-42ed-945d-cf78eabea12b@nvidia.com/ -Suggested-by: Hans-Frieder Vogt -Signed-off-by: Daniel Golle ---- - 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) diff --git a/target/linux/generic/backport-6.12/841-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch b/target/linux/generic/backport-6.12/841-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch deleted file mode 100644 index ad1d554531..0000000000 --- a/target/linux/generic/backport-6.12/841-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch +++ /dev/null @@ -1,53 +0,0 @@ -From a274465cc3bef2dfd9c9ea5100848dda0a8641e1 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -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. - -Signed-off-by: Daniel Golle -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/91598487773d768f254d5faf06cf65b13e972f0e.1728558223.git.daniel@makrotopia.org -Signed-off-by: Paolo Abeni ---- - 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, diff --git a/target/linux/generic/backport-6.12/842-v6.13-net-phy-aquantia-correctly-describe-LED-polarity-ove.patch b/target/linux/generic/backport-6.12/842-v6.13-net-phy-aquantia-correctly-describe-LED-polarity-ove.patch deleted file mode 100644 index 155f796f8c..0000000000 --- a/target/linux/generic/backport-6.12/842-v6.13-net-phy-aquantia-correctly-describe-LED-polarity-ove.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 9d55e68b19f222e6334ef4021c5527998f5ab537 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -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. - -Signed-off-by: Daniel Golle -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/86a413b4387c42dcb54f587cc2433a06f16aae83.1728558223.git.daniel@makrotopia.org -Signed-off-by: Paolo Abeni ---- - 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; - } diff --git a/target/linux/generic/backport-6.12/843-v6.13-net-phy-mxl-gpy-add-basic-LED-support.patch b/target/linux/generic/backport-6.12/843-v6.13-net-phy-mxl-gpy-add-basic-LED-support.patch deleted file mode 100644 index c785f8a98a..0000000000 --- a/target/linux/generic/backport-6.12/843-v6.13-net-phy-mxl-gpy-add-basic-LED-support.patch +++ /dev/null @@ -1,332 +0,0 @@ -From 78997e9a5e4d8a4df561e083a92c91ae23010e07 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -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. - -Signed-off-by: Daniel Golle -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/b6ec9050339f8244ff898898a1cecc33b13a48fc.1727741563.git.daniel@makrotopia.org -Signed-off-by: Jakub Kicinski ---- - 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), diff --git a/target/linux/generic/backport-6.12/844-v6.13-net-phy-mxl-gpy-add-missing-support-for-TRIGGER_NETD.patch b/target/linux/generic/backport-6.12/844-v6.13-net-phy-mxl-gpy-add-missing-support-for-TRIGGER_NETD.patch deleted file mode 100644 index 39bef9b982..0000000000 --- a/target/linux/generic/backport-6.12/844-v6.13-net-phy-mxl-gpy-add-missing-support-for-TRIGGER_NETD.patch +++ /dev/null @@ -1,28 +0,0 @@ -From f95b4725e796b12e5f347a0d161e1d3843142aa8 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -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. - -Signed-off-by: Daniel Golle -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/cc5da0a989af8b0d49d823656d88053c4de2ab98.1728057367.git.daniel@makrotopia.org -Signed-off-by: Jakub Kicinski ---- - 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) | diff --git a/target/linux/generic/backport-6.12/845-v6.13-net-phy-mxl-gpy-correctly-describe-LED-polarity.patch b/target/linux/generic/backport-6.12/845-v6.13-net-phy-mxl-gpy-correctly-describe-LED-polarity.patch deleted file mode 100644 index 5fd3dcc77b..0000000000 --- a/target/linux/generic/backport-6.12/845-v6.13-net-phy-mxl-gpy-correctly-describe-LED-polarity.patch +++ /dev/null @@ -1,58 +0,0 @@ -From eb89c79c1b8f17fc1611540768678e60df89ac42 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -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. - -Signed-off-by: Daniel Golle -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/180ccafa837f09908b852a8a874a3808c5ecd2d0.1728558223.git.daniel@makrotopia.org -Signed-off-by: Paolo Abeni ---- - 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[] = { diff --git a/target/linux/generic/backport-6.12/846-v6.13-net-phy-intel-xway-add-support-for-PHY-LEDs.patch b/target/linux/generic/backport-6.12/846-v6.13-net-phy-intel-xway-add-support-for-PHY-LEDs.patch deleted file mode 100644 index c57b5777ad..0000000000 --- a/target/linux/generic/backport-6.12/846-v6.13-net-phy-intel-xway-add-support-for-PHY-LEDs.patch +++ /dev/null @@ -1,379 +0,0 @@ -From 1758af47b98c17da464cb45f476875150955dd48 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -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. - -Signed-off-by: Daniel Golle -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/81f4717ab9acf38f3239727a4540ae96fd01109b.1728558223.git.daniel@makrotopia.org -Signed-off-by: Paolo Abeni ---- - 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); diff --git a/target/linux/generic/backport-6.12/880-v6.14-gpio-regmap-Use-generic-request-free-ops.patch b/target/linux/generic/backport-6.12/880-v6.14-gpio-regmap-Use-generic-request-free-ops.patch deleted file mode 100644 index f9299f9733..0000000000 --- a/target/linux/generic/backport-6.12/880-v6.14-gpio-regmap-Use-generic-request-free-ops.patch +++ /dev/null @@ -1,30 +0,0 @@ -From b0fa00fe38f673c986633c11087274deeb7ce7b0 Mon Sep 17 00:00:00 2001 -From: Sander Vanheule -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. - -Signed-off-by: Sander Vanheule -Acked-by: Michael Walle -Link: https://lore.kernel.org/r/20250107201621.12467-1-sander@svanheule.net -Signed-off-by: Bartosz Golaszewski ---- - 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; diff --git a/target/linux/generic/backport-6.12/901-v6.13-net-dsa-mv88e6xxx-Support-LED-control.patch b/target/linux/generic/backport-6.12/901-v6.13-net-dsa-mv88e6xxx-Support-LED-control.patch deleted file mode 100644 index 19268cf578..0000000000 --- a/target/linux/generic/backport-6.12/901-v6.13-net-dsa-mv88e6xxx-Support-LED-control.patch +++ /dev/null @@ -1,1250 +0,0 @@ -From 7b590490e3aa6bfa38bf6e2069a529017fd3c1d2 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -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 = ; - function = LED_FUNCTION_LAN; - default-state = "off"; - linux,default-trigger = "netdev"; - }; - led@1 { - reg = <1>; - color = ; - 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. - -Signed-off-by: Linus Walleij ---- - 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 - #include - #include -+#include - #include - #include - #include -@@ -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 - #include - #include -+#include - #include -+#include - #include - #include - #include -@@ -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 -+#include -+#include -+ -+#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 - #include - #include -+#include - - #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); diff --git a/target/linux/generic/backport-6.12/902-v6.13-fortify-Hide-run-time-copy-size-from-value-range-tracking.patch b/target/linux/generic/backport-6.12/902-v6.13-fortify-Hide-run-time-copy-size-from-value-range-tracking.patch deleted file mode 100644 index 8dca649866..0000000000 --- a/target/linux/generic/backport-6.12/902-v6.13-fortify-Hide-run-time-copy-size-from-value-range-tracking.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 239d87327dcd361b0098038995f8908f3296864f Mon Sep 17 00:00:00 2001 -From: Kees Cook -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. - -Reported-by: "Thomas Weißschuh" -Closes: https://lore.kernel.org/all/db7190c8-d17f-4a0d-bc2f-5903c79f36c2@t-8ch.de/ -Reported-by: Nilay Shroff -Closes: https://lore.kernel.org/all/20241112124127.1666300-1-nilay@linux.ibm.com/ -Tested-by: Nilay Shroff -Acked-by: Yury Norov -Acked-by: Greg Kroah-Hartman -Signed-off-by: Kees Cook ---- - 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); \ - }) - - /*