generic: 6.12: reorganize backports
authorÁlvaro Fernández Rojas <[email protected]>
Sat, 7 Jun 2025 08:38:55 +0000 (10:38 +0200)
committerÁlvaro Fernández Rojas <[email protected]>
Wed, 11 Jun 2025 05:37:25 +0000 (07:37 +0200)
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 <[email protected]>
130 files changed:
target/linux/generic/backport-6.12/200-01-v6.13-jiffies-Define-secs_to_jiffies.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/200-02-v6.14-jiffies-Cast-to-unsigned-long-in-secs_to_jiffies-con.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/201-v6.16-mips-Add-std-flag-specified.patch [deleted file]
target/linux/generic/backport-6.12/210-v6.13-fortify-Hide-run-time-copy-size-from-value-range-tracking.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/300-v6.16-mips-Add-std-flag-specified.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/330-v6.13-jiffies-Define-secs_to_jiffies.patch [deleted file]
target/linux/generic/backport-6.12/331-v6.14-jiffies-Cast-to-unsigned-long-in-secs_to_jiffies-con.patch [deleted file]
target/linux/generic/backport-6.12/400-v6.14-mtd-spinand-add-support-for-FORESEE-F35SQA001G.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-01-v6.14-mtd-rawnand-qcom-cleanup-qcom_nandc-driver.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-02-v6.14-mtd-rawnand-qcom-Add-qcom-prefix-to-common-api.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-03-v6.14-mtd-nand-Add-qpic_common-API-file.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-04-v6.14-mtd-rawnand-qcom-use-FIELD_PREP-and-GENMASK.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-05-v6.14-mtd-rawnand-qcom-fix-broken-config-in-qcom_param_pag.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-06-v6.14-mtd-rawnand-qcom-Fix-build-issue-on-x86-architecture.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-07-v6.15-spi-spi-qpic-add-driver-for-QCOM-SPI-NAND-flash-Inte.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-08-v6.15-spi-spi-qpic-snand-Fix-ECC_CFG_ECC_DISABLE-shift-in-.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-09-v6.15-spi-spi-qpic-snand-avoid-memleak-in-qcom_spi_ecc_ini.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-10-v6.15-spi-SPI_QPIC_SNAND-should-be-tristate-and-depend-on-.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-11-v6.15-spi-spi-qpic-snand-propagate-errors-from-qcom_spi_block_erase.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-12-v6.15-spi-spi-qpic-snand-fix-NAND_READ_LOCATION_2-register-handling.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/410-13-v6.15-spi-spi-qpic-snand-use-kmalloc-for-OOB-buffer-alloca.patch [new file with mode: 0644]
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 with mode: 0644]
target/linux/generic/backport-6.12/410-v6.13-01-block-add-support-for-defining-read-only-partitions.patch [deleted file]
target/linux/generic/backport-6.12/410-v6.13-03-block-introduce-add_disk_fwnode.patch [deleted file]
target/linux/generic/backport-6.12/410-v6.13-04-mmc-block-attach-partitions-fwnode-if-found-in-mmc-c.patch [deleted file]
target/linux/generic/backport-6.12/410-v6.13-05-block-add-support-for-partition-table-defined-in-OF.patch [deleted file]
target/linux/generic/backport-6.12/412-v6.14-mtd-spinand-add-support-for-FORESEE-F35SQA001G.patch [deleted file]
target/linux/generic/backport-6.12/413-01-v6.14-mtd-rawnand-qcom-cleanup-qcom_nandc-driver.patch [deleted file]
target/linux/generic/backport-6.12/413-02-v6.14-mtd-rawnand-qcom-Add-qcom-prefix-to-common-api.patch [deleted file]
target/linux/generic/backport-6.12/413-03-v6.14-mtd-nand-Add-qpic_common-API-file.patch [deleted file]
target/linux/generic/backport-6.12/413-04-v6.14-mtd-rawnand-qcom-use-FIELD_PREP-and-GENMASK.patch [deleted file]
target/linux/generic/backport-6.12/414-v6.14-mtd-rawnand-qcom-fix-broken-config-in-qcom_param_pag.patch [deleted file]
target/linux/generic/backport-6.12/415-v6.14-mtd-rawnand-qcom-Fix-build-issue-on-x86-architecture.patch [deleted file]
target/linux/generic/backport-6.12/416-v6.15-01-spi-spi-qpic-add-driver-for-QCOM-SPI-NAND-flash-Inte.patch [deleted file]
target/linux/generic/backport-6.12/416-v6.15-02-spi-spi-qpic-snand-Fix-ECC_CFG_ECC_DISABLE-shift-in-.patch [deleted file]
target/linux/generic/backport-6.12/416-v6.15-03-spi-spi-qpic-snand-avoid-memleak-in-qcom_spi_ecc_ini.patch [deleted file]
target/linux/generic/backport-6.12/416-v6.15-04-spi-SPI_QPIC_SNAND-should-be-tristate-and-depend-on-.patch [deleted file]
target/linux/generic/backport-6.12/416-v6.15-05-spi-spi-qpic-snand-propagate-errors-from-qcom_spi_block_erase.patch [deleted file]
target/linux/generic/backport-6.12/416-v6.15-06-spi-spi-qpic-snand-fix-NAND_READ_LOCATION_2-register-handling.patch [deleted file]
target/linux/generic/backport-6.12/416-v6.15-07-spi-spi-qpic-snand-use-kmalloc-for-OOB-buffer-alloca.patch [deleted file]
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]
target/linux/generic/backport-6.12/500-01-v6.13-block-add-support-for-defining-read-only-partitions.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/500-02-v6.13-block-introduce-add_disk_fwnode.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/500-03-v6.13-mmc-block-attach-partitions-fwnode-if-found-in-mmc-c.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/500-04-v6.13-block-add-support-for-partition-table-defined-in-OF.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/600-01-v6.14-net-dsa-add-hook-to-determine-whether-EEE-is-support.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/600-02-v6.14-net-dsa-provide-implementation-of-.support_eee.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/610-01-v6.13-net-dsa-use-ethtool-string-helpers.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/610-02-v6.14-net-dsa-b53-bcm_sf2-implement-.support_eee-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/610-03-v6.15-net-dsa-b53-mdio-add-support-for-BCM53101.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/610-04-v6.16-net-dsa-b53-implement-setting-ageing-time.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/610-05-v6.16-net-dsa-b53-do-not-enable-EEE-on-bcm63xx.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/610-06-v6.16-net-dsa-b53-do-not-enable-RGMII-delay-on-bcm63xx.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/610-07-v6.16-net-dsa-b53-do-not-configure-bcm63xx-s-IMP-port-inte.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/610-08-v6.16-net-dsa-b53-allow-RGMII-for-bcm63xx-RGMII-ports.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/610-09-v6.16-net-dsa-b53-do-not-touch-DLL_IQQD-on-bcm53115.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/611-v6.16-net-dsa-tag_brcm-legacy-fix-pskb_may_pull-length.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/700-01-v6.14-net-dsa-add-hook-to-determine-whether-EEE-is-support.patch [deleted file]
target/linux/generic/backport-6.12/700-02-v6.14-net-dsa-provide-implementation-of-.support_eee.patch [deleted file]
target/linux/generic/backport-6.12/710-01-v6.13-net-dsa-use-ethtool-string-helpers.patch [deleted file]
target/linux/generic/backport-6.12/710-02-v6.14-net-dsa-b53-bcm_sf2-implement-.support_eee-method.patch [deleted file]
target/linux/generic/backport-6.12/710-03-v6.15-net-dsa-b53-mdio-add-support-for-BCM53101.patch [deleted file]
target/linux/generic/backport-6.12/710-04-v6.16-net-dsa-b53-implement-setting-ageing-time.patch [deleted file]
target/linux/generic/backport-6.12/710-05-v6.16-net-dsa-b53-do-not-enable-EEE-on-bcm63xx.patch [deleted file]
target/linux/generic/backport-6.12/710-06-v6.16-net-dsa-b53-do-not-enable-RGMII-delay-on-bcm63xx.patch [deleted file]
target/linux/generic/backport-6.12/710-07-v6.16-net-dsa-b53-do-not-configure-bcm63xx-s-IMP-port-inte.patch [deleted file]
target/linux/generic/backport-6.12/710-08-v6.16-net-dsa-b53-allow-RGMII-for-bcm63xx-RGMII-ports.patch [deleted file]
target/linux/generic/backport-6.12/710-09-v6.16-net-dsa-b53-do-not-touch-DLL_IQQD-on-bcm53115.patch [deleted file]
target/linux/generic/backport-6.12/710-v6.16-igc-enable-HW-vlan-tag-insertion-stripping-by-defaul.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/711-01-v6.16-net-dsa-tag_brcm-legacy-fix-pskb_may_pull-length.patch [deleted file]
target/linux/generic/backport-6.12/720-01-v6.13-net-phy-mediatek-ge-soc-Fix-coding-style.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-02-v6.13-net-phy-mediatek-ge-soc-Shrink-line-wrapping-to-80-c.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-03-v6.13-net-phy-mediatek-ge-soc-Propagate-error-code-correct.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-04-v6.13-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-05-v6.13-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-06-v6.13-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-07-v6.13-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-08-v6.13-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-09-v6.14-net-phy-Constify-struct-mdio_device_id.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-10-v6.15-net-phy-mediatek-Change-to-more-meaningful-macros.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-11-v6.15-net-phy-mediatek-Add-token-ring-access-helper-functi.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-12-v6.15-net-phy-mediatek-Add-token-ring-set-bit-operation-su.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-13-v6.15-net-phy-mediatek-Add-token-ring-clear-bit-operation-.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-14-v6.15-net-phy-mediatek-Move-some-macros-to-phy-lib-for-lat.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-15-v6.16-net-phy-mediatek-permit-to-compile-test-GE-SOC-PHY-d.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-16-v6.16-net-phy-mediatek-add-Airoha-PHY-ID-to-SoC-driver.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-17-v6.16-net-phy-mediatek-init-val-in-.phy_led_polarity_set-f.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-v6.13-net-phy-mediatek-ge-soc-Fix-coding-style.patch [deleted file]
target/linux/generic/backport-6.12/721-01-v6.15-net-ethernet-mediatek-add-EEE-support.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/721-v6.13-net-phy-mediatek-ge-soc-Shrink-line-wrapping-to-80-c.patch [deleted file]
target/linux/generic/backport-6.12/722-v6.13-net-phy-mediatek-ge-soc-Propagate-error-code-correct.patch [deleted file]
target/linux/generic/backport-6.12/723-v6.13-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch [deleted file]
target/linux/generic/backport-6.12/724-v6.13-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch [deleted file]
target/linux/generic/backport-6.12/725-v6.13-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch [deleted file]
target/linux/generic/backport-6.12/726-v6.13-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch [deleted file]
target/linux/generic/backport-6.12/727-v6.13-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch [deleted file]
target/linux/generic/backport-6.12/728-v6.14-net-phy-Constify-struct-mdio_device_id.patch [deleted file]
target/linux/generic/backport-6.12/729-v6.15-net-phy-mediatek-Change-to-more-meaningful-macros.patch [deleted file]
target/linux/generic/backport-6.12/730-01-v6.13-net-phy-aquantia-allow-forcing-order-of-MDI-pairs.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/730-02-v6.13-net-phy-aquantia-fix-return-value-check-in-aqr107_co.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/730-03-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/730-04-v6.13-net-phy-aquantia-correctly-describe-LED-polarity-ove.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/730-05-v6.13-net-phy-mxl-gpy-add-basic-LED-support.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/730-06-v6.13-net-phy-mxl-gpy-add-missing-support-for-TRIGGER_NETD.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/730-07-v6.13-net-phy-mxl-gpy-correctly-describe-LED-polarity.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/730-08-v6.13-net-phy-intel-xway-add-support-for-PHY-LEDs.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/730-v6.15-net-phy-mediatek-Add-token-ring-access-helper-functi.patch [deleted file]
target/linux/generic/backport-6.12/731-v6.15-net-phy-mediatek-Add-token-ring-set-bit-operation-su.patch [deleted file]
target/linux/generic/backport-6.12/732-v6.15-net-phy-mediatek-Add-token-ring-clear-bit-operation-.patch [deleted file]
target/linux/generic/backport-6.12/733-v6.15-net-phy-mediatek-Move-some-macros-to-phy-lib-for-lat.patch [deleted file]
target/linux/generic/backport-6.12/735-v6.16-net-phy-mediatek-permit-to-compile-test-GE-SOC-PHY-d.patch [deleted file]
target/linux/generic/backport-6.12/736-v6.16-net-phy-mediatek-add-Airoha-PHY-ID-to-SoC-driver.patch [deleted file]
target/linux/generic/backport-6.12/737-v6.16-net-phy-mediatek-init-val-in-.phy_led_polarity_set-f.patch [deleted file]
target/linux/generic/backport-6.12/740-v6.13-net-dsa-mv88e6xxx-Support-LED-control.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/753-v6.15-net-ethernet-mediatek-add-EEE-support.patch [deleted file]
target/linux/generic/backport-6.12/792-v6.16-igc-enable-HW-vlan-tag-insertion-stripping-by-defaul.patch [deleted file]
target/linux/generic/backport-6.12/807-v6.15-power-supply-sysfs-remove-duplicate-nul-termination-to-fix-build-with-GCC15.patch [deleted file]
target/linux/generic/backport-6.12/810-v6.14-gpio-regmap-Use-generic-request-free-ops.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/820-v6.15-power-supply-sysfs-remove-duplicate-nul-termination-to-fix-build-with-GCC15.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/839-v6.13-net-phy-aquantia-allow-forcing-order-of-MDI-pairs.patch [deleted file]
target/linux/generic/backport-6.12/840-v6.13-net-phy-aquantia-fix-return-value-check-in-aqr107_co.patch [deleted file]
target/linux/generic/backport-6.12/841-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch [deleted file]
target/linux/generic/backport-6.12/842-v6.13-net-phy-aquantia-correctly-describe-LED-polarity-ove.patch [deleted file]
target/linux/generic/backport-6.12/843-v6.13-net-phy-mxl-gpy-add-basic-LED-support.patch [deleted file]
target/linux/generic/backport-6.12/844-v6.13-net-phy-mxl-gpy-add-missing-support-for-TRIGGER_NETD.patch [deleted file]
target/linux/generic/backport-6.12/845-v6.13-net-phy-mxl-gpy-correctly-describe-LED-polarity.patch [deleted file]
target/linux/generic/backport-6.12/846-v6.13-net-phy-intel-xway-add-support-for-PHY-LEDs.patch [deleted file]
target/linux/generic/backport-6.12/880-v6.14-gpio-regmap-Use-generic-request-free-ops.patch [deleted file]
target/linux/generic/backport-6.12/901-v6.13-net-dsa-mv88e6xxx-Support-LED-control.patch [deleted file]
target/linux/generic/backport-6.12/902-v6.13-fortify-Hide-run-time-copy-size-from-value-range-tracking.patch [deleted file]

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 (file)
index 0000000..ad9af1d
--- /dev/null
@@ -0,0 +1,60 @@
+From b35108a51cf7bab58d7eace1267d7965978bcdb8 Mon Sep 17 00:00:00 2001
+From: Easwar Hariharan <[email protected]>
+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 <[email protected]>
+Signed-off-by: Easwar Hariharan <[email protected]>
+Signed-off-by: Thomas Gleixner <[email protected]>
+Reviewed-by: Luiz Augusto von Dentz <[email protected]>
+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 (file)
index 0000000..cddd558
--- /dev/null
@@ -0,0 +1,35 @@
+From bb2784d9ab49587ba4fbff37a319fff2924db289 Mon Sep 17 00:00:00 2001
+From: Easwar Hariharan <[email protected]>
+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 <[email protected]>
+Signed-off-by: Easwar Hariharan <[email protected]>
+Signed-off-by: Thomas Gleixner <[email protected]>
+Link: https://lore.kernel.org/all/[email protected]
+Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
+---
+ 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 (file)
index a0d2273..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-From 0f4ae7c6ecb89bfda026d210dcf8216fb67d2333 Mon Sep 17 00:00:00 2001
-From: Khem Raj <[email protected]>
-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 <[email protected]>
-Signed-off-by: Thomas Bogendoerfer <[email protected]>
----
- 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 (file)
index 0000000..8dca649
--- /dev/null
@@ -0,0 +1,155 @@
+From 239d87327dcd361b0098038995f8908f3296864f Mon Sep 17 00:00:00 2001
+From: Kees Cook <[email protected]>
+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" <[email protected]>
+Closes: https://lore.kernel.org/all/[email protected]/
+Reported-by: Nilay Shroff <[email protected]>
+Closes: https://lore.kernel.org/all/[email protected]/
+Tested-by: Nilay Shroff <[email protected]>
+Acked-by: Yury Norov <[email protected]>
+Acked-by: Greg Kroah-Hartman <[email protected]>
+Signed-off-by: Kees Cook <[email protected]>
+---
+ 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 (file)
index 0000000..a0d2273
--- /dev/null
@@ -0,0 +1,44 @@
+From 0f4ae7c6ecb89bfda026d210dcf8216fb67d2333 Mon Sep 17 00:00:00 2001
+From: Khem Raj <[email protected]>
+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 <[email protected]>
+Signed-off-by: Thomas Bogendoerfer <[email protected]>
+---
+ 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 (file)
index ad9af1d..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-From b35108a51cf7bab58d7eace1267d7965978bcdb8 Mon Sep 17 00:00:00 2001
-From: Easwar Hariharan <[email protected]>
-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 <[email protected]>
-Signed-off-by: Easwar Hariharan <[email protected]>
-Signed-off-by: Thomas Gleixner <[email protected]>
-Reviewed-by: Luiz Augusto von Dentz <[email protected]>
-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 (file)
index cddd558..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From bb2784d9ab49587ba4fbff37a319fff2924db289 Mon Sep 17 00:00:00 2001
-From: Easwar Hariharan <[email protected]>
-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 <[email protected]>
-Signed-off-by: Easwar Hariharan <[email protected]>
-Signed-off-by: Thomas Gleixner <[email protected]>
-Link: https://lore.kernel.org/all/[email protected]
-Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
----
- 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 (file)
index 0000000..84b3b2a
--- /dev/null
@@ -0,0 +1,38 @@
+From ae461cde5c559675fc4c0ba351c7c31ace705f56 Mon Sep 17 00:00:00 2001
+From: Bohdan Chubuk <[email protected]>
+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 <[email protected]>
+Signed-off-by: Miquel Raynal <[email protected]>
+---
+ 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 (file)
index 0000000..8c5457a
--- /dev/null
@@ -0,0 +1,1013 @@
+From 8c52932da5e6756fa66f52f0720da283fba13aa6 Mon Sep 17 00:00:00 2001
+From: Md Sadre Alam <[email protected]>
+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 <[email protected]>
+Signed-off-by: Miquel Raynal <[email protected]>
+---
+ 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 &regs->cmd;
+-      case NAND_ADDR0:
+-              return &regs->addr0;
+-      case NAND_ADDR1:
+-              return &regs->addr1;
+-      case NAND_FLASH_CHIP_SELECT:
+-              return &regs->chip_sel;
+-      case NAND_EXEC_CMD:
+-              return &regs->exec;
+-      case NAND_FLASH_STATUS:
+-              return &regs->clrflashstatus;
+-      case NAND_DEV0_CFG0:
+-              return &regs->cfg0;
+-      case NAND_DEV0_CFG1:
+-              return &regs->cfg1;
+-      case NAND_DEV0_ECC_CFG:
+-              return &regs->ecc_bch_cfg;
+-      case NAND_READ_STATUS:
+-              return &regs->clrreadstatus;
+-      case NAND_DEV_CMD1:
+-              return &regs->cmd1;
+-      case NAND_DEV_CMD1_RESTORE:
+-              return &regs->orig_cmd1;
+-      case NAND_DEV_CMD_VLD:
+-              return &regs->vld;
+-      case NAND_DEV_CMD_VLD_RESTORE:
+-              return &regs->orig_vld;
+-      case NAND_EBI2_ECC_BUF_CFG:
+-              return &regs->ecc_buf_cfg;
+-      case NAND_READ_LOCATION_0:
+-              return &regs->read_location0;
+-      case NAND_READ_LOCATION_1:
+-              return &regs->read_location1;
+-      case NAND_READ_LOCATION_2:
+-              return &regs->read_location2;
+-      case NAND_READ_LOCATION_3:
+-              return &regs->read_location3;
+-      case NAND_READ_LOCATION_LAST_CW_0:
+-              return &regs->read_location_last0;
+-      case NAND_READ_LOCATION_LAST_CW_1:
+-              return &regs->read_location_last1;
+-      case NAND_READ_LOCATION_LAST_CW_2:
+-              return &regs->read_location_last2;
+-      case NAND_READ_LOCATION_LAST_CW_3:
+-              return &regs->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 = &regs->erased_cw_detect_cfg_set;
+-              else
+-                      vaddr = &regs->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 (file)
index 0000000..078a56c
--- /dev/null
@@ -0,0 +1,880 @@
+From 1d479f5b345e0c3650fec4dddeef9fc6fab30c8b Mon Sep 17 00:00:00 2001
+From: Md Sadre Alam <[email protected]>
+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 <[email protected]>
+Signed-off-by: Md Sadre Alam <[email protected]>
+Signed-off-by: Miquel Raynal <[email protected]>
+---
+ 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 (file)
index 0000000..2621146
--- /dev/null
@@ -0,0 +1,2436 @@
+From fdf3ee5c6e5278dab4f60b998b47ed2d510bf80f Mon Sep 17 00:00:00 2001
+From: Md Sadre Alam <[email protected]>
+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 <[email protected]>
+Signed-off-by: Miquel Raynal <[email protected]>
+---
+ drivers/mtd/nand/Makefile            |    2 +-
+ drivers/mtd/nand/qpic_common.c       |  759 ++++++++++++++++++
+ drivers/mtd/nand/raw/qcom_nandc.c    | 1092 +-------------------------
+ include/linux/mtd/nand-qpic-common.h |  468 +++++++++++
+ 4 files changed, 1240 insertions(+), 1081 deletions(-)
+ create mode 100644 drivers/mtd/nand/qpic_common.c
+ create mode 100644 include/linux/mtd/nand-qpic-common.h
+
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -3,7 +3,7 @@
+ nandcore-objs := core.o bbt.o
+ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
+ obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
+-
++obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o
+ obj-y += onenand/
+ obj-y += raw/
+ obj-y += spi/
+--- /dev/null
++++ b/drivers/mtd/nand/qpic_common.c
+@@ -0,0 +1,759 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
++ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved
++ */
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/dma/qcom_adm.h>
++#include <linux/dma/qcom_bam_dma.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/nand-qpic-common.h>
++
++/**
++ * qcom_free_bam_transaction() - Frees the BAM transaction memory
++ * @nandc: qpic nand controller
++ *
++ * This function frees the bam transaction memory
++ */
++void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
++{
++      struct bam_transaction *bam_txn = nandc->bam_txn;
++
++      kfree(bam_txn);
++}
++EXPORT_SYMBOL(qcom_free_bam_transaction);
++
++/**
++ * qcom_alloc_bam_transaction() - allocate BAM transaction
++ * @nandc: qpic nand controller
++ *
++ * This function will allocate and initialize the BAM transaction structure
++ */
++struct bam_transaction *
++qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
++{
++      struct bam_transaction *bam_txn;
++      size_t bam_txn_size;
++      unsigned int num_cw = nandc->max_cwperpage;
++      void *bam_txn_buf;
++
++      bam_txn_size =
++              sizeof(*bam_txn) + num_cw *
++              ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
++              (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
++              (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
++
++      bam_txn_buf = kzalloc(bam_txn_size, GFP_KERNEL);
++      if (!bam_txn_buf)
++              return NULL;
++
++      bam_txn = bam_txn_buf;
++      bam_txn_buf += sizeof(*bam_txn);
++
++      bam_txn->bam_ce = bam_txn_buf;
++      bam_txn_buf +=
++              sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
++
++      bam_txn->cmd_sgl = bam_txn_buf;
++      bam_txn_buf +=
++              sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
++
++      bam_txn->data_sgl = bam_txn_buf;
++
++      init_completion(&bam_txn->txn_done);
++
++      return bam_txn;
++}
++EXPORT_SYMBOL(qcom_alloc_bam_transaction);
++
++/**
++ * qcom_clear_bam_transaction() - Clears the BAM transaction
++ * @nandc: qpic nand controller
++ *
++ * This function will clear the BAM transaction indexes.
++ */
++void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
++{
++      struct bam_transaction *bam_txn = nandc->bam_txn;
++
++      if (!nandc->props->supports_bam)
++              return;
++
++      memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
++      bam_txn->last_data_desc = NULL;
++
++      sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
++                    QPIC_PER_CW_CMD_SGL);
++      sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
++                    QPIC_PER_CW_DATA_SGL);
++
++      reinit_completion(&bam_txn->txn_done);
++}
++EXPORT_SYMBOL(qcom_clear_bam_transaction);
++
++/**
++ * qcom_qpic_bam_dma_done() - Callback for DMA descriptor completion
++ * @data: data pointer
++ *
++ * This function is a callback for DMA descriptor completion
++ */
++void qcom_qpic_bam_dma_done(void *data)
++{
++      struct bam_transaction *bam_txn = data;
++
++      complete(&bam_txn->txn_done);
++}
++EXPORT_SYMBOL(qcom_qpic_bam_dma_done);
++
++/**
++ * qcom_nandc_dev_to_mem() - Check for dma sync for cpu or device
++ * @nandc: qpic nand controller
++ * @is_cpu: cpu or Device
++ *
++ * This function will check for dma sync for cpu or device
++ */
++inline void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
++{
++      if (!nandc->props->supports_bam)
++              return;
++
++      if (is_cpu)
++              dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
++                                      MAX_REG_RD *
++                                      sizeof(*nandc->reg_read_buf),
++                                      DMA_FROM_DEVICE);
++      else
++              dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
++                                         MAX_REG_RD *
++                                         sizeof(*nandc->reg_read_buf),
++                                         DMA_FROM_DEVICE);
++}
++EXPORT_SYMBOL(qcom_nandc_dev_to_mem);
++
++/**
++ * qcom_prepare_bam_async_desc() - Prepare DMA descriptor
++ * @nandc: qpic nand controller
++ * @chan: dma channel
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function maps the scatter gather list for DMA transfer and forms the
++ * DMA descriptor for BAM.This descriptor will be added in the NAND DMA
++ * descriptor queue which will be submitted to DMA engine.
++ */
++int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
++                              struct dma_chan *chan, unsigned long flags)
++{
++      struct desc_info *desc;
++      struct scatterlist *sgl;
++      unsigned int sgl_cnt;
++      int ret;
++      struct bam_transaction *bam_txn = nandc->bam_txn;
++      enum dma_transfer_direction dir_eng;
++      struct dma_async_tx_descriptor *dma_desc;
++
++      desc = kzalloc(sizeof(*desc), GFP_KERNEL);
++      if (!desc)
++              return -ENOMEM;
++
++      if (chan == nandc->cmd_chan) {
++              sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
++              sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
++              bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
++              dir_eng = DMA_MEM_TO_DEV;
++              desc->dir = DMA_TO_DEVICE;
++      } else if (chan == nandc->tx_chan) {
++              sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
++              sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
++              bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
++              dir_eng = DMA_MEM_TO_DEV;
++              desc->dir = DMA_TO_DEVICE;
++      } else {
++              sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
++              sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
++              bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
++              dir_eng = DMA_DEV_TO_MEM;
++              desc->dir = DMA_FROM_DEVICE;
++      }
++
++      sg_mark_end(sgl + sgl_cnt - 1);
++      ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
++      if (ret == 0) {
++              dev_err(nandc->dev, "failure in mapping desc\n");
++              kfree(desc);
++              return -ENOMEM;
++      }
++
++      desc->sgl_cnt = sgl_cnt;
++      desc->bam_sgl = sgl;
++
++      dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
++                                         flags);
++
++      if (!dma_desc) {
++              dev_err(nandc->dev, "failure in prep desc\n");
++              dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
++              kfree(desc);
++              return -EINVAL;
++      }
++
++      desc->dma_desc = dma_desc;
++
++      /* update last data/command descriptor */
++      if (chan == nandc->cmd_chan)
++              bam_txn->last_cmd_desc = dma_desc;
++      else
++              bam_txn->last_data_desc = dma_desc;
++
++      list_add_tail(&desc->node, &nandc->desc_list);
++
++      return 0;
++}
++EXPORT_SYMBOL(qcom_prepare_bam_async_desc);
++
++/**
++ * qcom_prep_bam_dma_desc_cmd() - Prepares the command descriptor for BAM DMA
++ * @nandc: qpic nand controller
++ * @read: read or write type
++ * @reg_off: offset within the controller's data buffer
++ * @vaddr: virtual address of the buffer we want to write to
++ * @size: DMA transaction size in bytes
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares the command descriptor for BAM DMA
++ * which will be used for NAND register reads and writes.
++ */
++int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
++                             int reg_off, const void *vaddr,
++                             int size, unsigned int flags)
++{
++      int bam_ce_size;
++      int i, ret;
++      struct bam_cmd_element *bam_ce_buffer;
++      struct bam_transaction *bam_txn = nandc->bam_txn;
++
++      bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
++
++      /* fill the command desc */
++      for (i = 0; i < size; i++) {
++              if (read)
++                      bam_prep_ce(&bam_ce_buffer[i],
++                                  nandc_reg_phys(nandc, reg_off + 4 * i),
++                                  BAM_READ_COMMAND,
++                                  reg_buf_dma_addr(nandc,
++                                                   (__le32 *)vaddr + i));
++              else
++                      bam_prep_ce_le32(&bam_ce_buffer[i],
++                                       nandc_reg_phys(nandc, reg_off + 4 * i),
++                                       BAM_WRITE_COMMAND,
++                                       *((__le32 *)vaddr + i));
++      }
++
++      bam_txn->bam_ce_pos += size;
++
++      /* use the separate sgl after this command */
++      if (flags & NAND_BAM_NEXT_SGL) {
++              bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
++              bam_ce_size = (bam_txn->bam_ce_pos -
++                              bam_txn->bam_ce_start) *
++                              sizeof(struct bam_cmd_element);
++              sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
++                         bam_ce_buffer, bam_ce_size);
++              bam_txn->cmd_sgl_pos++;
++              bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
++
++              if (flags & NAND_BAM_NWD) {
++                      ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
++                                                        DMA_PREP_FENCE | DMA_PREP_CMD);
++                      if (ret)
++                              return ret;
++              }
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(qcom_prep_bam_dma_desc_cmd);
++
++/**
++ * qcom_prep_bam_dma_desc_data() - Prepares the data descriptor for BAM DMA
++ * @nandc: qpic nand controller
++ * @read: read or write type
++ * @vaddr: virtual address of the buffer we want to write to
++ * @size: DMA transaction size in bytes
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares the data descriptor for BAM DMA which
++ * will be used for NAND data reads and writes.
++ */
++int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
++                              const void *vaddr, int size, unsigned int flags)
++{
++      int ret;
++      struct bam_transaction *bam_txn = nandc->bam_txn;
++
++      if (read) {
++              sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
++                         vaddr, size);
++              bam_txn->rx_sgl_pos++;
++      } else {
++              sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
++                         vaddr, size);
++              bam_txn->tx_sgl_pos++;
++
++              /*
++               * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
++               * is not set, form the DMA descriptor
++               */
++              if (!(flags & NAND_BAM_NO_EOT)) {
++                      ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
++                                                        DMA_PREP_INTERRUPT);
++                      if (ret)
++                              return ret;
++              }
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(qcom_prep_bam_dma_desc_data);
++
++/**
++ * qcom_prep_adm_dma_desc() - Prepare descriptor for adma
++ * @nandc: qpic nand controller
++ * @read: read or write type
++ * @reg_off: offset within the controller's data buffer
++ * @vaddr: virtual address of the buffer we want to write to
++ * @size: adm dma transaction size in bytes
++ * @flow_control: flow controller
++ *
++ * This function will prepare descriptor for adma
++ */
++int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
++                         int reg_off, const void *vaddr, int size,
++                         bool flow_control)
++{
++      struct qcom_adm_peripheral_config periph_conf = {};
++      struct dma_async_tx_descriptor *dma_desc;
++      struct dma_slave_config slave_conf = {0};
++      enum dma_transfer_direction dir_eng;
++      struct desc_info *desc;
++      struct scatterlist *sgl;
++      int ret;
++
++      desc = kzalloc(sizeof(*desc), GFP_KERNEL);
++      if (!desc)
++              return -ENOMEM;
++
++      sgl = &desc->adm_sgl;
++
++      sg_init_one(sgl, vaddr, size);
++
++      if (read) {
++              dir_eng = DMA_DEV_TO_MEM;
++              desc->dir = DMA_FROM_DEVICE;
++      } else {
++              dir_eng = DMA_MEM_TO_DEV;
++              desc->dir = DMA_TO_DEVICE;
++      }
++
++      ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
++      if (!ret) {
++              ret = -ENOMEM;
++              goto err;
++      }
++
++      slave_conf.device_fc = flow_control;
++      if (read) {
++              slave_conf.src_maxburst = 16;
++              slave_conf.src_addr = nandc->base_dma + reg_off;
++              if (nandc->data_crci) {
++                      periph_conf.crci = nandc->data_crci;
++                      slave_conf.peripheral_config = &periph_conf;
++                      slave_conf.peripheral_size = sizeof(periph_conf);
++              }
++      } else {
++              slave_conf.dst_maxburst = 16;
++              slave_conf.dst_addr = nandc->base_dma + reg_off;
++              if (nandc->cmd_crci) {
++                      periph_conf.crci = nandc->cmd_crci;
++                      slave_conf.peripheral_config = &periph_conf;
++                      slave_conf.peripheral_size = sizeof(periph_conf);
++              }
++      }
++
++      ret = dmaengine_slave_config(nandc->chan, &slave_conf);
++      if (ret) {
++              dev_err(nandc->dev, "failed to configure dma channel\n");
++              goto err;
++      }
++
++      dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
++      if (!dma_desc) {
++              dev_err(nandc->dev, "failed to prepare desc\n");
++              ret = -EINVAL;
++              goto err;
++      }
++
++      desc->dma_desc = dma_desc;
++
++      list_add_tail(&desc->node, &nandc->desc_list);
++
++      return 0;
++err:
++      kfree(desc);
++
++      return ret;
++}
++EXPORT_SYMBOL(qcom_prep_adm_dma_desc);
++
++/**
++ * qcom_read_reg_dma() - read a given number of registers to the reg_read_buf pointer
++ * @nandc: qpic nand controller
++ * @first: offset of the first register in the contiguous block
++ * @num_regs: number of registers to read
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares a descriptor to read a given number of
++ * contiguous registers to the reg_read_buf pointer.
++ */
++int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
++                    int num_regs, unsigned int flags)
++{
++      bool flow_control = false;
++      void *vaddr;
++
++      vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
++      nandc->reg_read_pos += num_regs;
++
++      if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
++              first = dev_cmd_reg_addr(nandc, first);
++
++      if (nandc->props->supports_bam)
++              return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
++                                           num_regs, flags);
++
++      if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
++              flow_control = true;
++
++      return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
++                                    num_regs * sizeof(u32), flow_control);
++}
++EXPORT_SYMBOL(qcom_read_reg_dma);
++
++/**
++ * qcom_write_reg_dma() - write a given number of registers
++ * @nandc: qpic nand controller
++ * @vaddr: contiguous memory from where register value will
++ *       be written
++ * @first: offset of the first register in the contiguous block
++ * @num_regs: number of registers to write
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares a descriptor to write a given number of
++ * contiguous registers
++ */
++int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
++                     int first, int num_regs, unsigned int flags)
++{
++      bool flow_control = false;
++
++      if (first == NAND_EXEC_CMD)
++              flags |= NAND_BAM_NWD;
++
++      if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
++              first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
++
++      if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
++              first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
++
++      if (nandc->props->supports_bam)
++              return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
++                                                num_regs, flags);
++
++      if (first == NAND_FLASH_CMD)
++              flow_control = true;
++
++      return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
++                                    num_regs * sizeof(u32), flow_control);
++}
++EXPORT_SYMBOL(qcom_write_reg_dma);
++
++/**
++ * qcom_read_data_dma() - transfer data
++ * @nandc: qpic nand controller
++ * @reg_off: offset within the controller's data buffer
++ * @vaddr: virtual address of the buffer we want to write to
++ * @size: DMA transaction size in bytes
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares a DMA descriptor to transfer data from the
++ * controller's internal buffer to the buffer 'vaddr'
++ */
++int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
++                     const u8 *vaddr, int size, unsigned int flags)
++{
++      if (nandc->props->supports_bam)
++              return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
++
++      return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
++}
++EXPORT_SYMBOL(qcom_read_data_dma);
++
++/**
++ * qcom_write_data_dma() - transfer data
++ * @nandc: qpic nand controller
++ * @reg_off: offset within the controller's data buffer
++ * @vaddr: virtual address of the buffer we want to read from
++ * @size: DMA transaction size in bytes
++ * @flags: flags to control DMA descriptor preparation
++ *
++ * This function will prepares a DMA descriptor to transfer data from
++ * 'vaddr' to the controller's internal buffer
++ */
++int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
++                      const u8 *vaddr, int size, unsigned int flags)
++{
++      if (nandc->props->supports_bam)
++              return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
++
++      return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
++}
++EXPORT_SYMBOL(qcom_write_data_dma);
++
++/**
++ * qcom_submit_descs() - submit dma descriptor
++ * @nandc: qpic nand controller
++ *
++ * This function will submit all the prepared dma descriptor
++ * cmd or data descriptor
++ */
++int qcom_submit_descs(struct qcom_nand_controller *nandc)
++{
++      struct desc_info *desc, *n;
++      dma_cookie_t cookie = 0;
++      struct bam_transaction *bam_txn = nandc->bam_txn;
++      int ret = 0;
++
++      if (nandc->props->supports_bam) {
++              if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
++                      ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
++                      if (ret)
++                              goto err_unmap_free_desc;
++              }
++
++              if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
++                      ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
++                                                        DMA_PREP_INTERRUPT);
++                      if (ret)
++                              goto err_unmap_free_desc;
++              }
++
++              if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
++                      ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
++                                                        DMA_PREP_CMD);
++                      if (ret)
++                              goto err_unmap_free_desc;
++              }
++      }
++
++      list_for_each_entry(desc, &nandc->desc_list, node)
++              cookie = dmaengine_submit(desc->dma_desc);
++
++      if (nandc->props->supports_bam) {
++              bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
++              bam_txn->last_cmd_desc->callback_param = bam_txn;
++
++              dma_async_issue_pending(nandc->tx_chan);
++              dma_async_issue_pending(nandc->rx_chan);
++              dma_async_issue_pending(nandc->cmd_chan);
++
++              if (!wait_for_completion_timeout(&bam_txn->txn_done,
++                                               QPIC_NAND_COMPLETION_TIMEOUT))
++                      ret = -ETIMEDOUT;
++      } else {
++              if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
++                      ret = -ETIMEDOUT;
++      }
++
++err_unmap_free_desc:
++      /*
++       * Unmap the dma sg_list and free the desc allocated by both
++       * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
++       */
++      list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
++              list_del(&desc->node);
++
++              if (nandc->props->supports_bam)
++                      dma_unmap_sg(nandc->dev, desc->bam_sgl,
++                                   desc->sgl_cnt, desc->dir);
++              else
++                      dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
++                                   desc->dir);
++
++              kfree(desc);
++      }
++
++      return ret;
++}
++EXPORT_SYMBOL(qcom_submit_descs);
++
++/**
++ * qcom_clear_read_regs() - reset the read register buffer
++ * @nandc: qpic nand controller
++ *
++ * This function reset the register read buffer for next NAND operation
++ */
++void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
++{
++      nandc->reg_read_pos = 0;
++      qcom_nandc_dev_to_mem(nandc, false);
++}
++EXPORT_SYMBOL(qcom_clear_read_regs);
++
++/**
++ * qcom_nandc_unalloc() - unallocate qpic nand controller
++ * @nandc: qpic nand controller
++ *
++ * This function will unallocate memory alloacted for qpic nand controller
++ */
++void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
++{
++      if (nandc->props->supports_bam) {
++              if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
++                      dma_unmap_single(nandc->dev, nandc->reg_read_dma,
++                                       MAX_REG_RD *
++                                       sizeof(*nandc->reg_read_buf),
++                                       DMA_FROM_DEVICE);
++
++              if (nandc->tx_chan)
++                      dma_release_channel(nandc->tx_chan);
++
++              if (nandc->rx_chan)
++                      dma_release_channel(nandc->rx_chan);
++
++              if (nandc->cmd_chan)
++                      dma_release_channel(nandc->cmd_chan);
++      } else {
++              if (nandc->chan)
++                      dma_release_channel(nandc->chan);
++      }
++}
++EXPORT_SYMBOL(qcom_nandc_unalloc);
++
++/**
++ * qcom_nandc_alloc() - Allocate qpic nand controller
++ * @nandc: qpic nand controller
++ *
++ * This function will allocate memory for qpic nand controller
++ */
++int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
++{
++      int ret;
++
++      ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
++      if (ret) {
++              dev_err(nandc->dev, "failed to set DMA mask\n");
++              return ret;
++      }
++
++      /*
++       * we use the internal buffer for reading ONFI params, reading small
++       * data like ID and status, and preforming read-copy-write operations
++       * when writing to a codeword partially. 532 is the maximum possible
++       * size of a codeword for our nand controller
++       */
++      nandc->buf_size = 532;
++
++      nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
++      if (!nandc->data_buffer)
++              return -ENOMEM;
++
++      nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
++      if (!nandc->regs)
++              return -ENOMEM;
++
++      nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
++                                         sizeof(*nandc->reg_read_buf),
++                                         GFP_KERNEL);
++      if (!nandc->reg_read_buf)
++              return -ENOMEM;
++
++      if (nandc->props->supports_bam) {
++              nandc->reg_read_dma =
++                      dma_map_single(nandc->dev, nandc->reg_read_buf,
++                                     MAX_REG_RD *
++                                     sizeof(*nandc->reg_read_buf),
++                                     DMA_FROM_DEVICE);
++              if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
++                      dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
++                      return -EIO;
++              }
++
++              nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
++              if (IS_ERR(nandc->tx_chan)) {
++                      ret = PTR_ERR(nandc->tx_chan);
++                      nandc->tx_chan = NULL;
++                      dev_err_probe(nandc->dev, ret,
++                                    "tx DMA channel request failed\n");
++                      goto unalloc;
++              }
++
++              nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
++              if (IS_ERR(nandc->rx_chan)) {
++                      ret = PTR_ERR(nandc->rx_chan);
++                      nandc->rx_chan = NULL;
++                      dev_err_probe(nandc->dev, ret,
++                                    "rx DMA channel request failed\n");
++                      goto unalloc;
++              }
++
++              nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
++              if (IS_ERR(nandc->cmd_chan)) {
++                      ret = PTR_ERR(nandc->cmd_chan);
++                      nandc->cmd_chan = NULL;
++                      dev_err_probe(nandc->dev, ret,
++                                    "cmd DMA channel request failed\n");
++                      goto unalloc;
++              }
++
++              /*
++               * Initially allocate BAM transaction to read ONFI param page.
++               * After detecting all the devices, this BAM transaction will
++               * be freed and the next BAM transaction will be allocated with
++               * maximum codeword size
++               */
++              nandc->max_cwperpage = 1;
++              nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
++              if (!nandc->bam_txn) {
++                      dev_err(nandc->dev,
++                              "failed to allocate bam transaction\n");
++                      ret = -ENOMEM;
++                      goto unalloc;
++              }
++      } else {
++              nandc->chan = dma_request_chan(nandc->dev, "rxtx");
++              if (IS_ERR(nandc->chan)) {
++                      ret = PTR_ERR(nandc->chan);
++                      nandc->chan = NULL;
++                      dev_err_probe(nandc->dev, ret,
++                                    "rxtx DMA channel request failed\n");
++                      return ret;
++              }
++      }
++
++      INIT_LIST_HEAD(&nandc->desc_list);
++      INIT_LIST_HEAD(&nandc->host_list);
++
++      return 0;
++unalloc:
++      qcom_nandc_unalloc(nandc);
++      return ret;
++}
++EXPORT_SYMBOL(qcom_nandc_alloc);
++
++MODULE_DESCRIPTION("QPIC controller common api");
++MODULE_LICENSE("GPL");
+--- a/drivers/mtd/nand/raw/qcom_nandc.c
++++ b/drivers/mtd/nand/raw/qcom_nandc.c
+@@ -15,417 +15,7 @@
+ #include <linux/of.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+-
+-/* NANDc reg offsets */
+-#define       NAND_FLASH_CMD                  0x00
+-#define       NAND_ADDR0                      0x04
+-#define       NAND_ADDR1                      0x08
+-#define       NAND_FLASH_CHIP_SELECT          0x0c
+-#define       NAND_EXEC_CMD                   0x10
+-#define       NAND_FLASH_STATUS               0x14
+-#define       NAND_BUFFER_STATUS              0x18
+-#define       NAND_DEV0_CFG0                  0x20
+-#define       NAND_DEV0_CFG1                  0x24
+-#define       NAND_DEV0_ECC_CFG               0x28
+-#define       NAND_AUTO_STATUS_EN             0x2c
+-#define       NAND_DEV1_CFG0                  0x30
+-#define       NAND_DEV1_CFG1                  0x34
+-#define       NAND_READ_ID                    0x40
+-#define       NAND_READ_STATUS                0x44
+-#define       NAND_DEV_CMD0                   0xa0
+-#define       NAND_DEV_CMD1                   0xa4
+-#define       NAND_DEV_CMD2                   0xa8
+-#define       NAND_DEV_CMD_VLD                0xac
+-#define       SFLASHC_BURST_CFG               0xe0
+-#define       NAND_ERASED_CW_DETECT_CFG       0xe8
+-#define       NAND_ERASED_CW_DETECT_STATUS    0xec
+-#define       NAND_EBI2_ECC_BUF_CFG           0xf0
+-#define       FLASH_BUF_ACC                   0x100
+-
+-#define       NAND_CTRL                       0xf00
+-#define       NAND_VERSION                    0xf08
+-#define       NAND_READ_LOCATION_0            0xf20
+-#define       NAND_READ_LOCATION_1            0xf24
+-#define       NAND_READ_LOCATION_2            0xf28
+-#define       NAND_READ_LOCATION_3            0xf2c
+-#define       NAND_READ_LOCATION_LAST_CW_0    0xf40
+-#define       NAND_READ_LOCATION_LAST_CW_1    0xf44
+-#define       NAND_READ_LOCATION_LAST_CW_2    0xf48
+-#define       NAND_READ_LOCATION_LAST_CW_3    0xf4c
+-
+-/* dummy register offsets, used by qcom_write_reg_dma */
+-#define       NAND_DEV_CMD1_RESTORE           0xdead
+-#define       NAND_DEV_CMD_VLD_RESTORE        0xbeef
+-
+-/* NAND_FLASH_CMD bits */
+-#define       PAGE_ACC                        BIT(4)
+-#define       LAST_PAGE                       BIT(5)
+-
+-/* NAND_FLASH_CHIP_SELECT bits */
+-#define       NAND_DEV_SEL                    0
+-#define       DM_EN                           BIT(2)
+-
+-/* NAND_FLASH_STATUS bits */
+-#define       FS_OP_ERR                       BIT(4)
+-#define       FS_READY_BSY_N                  BIT(5)
+-#define       FS_MPU_ERR                      BIT(8)
+-#define       FS_DEVICE_STS_ERR               BIT(16)
+-#define       FS_DEVICE_WP                    BIT(23)
+-
+-/* NAND_BUFFER_STATUS bits */
+-#define       BS_UNCORRECTABLE_BIT            BIT(8)
+-#define       BS_CORRECTABLE_ERR_MSK          0x1f
+-
+-/* NAND_DEVn_CFG0 bits */
+-#define       DISABLE_STATUS_AFTER_WRITE      4
+-#define       CW_PER_PAGE                     6
+-#define       UD_SIZE_BYTES                   9
+-#define       UD_SIZE_BYTES_MASK              GENMASK(18, 9)
+-#define       ECC_PARITY_SIZE_BYTES_RS        19
+-#define       SPARE_SIZE_BYTES                23
+-#define       SPARE_SIZE_BYTES_MASK           GENMASK(26, 23)
+-#define       NUM_ADDR_CYCLES                 27
+-#define       STATUS_BFR_READ                 30
+-#define       SET_RD_MODE_AFTER_STATUS        31
+-
+-/* NAND_DEVn_CFG0 bits */
+-#define       DEV0_CFG1_ECC_DISABLE           0
+-#define       WIDE_FLASH                      1
+-#define       NAND_RECOVERY_CYCLES            2
+-#define       CS_ACTIVE_BSY                   5
+-#define       BAD_BLOCK_BYTE_NUM              6
+-#define       BAD_BLOCK_IN_SPARE_AREA         16
+-#define       WR_RD_BSY_GAP                   17
+-#define       ENABLE_BCH_ECC                  27
+-
+-/* NAND_DEV0_ECC_CFG bits */
+-#define       ECC_CFG_ECC_DISABLE             0
+-#define       ECC_SW_RESET                    1
+-#define       ECC_MODE                        4
+-#define       ECC_PARITY_SIZE_BYTES_BCH       8
+-#define       ECC_NUM_DATA_BYTES              16
+-#define       ECC_NUM_DATA_BYTES_MASK         GENMASK(25, 16)
+-#define       ECC_FORCE_CLK_OPEN              30
+-
+-/* NAND_DEV_CMD1 bits */
+-#define       READ_ADDR                       0
+-
+-/* NAND_DEV_CMD_VLD bits */
+-#define       READ_START_VLD                  BIT(0)
+-#define       READ_STOP_VLD                   BIT(1)
+-#define       WRITE_START_VLD                 BIT(2)
+-#define       ERASE_START_VLD                 BIT(3)
+-#define       SEQ_READ_START_VLD              BIT(4)
+-
+-/* NAND_EBI2_ECC_BUF_CFG bits */
+-#define       NUM_STEPS                       0
+-
+-/* NAND_ERASED_CW_DETECT_CFG bits */
+-#define       ERASED_CW_ECC_MASK              1
+-#define       AUTO_DETECT_RES                 0
+-#define       MASK_ECC                        BIT(ERASED_CW_ECC_MASK)
+-#define       RESET_ERASED_DET                BIT(AUTO_DETECT_RES)
+-#define       ACTIVE_ERASED_DET               (0 << AUTO_DETECT_RES)
+-#define       CLR_ERASED_PAGE_DET             (RESET_ERASED_DET | MASK_ECC)
+-#define       SET_ERASED_PAGE_DET             (ACTIVE_ERASED_DET | MASK_ECC)
+-
+-/* NAND_ERASED_CW_DETECT_STATUS bits */
+-#define       PAGE_ALL_ERASED                 BIT(7)
+-#define       CODEWORD_ALL_ERASED             BIT(6)
+-#define       PAGE_ERASED                     BIT(5)
+-#define       CODEWORD_ERASED                 BIT(4)
+-#define       ERASED_PAGE                     (PAGE_ALL_ERASED | PAGE_ERASED)
+-#define       ERASED_CW                       (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
+-
+-/* NAND_READ_LOCATION_n bits */
+-#define READ_LOCATION_OFFSET          0
+-#define READ_LOCATION_SIZE            16
+-#define READ_LOCATION_LAST            31
+-
+-/* Version Mask */
+-#define       NAND_VERSION_MAJOR_MASK         0xf0000000
+-#define       NAND_VERSION_MAJOR_SHIFT        28
+-#define       NAND_VERSION_MINOR_MASK         0x0fff0000
+-#define       NAND_VERSION_MINOR_SHIFT        16
+-
+-/* NAND OP_CMDs */
+-#define       OP_PAGE_READ                    0x2
+-#define       OP_PAGE_READ_WITH_ECC           0x3
+-#define       OP_PAGE_READ_WITH_ECC_SPARE     0x4
+-#define       OP_PAGE_READ_ONFI_READ          0x5
+-#define       OP_PROGRAM_PAGE                 0x6
+-#define       OP_PAGE_PROGRAM_WITH_ECC        0x7
+-#define       OP_PROGRAM_PAGE_SPARE           0x9
+-#define       OP_BLOCK_ERASE                  0xa
+-#define       OP_CHECK_STATUS                 0xc
+-#define       OP_FETCH_ID                     0xb
+-#define       OP_RESET_DEVICE                 0xd
+-
+-/* Default Value for NAND_DEV_CMD_VLD */
+-#define NAND_DEV_CMD_VLD_VAL          (READ_START_VLD | WRITE_START_VLD | \
+-                                       ERASE_START_VLD | SEQ_READ_START_VLD)
+-
+-/* NAND_CTRL bits */
+-#define       BAM_MODE_EN                     BIT(0)
+-
+-/*
+- * the NAND controller performs reads/writes with ECC in 516 byte chunks.
+- * the driver calls the chunks 'step' or 'codeword' interchangeably
+- */
+-#define       NANDC_STEP_SIZE                 512
+-
+-/*
+- * the largest page size we support is 8K, this will have 16 steps/codewords
+- * of 512 bytes each
+- */
+-#define       MAX_NUM_STEPS                   (SZ_8K / NANDC_STEP_SIZE)
+-
+-/* we read at most 3 registers per codeword scan */
+-#define       MAX_REG_RD                      (3 * MAX_NUM_STEPS)
+-
+-/* ECC modes supported by the controller */
+-#define       ECC_NONE        BIT(0)
+-#define       ECC_RS_4BIT     BIT(1)
+-#define       ECC_BCH_4BIT    BIT(2)
+-#define       ECC_BCH_8BIT    BIT(3)
+-
+-/*
+- * Returns the actual register address for all NAND_DEV_ registers
+- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
+- */
+-#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
+-
+-/* Returns the NAND register physical address */
+-#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
+-
+-/* Returns the dma address for reg read buffer */
+-#define reg_buf_dma_addr(chip, vaddr) \
+-      ((chip)->reg_read_dma + \
+-      ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
+-
+-#define QPIC_PER_CW_CMD_ELEMENTS      32
+-#define QPIC_PER_CW_CMD_SGL           32
+-#define QPIC_PER_CW_DATA_SGL          8
+-
+-#define QPIC_NAND_COMPLETION_TIMEOUT  msecs_to_jiffies(2000)
+-
+-/*
+- * Flags used in DMA descriptor preparation helper functions
+- * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
+- */
+-/* Don't set the EOT in current tx BAM sgl */
+-#define NAND_BAM_NO_EOT                       BIT(0)
+-/* Set the NWD flag in current BAM sgl */
+-#define NAND_BAM_NWD                  BIT(1)
+-/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
+-#define NAND_BAM_NEXT_SGL             BIT(2)
+-/*
+- * Erased codeword status is being used two times in single transfer so this
+- * flag will determine the current value of erased codeword status register
+- */
+-#define NAND_ERASED_CW_SET            BIT(4)
+-
+-#define MAX_ADDRESS_CYCLE             5
+-
+-/*
+- * This data type corresponds to the BAM transaction which will be used for all
+- * NAND transfers.
+- * @bam_ce - the array of BAM command elements
+- * @cmd_sgl - sgl for NAND BAM command pipe
+- * @data_sgl - sgl for NAND BAM consumer/producer pipe
+- * @last_data_desc - last DMA desc in data channel (tx/rx).
+- * @last_cmd_desc - last DMA desc in command channel.
+- * @txn_done - completion for NAND transfer.
+- * @bam_ce_pos - the index in bam_ce which is available for next sgl
+- * @bam_ce_start - the index in bam_ce which marks the start position ce
+- *               for current sgl. It will be used for size calculation
+- *               for current sgl
+- * @cmd_sgl_pos - current index in command sgl.
+- * @cmd_sgl_start - start index in command sgl.
+- * @tx_sgl_pos - current index in data sgl for tx.
+- * @tx_sgl_start - start index in data sgl for tx.
+- * @rx_sgl_pos - current index in data sgl for rx.
+- * @rx_sgl_start - start index in data sgl for rx.
+- */
+-struct bam_transaction {
+-      struct bam_cmd_element *bam_ce;
+-      struct scatterlist *cmd_sgl;
+-      struct scatterlist *data_sgl;
+-      struct dma_async_tx_descriptor *last_data_desc;
+-      struct dma_async_tx_descriptor *last_cmd_desc;
+-      struct completion txn_done;
+-      u32 bam_ce_pos;
+-      u32 bam_ce_start;
+-      u32 cmd_sgl_pos;
+-      u32 cmd_sgl_start;
+-      u32 tx_sgl_pos;
+-      u32 tx_sgl_start;
+-      u32 rx_sgl_pos;
+-      u32 rx_sgl_start;
+-};
+-
+-/*
+- * This data type corresponds to the nand dma descriptor
+- * @dma_desc - low level DMA engine descriptor
+- * @list - list for desc_info
+- *
+- * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
+- *          ADM
+- * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
+- * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
+- * @dir - DMA transfer direction
+- */
+-struct desc_info {
+-      struct dma_async_tx_descriptor *dma_desc;
+-      struct list_head node;
+-
+-      union {
+-              struct scatterlist adm_sgl;
+-              struct {
+-                      struct scatterlist *bam_sgl;
+-                      int sgl_cnt;
+-              };
+-      };
+-      enum dma_data_direction dir;
+-};
+-
+-/*
+- * holds the current register values that we want to write. acts as a contiguous
+- * chunk of memory which we use to write the controller registers through DMA.
+- */
+-struct nandc_regs {
+-      __le32 cmd;
+-      __le32 addr0;
+-      __le32 addr1;
+-      __le32 chip_sel;
+-      __le32 exec;
+-
+-      __le32 cfg0;
+-      __le32 cfg1;
+-      __le32 ecc_bch_cfg;
+-
+-      __le32 clrflashstatus;
+-      __le32 clrreadstatus;
+-
+-      __le32 cmd1;
+-      __le32 vld;
+-
+-      __le32 orig_cmd1;
+-      __le32 orig_vld;
+-
+-      __le32 ecc_buf_cfg;
+-      __le32 read_location0;
+-      __le32 read_location1;
+-      __le32 read_location2;
+-      __le32 read_location3;
+-      __le32 read_location_last0;
+-      __le32 read_location_last1;
+-      __le32 read_location_last2;
+-      __le32 read_location_last3;
+-
+-      __le32 erased_cw_detect_cfg_clr;
+-      __le32 erased_cw_detect_cfg_set;
+-};
+-
+-/*
+- * NAND controller data struct
+- *
+- * @dev:                      parent device
+- *
+- * @base:                     MMIO base
+- *
+- * @core_clk:                 controller clock
+- * @aon_clk:                  another controller clock
+- *
+- * @regs:                     a contiguous chunk of memory for DMA register
+- *                            writes. contains the register values to be
+- *                            written to controller
+- *
+- * @props:                    properties of current NAND controller,
+- *                            initialized via DT match data
+- *
+- * @controller:                       base controller structure
+- * @host_list:                        list containing all the chips attached to the
+- *                            controller
+- *
+- * @chan:                     dma channel
+- * @cmd_crci:                 ADM DMA CRCI for command flow control
+- * @data_crci:                        ADM DMA CRCI for data flow control
+- *
+- * @desc_list:                        DMA descriptor list (list of desc_infos)
+- *
+- * @data_buffer:              our local DMA buffer for page read/writes,
+- *                            used when we can't use the buffer provided
+- *                            by upper layers directly
+- * @reg_read_buf:             local buffer for reading back registers via DMA
+- *
+- * @base_phys:                        physical base address of controller registers
+- * @base_dma:                 dma base address of controller registers
+- * @reg_read_dma:             contains dma address for register read buffer
+- *
+- * @buf_size/count/start:     markers for chip->legacy.read_buf/write_buf
+- *                            functions
+- * @max_cwperpage:            maximum QPIC codewords required. calculated
+- *                            from all connected NAND devices pagesize
+- *
+- * @reg_read_pos:             marker for data read in reg_read_buf
+- *
+- * @cmd1/vld:                 some fixed controller register values
+- *
+- * @exec_opwrite:             flag to select correct number of code word
+- *                            while reading status
+- */
+-struct qcom_nand_controller {
+-      struct device *dev;
+-
+-      void __iomem *base;
+-
+-      struct clk *core_clk;
+-      struct clk *aon_clk;
+-
+-      struct nandc_regs *regs;
+-      struct bam_transaction *bam_txn;
+-
+-      const struct qcom_nandc_props *props;
+-
+-      struct nand_controller controller;
+-      struct list_head host_list;
+-
+-      union {
+-              /* will be used only by QPIC for BAM DMA */
+-              struct {
+-                      struct dma_chan *tx_chan;
+-                      struct dma_chan *rx_chan;
+-                      struct dma_chan *cmd_chan;
+-              };
+-
+-              /* will be used only by EBI2 for ADM DMA */
+-              struct {
+-                      struct dma_chan *chan;
+-                      unsigned int cmd_crci;
+-                      unsigned int data_crci;
+-              };
+-      };
+-
+-      struct list_head desc_list;
+-
+-      u8              *data_buffer;
+-      __le32          *reg_read_buf;
+-
+-      phys_addr_t base_phys;
+-      dma_addr_t base_dma;
+-      dma_addr_t reg_read_dma;
+-
+-      int             buf_size;
+-      int             buf_count;
+-      int             buf_start;
+-      unsigned int    max_cwperpage;
+-
+-      int reg_read_pos;
+-
+-      u32 cmd1, vld;
+-      bool exec_opwrite;
+-};
++#include <linux/mtd/nand-qpic-common.h>
+ /*
+  * NAND special boot partitions
+@@ -530,97 +120,6 @@ struct qcom_nand_host {
+       bool bch_enabled;
+ };
+-/*
+- * This data type corresponds to the NAND controller properties which varies
+- * among different NAND controllers.
+- * @ecc_modes - ecc mode for NAND
+- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
+- * @supports_bam - whether NAND controller is using Bus Access Manager (BAM)
+- * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
+- * @qpic_version2 - flag to indicate QPIC IP version 2
+- * @use_codeword_fixup - whether NAND has different layout for boot partitions
+- */
+-struct qcom_nandc_props {
+-      u32 ecc_modes;
+-      u32 dev_cmd_reg_start;
+-      bool supports_bam;
+-      bool nandc_part_of_qpic;
+-      bool qpic_version2;
+-      bool use_codeword_fixup;
+-};
+-
+-/* Frees the BAM transaction memory */
+-static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
+-{
+-      struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+-      devm_kfree(nandc->dev, bam_txn);
+-}
+-
+-/* Allocates and Initializes the BAM transaction */
+-static struct bam_transaction *
+-qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
+-{
+-      struct bam_transaction *bam_txn;
+-      size_t bam_txn_size;
+-      unsigned int num_cw = nandc->max_cwperpage;
+-      void *bam_txn_buf;
+-
+-      bam_txn_size =
+-              sizeof(*bam_txn) + num_cw *
+-              ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
+-              (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
+-              (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
+-
+-      bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
+-      if (!bam_txn_buf)
+-              return NULL;
+-
+-      bam_txn = bam_txn_buf;
+-      bam_txn_buf += sizeof(*bam_txn);
+-
+-      bam_txn->bam_ce = bam_txn_buf;
+-      bam_txn_buf +=
+-              sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
+-
+-      bam_txn->cmd_sgl = bam_txn_buf;
+-      bam_txn_buf +=
+-              sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
+-
+-      bam_txn->data_sgl = bam_txn_buf;
+-
+-      init_completion(&bam_txn->txn_done);
+-
+-      return bam_txn;
+-}
+-
+-/* Clears the BAM transaction indexes */
+-static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
+-{
+-      struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+-      if (!nandc->props->supports_bam)
+-              return;
+-
+-      memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
+-      bam_txn->last_data_desc = NULL;
+-
+-      sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
+-                    QPIC_PER_CW_CMD_SGL);
+-      sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
+-                    QPIC_PER_CW_DATA_SGL);
+-
+-      reinit_completion(&bam_txn->txn_done);
+-}
+-
+-/* Callback for DMA descriptor completion */
+-static void qcom_qpic_bam_dma_done(void *data)
+-{
+-      struct bam_transaction *bam_txn = data;
+-
+-      complete(&bam_txn->txn_done);
+-}
+-
+ static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
+ {
+       return container_of(chip, struct qcom_nand_host, chip);
+@@ -629,8 +128,8 @@ static struct qcom_nand_host *to_qcom_na
+ static struct qcom_nand_controller *
+ get_qcom_nand_controller(struct nand_chip *chip)
+ {
+-      return container_of(chip->controller, struct qcom_nand_controller,
+-                          controller);
++      return (struct qcom_nand_controller *)
++              ((u8 *)chip->controller - sizeof(struct qcom_nand_controller));
+ }
+ static u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
+@@ -644,23 +143,6 @@ static void nandc_write(struct qcom_nand
+       iowrite32(val, nandc->base + offset);
+ }
+-static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
+-{
+-      if (!nandc->props->supports_bam)
+-              return;
+-
+-      if (is_cpu)
+-              dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
+-                                      MAX_REG_RD *
+-                                      sizeof(*nandc->reg_read_buf),
+-                                      DMA_FROM_DEVICE);
+-      else
+-              dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
+-                                         MAX_REG_RD *
+-                                         sizeof(*nandc->reg_read_buf),
+-                                         DMA_FROM_DEVICE);
+-}
+-
+ /* Helper to check whether this is the last CW or not */
+ static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
+ {
+@@ -820,356 +302,6 @@ static void update_rw_regs(struct qcom_n
+ }
+ /*
+- * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
+- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
+- * which will be submitted to DMA engine.
+- */
+-static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
+-                                     struct dma_chan *chan,
+-                                     unsigned long flags)
+-{
+-      struct desc_info *desc;
+-      struct scatterlist *sgl;
+-      unsigned int sgl_cnt;
+-      int ret;
+-      struct bam_transaction *bam_txn = nandc->bam_txn;
+-      enum dma_transfer_direction dir_eng;
+-      struct dma_async_tx_descriptor *dma_desc;
+-
+-      desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+-      if (!desc)
+-              return -ENOMEM;
+-
+-      if (chan == nandc->cmd_chan) {
+-              sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
+-              sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
+-              bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
+-              dir_eng = DMA_MEM_TO_DEV;
+-              desc->dir = DMA_TO_DEVICE;
+-      } else if (chan == nandc->tx_chan) {
+-              sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
+-              sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
+-              bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
+-              dir_eng = DMA_MEM_TO_DEV;
+-              desc->dir = DMA_TO_DEVICE;
+-      } else {
+-              sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
+-              sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
+-              bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
+-              dir_eng = DMA_DEV_TO_MEM;
+-              desc->dir = DMA_FROM_DEVICE;
+-      }
+-
+-      sg_mark_end(sgl + sgl_cnt - 1);
+-      ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+-      if (ret == 0) {
+-              dev_err(nandc->dev, "failure in mapping desc\n");
+-              kfree(desc);
+-              return -ENOMEM;
+-      }
+-
+-      desc->sgl_cnt = sgl_cnt;
+-      desc->bam_sgl = sgl;
+-
+-      dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
+-                                         flags);
+-
+-      if (!dma_desc) {
+-              dev_err(nandc->dev, "failure in prep desc\n");
+-              dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+-              kfree(desc);
+-              return -EINVAL;
+-      }
+-
+-      desc->dma_desc = dma_desc;
+-
+-      /* update last data/command descriptor */
+-      if (chan == nandc->cmd_chan)
+-              bam_txn->last_cmd_desc = dma_desc;
+-      else
+-              bam_txn->last_data_desc = dma_desc;
+-
+-      list_add_tail(&desc->node, &nandc->desc_list);
+-
+-      return 0;
+-}
+-
+-/*
+- * Prepares the command descriptor for BAM DMA which will be used for NAND
+- * register reads and writes. The command descriptor requires the command
+- * to be formed in command element type so this function uses the command
+- * element from bam transaction ce array and fills the same with required
+- * data. A single SGL can contain multiple command elements so
+- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
+- * after the current command element.
+- */
+-static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
+-                                    int reg_off, const void *vaddr,
+-                                    int size, unsigned int flags)
+-{
+-      int bam_ce_size;
+-      int i, ret;
+-      struct bam_cmd_element *bam_ce_buffer;
+-      struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+-      bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
+-
+-      /* fill the command desc */
+-      for (i = 0; i < size; i++) {
+-              if (read)
+-                      bam_prep_ce(&bam_ce_buffer[i],
+-                                  nandc_reg_phys(nandc, reg_off + 4 * i),
+-                                  BAM_READ_COMMAND,
+-                                  reg_buf_dma_addr(nandc,
+-                                                   (__le32 *)vaddr + i));
+-              else
+-                      bam_prep_ce_le32(&bam_ce_buffer[i],
+-                                       nandc_reg_phys(nandc, reg_off + 4 * i),
+-                                       BAM_WRITE_COMMAND,
+-                                       *((__le32 *)vaddr + i));
+-      }
+-
+-      bam_txn->bam_ce_pos += size;
+-
+-      /* use the separate sgl after this command */
+-      if (flags & NAND_BAM_NEXT_SGL) {
+-              bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
+-              bam_ce_size = (bam_txn->bam_ce_pos -
+-                              bam_txn->bam_ce_start) *
+-                              sizeof(struct bam_cmd_element);
+-              sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
+-                         bam_ce_buffer, bam_ce_size);
+-              bam_txn->cmd_sgl_pos++;
+-              bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
+-
+-              if (flags & NAND_BAM_NWD) {
+-                      ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
+-                                                        DMA_PREP_FENCE |
+-                                                        DMA_PREP_CMD);
+-                      if (ret)
+-                              return ret;
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-/*
+- * Prepares the data descriptor for BAM DMA which will be used for NAND
+- * data reads and writes.
+- */
+-static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
+-                                     const void *vaddr, int size, unsigned int flags)
+-{
+-      int ret;
+-      struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+-      if (read) {
+-              sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
+-                         vaddr, size);
+-              bam_txn->rx_sgl_pos++;
+-      } else {
+-              sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
+-                         vaddr, size);
+-              bam_txn->tx_sgl_pos++;
+-
+-              /*
+-               * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
+-               * is not set, form the DMA descriptor
+-               */
+-              if (!(flags & NAND_BAM_NO_EOT)) {
+-                      ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
+-                                                        DMA_PREP_INTERRUPT);
+-                      if (ret)
+-                              return ret;
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
+-                                int reg_off, const void *vaddr, int size,
+-                                bool flow_control)
+-{
+-      struct desc_info *desc;
+-      struct dma_async_tx_descriptor *dma_desc;
+-      struct scatterlist *sgl;
+-      struct dma_slave_config slave_conf;
+-      struct qcom_adm_peripheral_config periph_conf = {};
+-      enum dma_transfer_direction dir_eng;
+-      int ret;
+-
+-      desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+-      if (!desc)
+-              return -ENOMEM;
+-
+-      sgl = &desc->adm_sgl;
+-
+-      sg_init_one(sgl, vaddr, size);
+-
+-      if (read) {
+-              dir_eng = DMA_DEV_TO_MEM;
+-              desc->dir = DMA_FROM_DEVICE;
+-      } else {
+-              dir_eng = DMA_MEM_TO_DEV;
+-              desc->dir = DMA_TO_DEVICE;
+-      }
+-
+-      ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
+-      if (ret == 0) {
+-              ret = -ENOMEM;
+-              goto err;
+-      }
+-
+-      memset(&slave_conf, 0x00, sizeof(slave_conf));
+-
+-      slave_conf.device_fc = flow_control;
+-      if (read) {
+-              slave_conf.src_maxburst = 16;
+-              slave_conf.src_addr = nandc->base_dma + reg_off;
+-              if (nandc->data_crci) {
+-                      periph_conf.crci = nandc->data_crci;
+-                      slave_conf.peripheral_config = &periph_conf;
+-                      slave_conf.peripheral_size = sizeof(periph_conf);
+-              }
+-      } else {
+-              slave_conf.dst_maxburst = 16;
+-              slave_conf.dst_addr = nandc->base_dma + reg_off;
+-              if (nandc->cmd_crci) {
+-                      periph_conf.crci = nandc->cmd_crci;
+-                      slave_conf.peripheral_config = &periph_conf;
+-                      slave_conf.peripheral_size = sizeof(periph_conf);
+-              }
+-      }
+-
+-      ret = dmaengine_slave_config(nandc->chan, &slave_conf);
+-      if (ret) {
+-              dev_err(nandc->dev, "failed to configure dma channel\n");
+-              goto err;
+-      }
+-
+-      dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
+-      if (!dma_desc) {
+-              dev_err(nandc->dev, "failed to prepare desc\n");
+-              ret = -EINVAL;
+-              goto err;
+-      }
+-
+-      desc->dma_desc = dma_desc;
+-
+-      list_add_tail(&desc->node, &nandc->desc_list);
+-
+-      return 0;
+-err:
+-      kfree(desc);
+-
+-      return ret;
+-}
+-
+-/*
+- * qcom_read_reg_dma: prepares a descriptor to read a given number of
+- *                    contiguous registers to the reg_read_buf pointer
+- *
+- * @first:            offset of the first register in the contiguous block
+- * @num_regs:         number of registers to read
+- * @flags:            flags to control DMA descriptor preparation
+- */
+-static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
+-                           int num_regs, unsigned int flags)
+-{
+-      bool flow_control = false;
+-      void *vaddr;
+-
+-      vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
+-      nandc->reg_read_pos += num_regs;
+-
+-      if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
+-              first = dev_cmd_reg_addr(nandc, first);
+-
+-      if (nandc->props->supports_bam)
+-              return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
+-                                           num_regs, flags);
+-
+-      if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
+-              flow_control = true;
+-
+-      return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
+-                               num_regs * sizeof(u32), flow_control);
+-}
+-
+-/*
+- * qcom_write_reg_dma:        prepares a descriptor to write a given number of
+- *                    contiguous registers
+- *
+- * @vaddr:            contiguous memory from where register value will
+- *                    be written
+- * @first:            offset of the first register in the contiguous block
+- * @num_regs:         number of registers to write
+- * @flags:            flags to control DMA descriptor preparation
+- */
+-static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
+-                            int first, int num_regs, unsigned int flags)
+-{
+-      bool flow_control = false;
+-
+-      if (first == NAND_EXEC_CMD)
+-              flags |= NAND_BAM_NWD;
+-
+-      if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
+-              first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
+-
+-      if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
+-              first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
+-
+-      if (nandc->props->supports_bam)
+-              return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
+-                                           num_regs, flags);
+-
+-      if (first == NAND_FLASH_CMD)
+-              flow_control = true;
+-
+-      return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
+-                               num_regs * sizeof(u32), flow_control);
+-}
+-
+-/*
+- * qcom_read_data_dma:        prepares a DMA descriptor to transfer data from the
+- *                    controller's internal buffer to the buffer 'vaddr'
+- *
+- * @reg_off:          offset within the controller's data buffer
+- * @vaddr:            virtual address of the buffer we want to write to
+- * @size:             DMA transaction size in bytes
+- * @flags:            flags to control DMA descriptor preparation
+- */
+-static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+-                            const u8 *vaddr, int size, unsigned int flags)
+-{
+-      if (nandc->props->supports_bam)
+-              return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
+-
+-      return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
+-}
+-
+-/*
+- * qcom_write_data_dma:       prepares a DMA descriptor to transfer data from
+- *                    'vaddr' to the controller's internal buffer
+- *
+- * @reg_off:          offset within the controller's data buffer
+- * @vaddr:            virtual address of the buffer we want to read from
+- * @size:             DMA transaction size in bytes
+- * @flags:            flags to control DMA descriptor preparation
+- */
+-static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+-                             const u8 *vaddr, int size, unsigned int flags)
+-{
+-      if (nandc->props->supports_bam)
+-              return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
+-
+-      return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
+-}
+-
+-/*
+  * Helper to prepare DMA descriptors for configuring registers
+  * before reading a NAND page.
+  */
+@@ -1262,83 +394,6 @@ static void config_nand_cw_write(struct
+                          NAND_BAM_NEXT_SGL);
+ }
+-/* helpers to submit/free our list of dma descriptors */
+-static int qcom_submit_descs(struct qcom_nand_controller *nandc)
+-{
+-      struct desc_info *desc, *n;
+-      dma_cookie_t cookie = 0;
+-      struct bam_transaction *bam_txn = nandc->bam_txn;
+-      int ret = 0;
+-
+-      if (nandc->props->supports_bam) {
+-              if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
+-                      ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
+-                      if (ret)
+-                              goto err_unmap_free_desc;
+-              }
+-
+-              if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
+-                      ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
+-                                                        DMA_PREP_INTERRUPT);
+-                      if (ret)
+-                              goto err_unmap_free_desc;
+-              }
+-
+-              if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
+-                      ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
+-                                                        DMA_PREP_CMD);
+-                      if (ret)
+-                              goto err_unmap_free_desc;
+-              }
+-      }
+-
+-      list_for_each_entry(desc, &nandc->desc_list, node)
+-              cookie = dmaengine_submit(desc->dma_desc);
+-
+-      if (nandc->props->supports_bam) {
+-              bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
+-              bam_txn->last_cmd_desc->callback_param = bam_txn;
+-
+-              dma_async_issue_pending(nandc->tx_chan);
+-              dma_async_issue_pending(nandc->rx_chan);
+-              dma_async_issue_pending(nandc->cmd_chan);
+-
+-              if (!wait_for_completion_timeout(&bam_txn->txn_done,
+-                                               QPIC_NAND_COMPLETION_TIMEOUT))
+-                      ret = -ETIMEDOUT;
+-      } else {
+-              if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
+-                      ret = -ETIMEDOUT;
+-      }
+-
+-err_unmap_free_desc:
+-      /*
+-       * Unmap the dma sg_list and free the desc allocated by both
+-       * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
+-       */
+-      list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
+-              list_del(&desc->node);
+-
+-              if (nandc->props->supports_bam)
+-                      dma_unmap_sg(nandc->dev, desc->bam_sgl,
+-                                   desc->sgl_cnt, desc->dir);
+-              else
+-                      dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
+-                                   desc->dir);
+-
+-              kfree(desc);
+-      }
+-
+-      return ret;
+-}
+-
+-/* reset the register read buffer for next NAND operation */
+-static void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
+-{
+-      nandc->reg_read_pos = 0;
+-      qcom_nandc_dev_to_mem(nandc, false);
+-}
+-
+ /*
+  * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+  * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+@@ -2967,141 +2022,14 @@ static const struct nand_controller_ops
+       .exec_op = qcom_nand_exec_op,
+ };
+-static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
+-{
+-      if (nandc->props->supports_bam) {
+-              if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
+-                      dma_unmap_single(nandc->dev, nandc->reg_read_dma,
+-                                       MAX_REG_RD *
+-                                       sizeof(*nandc->reg_read_buf),
+-                                       DMA_FROM_DEVICE);
+-
+-              if (nandc->tx_chan)
+-                      dma_release_channel(nandc->tx_chan);
+-
+-              if (nandc->rx_chan)
+-                      dma_release_channel(nandc->rx_chan);
+-
+-              if (nandc->cmd_chan)
+-                      dma_release_channel(nandc->cmd_chan);
+-      } else {
+-              if (nandc->chan)
+-                      dma_release_channel(nandc->chan);
+-      }
+-}
+-
+-static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
+-{
+-      int ret;
+-
+-      ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
+-      if (ret) {
+-              dev_err(nandc->dev, "failed to set DMA mask\n");
+-              return ret;
+-      }
+-
+-      /*
+-       * we use the internal buffer for reading ONFI params, reading small
+-       * data like ID and status, and preforming read-copy-write operations
+-       * when writing to a codeword partially. 532 is the maximum possible
+-       * size of a codeword for our nand controller
+-       */
+-      nandc->buf_size = 532;
+-
+-      nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
+-      if (!nandc->data_buffer)
+-              return -ENOMEM;
+-
+-      nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
+-      if (!nandc->regs)
+-              return -ENOMEM;
+-
+-      nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
+-                                         sizeof(*nandc->reg_read_buf),
+-                                         GFP_KERNEL);
+-      if (!nandc->reg_read_buf)
+-              return -ENOMEM;
+-
+-      if (nandc->props->supports_bam) {
+-              nandc->reg_read_dma =
+-                      dma_map_single(nandc->dev, nandc->reg_read_buf,
+-                                     MAX_REG_RD *
+-                                     sizeof(*nandc->reg_read_buf),
+-                                     DMA_FROM_DEVICE);
+-              if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
+-                      dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
+-                      return -EIO;
+-              }
+-
+-              nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
+-              if (IS_ERR(nandc->tx_chan)) {
+-                      ret = PTR_ERR(nandc->tx_chan);
+-                      nandc->tx_chan = NULL;
+-                      dev_err_probe(nandc->dev, ret,
+-                                    "tx DMA channel request failed\n");
+-                      goto unalloc;
+-              }
+-
+-              nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
+-              if (IS_ERR(nandc->rx_chan)) {
+-                      ret = PTR_ERR(nandc->rx_chan);
+-                      nandc->rx_chan = NULL;
+-                      dev_err_probe(nandc->dev, ret,
+-                                    "rx DMA channel request failed\n");
+-                      goto unalloc;
+-              }
+-
+-              nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
+-              if (IS_ERR(nandc->cmd_chan)) {
+-                      ret = PTR_ERR(nandc->cmd_chan);
+-                      nandc->cmd_chan = NULL;
+-                      dev_err_probe(nandc->dev, ret,
+-                                    "cmd DMA channel request failed\n");
+-                      goto unalloc;
+-              }
+-
+-              /*
+-               * Initially allocate BAM transaction to read ONFI param page.
+-               * After detecting all the devices, this BAM transaction will
+-               * be freed and the next BAM transaction will be allocated with
+-               * maximum codeword size
+-               */
+-              nandc->max_cwperpage = 1;
+-              nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
+-              if (!nandc->bam_txn) {
+-                      dev_err(nandc->dev,
+-                              "failed to allocate bam transaction\n");
+-                      ret = -ENOMEM;
+-                      goto unalloc;
+-              }
+-      } else {
+-              nandc->chan = dma_request_chan(nandc->dev, "rxtx");
+-              if (IS_ERR(nandc->chan)) {
+-                      ret = PTR_ERR(nandc->chan);
+-                      nandc->chan = NULL;
+-                      dev_err_probe(nandc->dev, ret,
+-                                    "rxtx DMA channel request failed\n");
+-                      return ret;
+-              }
+-      }
+-
+-      INIT_LIST_HEAD(&nandc->desc_list);
+-      INIT_LIST_HEAD(&nandc->host_list);
+-
+-      nand_controller_init(&nandc->controller);
+-      nandc->controller.ops = &qcom_nandc_ops;
+-
+-      return 0;
+-unalloc:
+-      qcom_nandc_unalloc(nandc);
+-      return ret;
+-}
+-
+ /* one time setup of a few nand controller registers */
+ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
+ {
+       u32 nand_ctrl;
++      nand_controller_init(nandc->controller);
++      nandc->controller->ops = &qcom_nandc_ops;
++
+       /* kill onenand */
+       if (!nandc->props->nandc_part_of_qpic)
+               nandc_write(nandc, SFLASHC_BURST_CFG, 0);
+@@ -3240,7 +2168,7 @@ static int qcom_nand_host_init_and_regis
+       chip->legacy.block_bad          = qcom_nandc_block_bad;
+       chip->legacy.block_markbad      = qcom_nandc_block_markbad;
+-      chip->controller = &nandc->controller;
++      chip->controller = nandc->controller;
+       chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA |
+                        NAND_SKIP_BBTSCAN;
+@@ -3323,17 +2251,21 @@ static int qcom_nandc_parse_dt(struct pl
+ static int qcom_nandc_probe(struct platform_device *pdev)
+ {
+       struct qcom_nand_controller *nandc;
++      struct nand_controller *controller;
+       const void *dev_data;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       int ret;
+-      nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
++      nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc) + sizeof(*controller),
++                           GFP_KERNEL);
+       if (!nandc)
+               return -ENOMEM;
++      controller = (struct nand_controller *)&nandc[1];
+       platform_set_drvdata(pdev, nandc);
+       nandc->dev = dev;
++      nandc->controller = controller;
+       dev_data = of_device_get_match_data(dev);
+       if (!dev_data) {
+--- /dev/null
++++ b/include/linux/mtd/nand-qpic-common.h
+@@ -0,0 +1,468 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * QCOM QPIC common APIs header file
++ *
++ * Copyright (c) 2023 Qualcomm Inc.
++ * Authors:   Md sadre Alam   <[email protected]>
++ *
++ */
++#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 (file)
index 0000000..b375074
--- /dev/null
@@ -0,0 +1,198 @@
+From 0c08080fd71cd5dd59643104b39d3c89d793ab3c Mon Sep 17 00:00:00 2001
+From: Md Sadre Alam <[email protected]>
+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 <[email protected]>
+Signed-off-by: Md Sadre Alam <[email protected]>
+Signed-off-by: Miquel Raynal <[email protected]>
+---
+ 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 (file)
index 0000000..a6a4db2
--- /dev/null
@@ -0,0 +1,64 @@
+From 9d4ffbcfde283f2a87ea45128ddf7e6651facdd9 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <[email protected]>
+Date: Fri, 7 Feb 2025 20:42:38 +0100
+Subject: [PATCH] mtd: rawnand: qcom: fix broken config in
+ qcom_param_page_type_exec
+
+Fix broken config in qcom_param_page_type_exec caused by copy-paste error
+from commit 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
+
+In qcom_param_page_type_exec the value needs to be set to
+nandc->regs->cfg0 instead of host->cfg0. This wrong configuration caused
+the Qcom NANDC driver to malfunction on any device that makes use of it
+(IPQ806x, IPQ40xx, IPQ807x, IPQ60xx) with the following error:
+
+[    0.885369] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xaa
+[    0.885909] nand: Micron NAND 256MiB 1,8V 8-bit
+[    0.892499] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
+[    0.896823] nand: ECC (step, strength) = (512, 8) does not fit in OOB
+[    0.896836] qcom-nandc 79b0000.nand-controller: No valid ECC settings possible
+[    0.910996] bam-dma-engine 7984000.dma-controller: Cannot free busy channel
+[    0.918070] qcom-nandc: probe of 79b0000.nand-controller failed with error -28
+
+Restore original configuration fix the problem and makes the driver work
+again.
+
+Fixes: 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
+Signed-off-by: Christian Marangi <[email protected]>
+---
+ 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 (file)
index 0000000..67beed3
--- /dev/null
@@ -0,0 +1,77 @@
+From b9371866799d67a80be0ea9e01bd41987db22f26 Mon Sep 17 00:00:00 2001
+From: Md Sadre Alam <[email protected]>
+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 <[email protected]>
+Signed-off-by: Miquel Raynal <[email protected]>
+---
+ 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 (file)
index 0000000..310d902
--- /dev/null
@@ -0,0 +1,1737 @@
+From 7304d1909080ef0c9da703500a97f46c98393fcd Mon Sep 17 00:00:00 2001
+From: Md Sadre Alam <[email protected]>
+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 <[email protected]>
+Signed-off-by: Sricharan Ramabadhran <[email protected]>
+Co-developed-by: Varadarajan Narayanan <[email protected]>
+Signed-off-by: Varadarajan Narayanan <[email protected]>
+Signed-off-by: Md Sadre Alam <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Mark Brown <[email protected]>
+---
+ 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 <[email protected]>
++ *    Sricharan R <[email protected]>
++ *    Varadarajan Narayanan <[email protected]>
++ */
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/dma/qcom_adm.h>
++#include <linux/dma/qcom_bam_dma.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/nand-qpic-common.h>
++#include <linux/mtd/spinand.h>
++#include <linux/bitfield.h>
++
++#define NAND_FLASH_SPI_CFG            0xc0
++#define NAND_NUM_ADDR_CYCLES          0xc4
++#define NAND_BUSY_CHECK_WAIT_CNT      0xc8
++#define NAND_FLASH_FEATURES           0xf64
++
++/* QSPI NAND config reg bits */
++#define LOAD_CLK_CNTR_INIT_EN         BIT(28)
++#define CLK_CNTR_INIT_VAL_VEC         0x924
++#define CLK_CNTR_INIT_VAL_VEC_MASK    GENMASK(27, 16)
++#define FEA_STATUS_DEV_ADDR           0xc0
++#define FEA_STATUS_DEV_ADDR_MASK      GENMASK(15, 8)
++#define SPI_CFG                               BIT(0)
++#define SPI_NUM_ADDR                  0xDA4DB
++#define SPI_WAIT_CNT                  0x10
++#define QPIC_QSPI_NUM_CS              1
++#define SPI_TRANSFER_MODE_x1          BIT(29)
++#define SPI_TRANSFER_MODE_x4          (3 << 29)
++#define SPI_WP                                BIT(28)
++#define SPI_HOLD                      BIT(27)
++#define QPIC_SET_FEATURE              BIT(31)
++
++#define SPINAND_RESET                 0xff
++#define SPINAND_READID                        0x9f
++#define SPINAND_GET_FEATURE           0x0f
++#define SPINAND_SET_FEATURE           0x1f
++#define SPINAND_READ                  0x13
++#define SPINAND_ERASE                 0xd8
++#define SPINAND_WRITE_EN              0x06
++#define SPINAND_PROGRAM_EXECUTE               0x10
++#define SPINAND_PROGRAM_LOAD          0x84
++
++#define ACC_FEATURE                   0xe
++#define BAD_BLOCK_MARKER_SIZE         0x2
++#define OOB_BUF_SIZE                  128
++#define ecceng_to_qspi(eng)           container_of(eng, struct qpic_spi_nand, ecc_eng)
++
++struct qpic_snand_op {
++      u32 cmd_reg;
++      u32 addr1_reg;
++      u32 addr2_reg;
++};
++
++struct snandc_read_status {
++      __le32 snandc_flash;
++      __le32 snandc_buffer;
++      __le32 snandc_erased_cw;
++};
++
++/*
++ * ECC state struct
++ * @corrected:                ECC corrected
++ * @bitflips:         Max bit flip
++ * @failed:           ECC failed
++ */
++struct qcom_ecc_stats {
++      u32 corrected;
++      u32 bitflips;
++      u32 failed;
++};
++
++struct qpic_ecc {
++      struct device *dev;
++      int ecc_bytes_hw;
++      int spare_bytes;
++      int bbm_size;
++      int ecc_mode;
++      int bytes;
++      int steps;
++      int step_size;
++      int strength;
++      int cw_size;
++      int cw_data;
++      u32 cfg0;
++      u32 cfg1;
++      u32 cfg0_raw;
++      u32 cfg1_raw;
++      u32 ecc_buf_cfg;
++      u32 ecc_bch_cfg;
++      u32 clrflashstatus;
++      u32 clrreadstatus;
++      bool bch_enabled;
++};
++
++struct qpic_spi_nand {
++      struct qcom_nand_controller *snandc;
++      struct spi_controller *ctlr;
++      struct mtd_info *mtd;
++      struct clk *iomacro_clk;
++      struct qpic_ecc *ecc;
++      struct qcom_ecc_stats ecc_stats;
++      struct nand_ecc_engine ecc_eng;
++      u8 *data_buf;
++      u8 *oob_buf;
++      u32 wlen;
++      __le32 addr1;
++      __le32 addr2;
++      __le32 cmd;
++      u32 num_cw;
++      bool oob_rw;
++      bool page_rw;
++      bool raw_rw;
++};
++
++static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc,
++                                      int reg, int cw_offset, int read_size,
++                                      int is_last_read_loc)
++{
++      __le32 locreg_val;
++      u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
++                ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
++                << READ_LOCATION_LAST));
++
++      locreg_val = cpu_to_le32(val);
++
++      if (reg == NAND_READ_LOCATION_0)
++              snandc->regs->read_location0 = locreg_val;
++      else if (reg == NAND_READ_LOCATION_1)
++              snandc->regs->read_location1 = locreg_val;
++      else if (reg == NAND_READ_LOCATION_2)
++              snandc->regs->read_location1 = locreg_val;
++      else if (reg == NAND_READ_LOCATION_3)
++              snandc->regs->read_location3 = locreg_val;
++}
++
++static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc,
++                                     int reg, int cw_offset, int read_size,
++                                     int is_last_read_loc)
++{
++      __le32 locreg_val;
++      u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
++                ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
++                << READ_LOCATION_LAST));
++
++      locreg_val = cpu_to_le32(val);
++
++      if (reg == NAND_READ_LOCATION_LAST_CW_0)
++              snandc->regs->read_location_last0 = locreg_val;
++      else if (reg == NAND_READ_LOCATION_LAST_CW_1)
++              snandc->regs->read_location_last1 = locreg_val;
++      else if (reg == NAND_READ_LOCATION_LAST_CW_2)
++              snandc->regs->read_location_last2 = locreg_val;
++      else if (reg == NAND_READ_LOCATION_LAST_CW_3)
++              snandc->regs->read_location_last3 = locreg_val;
++}
++
++static struct qcom_nand_controller *nand_to_qcom_snand(struct nand_device *nand)
++{
++      struct nand_ecc_engine *eng = nand->ecc.engine;
++      struct qpic_spi_nand *qspi = ecceng_to_qspi(eng);
++
++      return qspi->snandc;
++}
++
++static int qcom_spi_init(struct qcom_nand_controller *snandc)
++{
++      u32 snand_cfg_val = 0x0;
++      int ret;
++
++      snand_cfg_val = FIELD_PREP(CLK_CNTR_INIT_VAL_VEC_MASK, CLK_CNTR_INIT_VAL_VEC) |
++                      FIELD_PREP(LOAD_CLK_CNTR_INIT_EN, 0) |
++                      FIELD_PREP(FEA_STATUS_DEV_ADDR_MASK, FEA_STATUS_DEV_ADDR) |
++                      FIELD_PREP(SPI_CFG, 0);
++
++      snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
++      snandc->regs->num_addr_cycle = cpu_to_le32(SPI_NUM_ADDR);
++      snandc->regs->busy_wait_cnt = cpu_to_le32(SPI_WAIT_CNT);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
++
++      snand_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN;
++      snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->num_addr_cycle, NAND_NUM_ADDR_CYCLES, 1, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->busy_wait_cnt, NAND_BUSY_CHECK_WAIT_CNT, 1,
++                         NAND_BAM_NEXT_SGL);
++
++      ret = qcom_submit_descs(snandc);
++      if (ret) {
++              dev_err(snandc->dev, "failure in submitting spi init descriptor\n");
++              return ret;
++      }
++
++      return ret;
++}
++
++static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                struct mtd_oob_region *oobregion)
++{
++      struct nand_device *nand = mtd_to_nanddev(mtd);
++      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++      struct qpic_ecc *qecc = snandc->qspi->ecc;
++
++      if (section > 1)
++              return -ERANGE;
++
++      oobregion->length = qecc->ecc_bytes_hw + qecc->spare_bytes;
++      oobregion->offset = mtd->oobsize - oobregion->length;
++
++      return 0;
++}
++
++static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section,
++                                 struct mtd_oob_region *oobregion)
++{
++      struct nand_device *nand = mtd_to_nanddev(mtd);
++      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++      struct qpic_ecc *qecc = snandc->qspi->ecc;
++
++      if (section)
++              return -ERANGE;
++
++      oobregion->length = qecc->steps * 4;
++      oobregion->offset = ((qecc->steps - 1) * qecc->bytes) + qecc->bbm_size;
++
++      return 0;
++}
++
++static const struct mtd_ooblayout_ops qcom_spi_ooblayout = {
++      .ecc = qcom_spi_ooblayout_ecc,
++      .free = qcom_spi_ooblayout_free,
++};
++
++static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
++{
++      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++      struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
++      struct mtd_info *mtd = nanddev_to_mtd(nand);
++      int cwperpage, bad_block_byte;
++      struct qpic_ecc *ecc_cfg;
++
++      cwperpage = mtd->writesize / NANDC_STEP_SIZE;
++      snandc->qspi->num_cw = cwperpage;
++
++      ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
++      if (!ecc_cfg)
++              return -ENOMEM;
++      snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
++                                      GFP_KERNEL);
++      if (!snandc->qspi->oob_buf)
++              return -ENOMEM;
++
++      memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
++
++      nand->ecc.ctx.priv = ecc_cfg;
++      snandc->qspi->mtd = mtd;
++
++      ecc_cfg->ecc_bytes_hw = 7;
++      ecc_cfg->spare_bytes = 4;
++      ecc_cfg->bbm_size = 1;
++      ecc_cfg->bch_enabled = true;
++      ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
++
++      ecc_cfg->steps = 4;
++      ecc_cfg->strength = 4;
++      ecc_cfg->step_size = 512;
++      ecc_cfg->cw_data = 516;
++      ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
++      bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;
++
++      mtd_set_ooblayout(mtd, &qcom_spi_ooblayout);
++
++      ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
++                      FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) |
++                      FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) |
++                      FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
++                      FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, ecc_cfg->ecc_bytes_hw) |
++                      FIELD_PREP(STATUS_BFR_READ, 0) |
++                      FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) |
++                      FIELD_PREP(SPARE_SIZE_BYTES_MASK, ecc_cfg->spare_bytes);
++
++      ecc_cfg->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
++                      FIELD_PREP(CS_ACTIVE_BSY, 0) |
++                      FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) |
++                      FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) |
++                      FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
++                      FIELD_PREP(WIDE_FLASH, 0) |
++                      FIELD_PREP(ENABLE_BCH_ECC, ecc_cfg->bch_enabled);
++
++      ecc_cfg->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
++                          FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
++                          FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_size) |
++                          FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
++
++      ecc_cfg->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
++                          FIELD_PREP(CS_ACTIVE_BSY, 0) |
++                          FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
++                          FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
++                          FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
++                          FIELD_PREP(WIDE_FLASH, 0) |
++                          FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
++
++      ecc_cfg->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !ecc_cfg->bch_enabled) |
++                             FIELD_PREP(ECC_SW_RESET, 0) |
++                             FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
++                             FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
++                             FIELD_PREP(ECC_MODE_MASK, 0) |
++                             FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
++
++      ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
++      ecc_cfg->clrflashstatus = FS_READY_BSY_N;
++      ecc_cfg->clrreadstatus = 0xc0;
++
++      conf->step_size = ecc_cfg->step_size;
++      conf->strength = ecc_cfg->strength;
++
++      snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET);
++      snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET);
++
++      dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n",
++              ecc_cfg->strength, ecc_cfg->step_size);
++
++      return 0;
++}
++
++static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand)
++{
++      struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
++
++      kfree(ecc_cfg);
++}
++
++static int qcom_spi_ecc_prepare_io_req_pipelined(struct nand_device *nand,
++                                               struct nand_page_io_req *req)
++{
++      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++      struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
++
++      snandc->qspi->ecc = ecc_cfg;
++      snandc->qspi->raw_rw = false;
++      snandc->qspi->oob_rw = false;
++      snandc->qspi->page_rw = false;
++
++      if (req->datalen)
++              snandc->qspi->page_rw = true;
++
++      if (req->ooblen)
++              snandc->qspi->oob_rw = true;
++
++      if (req->mode == MTD_OPS_RAW)
++              snandc->qspi->raw_rw = true;
++
++      return 0;
++}
++
++static int qcom_spi_ecc_finish_io_req_pipelined(struct nand_device *nand,
++                                              struct nand_page_io_req *req)
++{
++      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++      struct mtd_info *mtd = nanddev_to_mtd(nand);
++
++      if (req->mode == MTD_OPS_RAW || req->type != NAND_PAGE_READ)
++              return 0;
++
++      if (snandc->qspi->ecc_stats.failed)
++              mtd->ecc_stats.failed += snandc->qspi->ecc_stats.failed;
++      else
++              mtd->ecc_stats.corrected += snandc->qspi->ecc_stats.corrected;
++
++      if (snandc->qspi->ecc_stats.failed)
++              return -EBADMSG;
++      else
++              return snandc->qspi->ecc_stats.bitflips;
++}
++
++static struct nand_ecc_engine_ops qcom_spi_ecc_engine_ops_pipelined = {
++      .init_ctx = qcom_spi_ecc_init_ctx_pipelined,
++      .cleanup_ctx = qcom_spi_ecc_cleanup_ctx_pipelined,
++      .prepare_io_req = qcom_spi_ecc_prepare_io_req_pipelined,
++      .finish_io_req = qcom_spi_ecc_finish_io_req_pipelined,
++};
++
++/* helper to configure location register values */
++static void qcom_spi_set_read_loc(struct qcom_nand_controller *snandc, int cw, int reg,
++                                int cw_offset, int read_size, int is_last_read_loc)
++{
++      int reg_base = NAND_READ_LOCATION_0;
++      int num_cw = snandc->qspi->num_cw;
++
++      if (cw == (num_cw - 1))
++              reg_base = NAND_READ_LOCATION_LAST_CW_0;
++
++      reg_base += reg * 4;
++
++      if (cw == (num_cw - 1))
++              return qcom_spi_set_read_loc_last(snandc, reg_base, cw_offset,
++                                                read_size, is_last_read_loc);
++      else
++              return qcom_spi_set_read_loc_first(snandc, reg_base, cw_offset,
++                                                 read_size, is_last_read_loc);
++}
++
++static void
++qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int cw)
++{
++      __le32 *reg = &snandc->regs->read_location0;
++      int num_cw = snandc->qspi->num_cw;
++
++      qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
++      if (cw == (num_cw - 1)) {
++              reg = &snandc->regs->read_location_last0;
++              qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4,
++                                 NAND_BAM_NEXT_SGL);
++      }
++
++      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++      qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0);
++      qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1,
++                        NAND_BAM_NEXT_SGL);
++}
++
++static int qcom_spi_block_erase(struct qcom_nand_controller *snandc)
++{
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      int ret;
++
++      snandc->buf_count = 0;
++      snandc->buf_start = 0;
++      qcom_clear_read_regs(snandc);
++      qcom_clear_bam_transaction(snandc);
++
++      snandc->regs->cmd = snandc->qspi->cmd;
++      snandc->regs->addr0 = snandc->qspi->addr1;
++      snandc->regs->addr1 = snandc->qspi->addr2;
++      snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE));
++      snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw);
++      snandc->regs->exec = cpu_to_le32(1);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
++      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
++      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++      ret = qcom_submit_descs(snandc);
++      if (ret) {
++              dev_err(snandc->dev, "failure to erase block\n");
++              return ret;
++      }
++
++      return 0;
++}
++
++static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *snandc,
++                                              bool use_ecc, int cw)
++{
++      __le32 *reg = &snandc->regs->read_location0;
++      int num_cw = snandc->qspi->num_cw;
++
++      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
++                         NAND_ERASED_CW_DETECT_CFG, 1, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
++                         NAND_ERASED_CW_DETECT_CFG, 1,
++                         NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++
++      if (cw == (num_cw - 1)) {
++              reg = &snandc->regs->read_location_last0;
++              qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, NAND_BAM_NEXT_SGL);
++      }
++      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++      qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0);
++}
++
++static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc,
++                               const struct spi_mem_op *op)
++{
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      struct mtd_info *mtd = snandc->qspi->mtd;
++      int size, ret = 0;
++      int col,  bbpos;
++      u32 cfg0, cfg1, ecc_bch_cfg;
++      u32 num_cw = snandc->qspi->num_cw;
++
++      qcom_clear_bam_transaction(snandc);
++      qcom_clear_read_regs(snandc);
++
++      size = ecc_cfg->cw_size;
++      col = ecc_cfg->cw_size * (num_cw - 1);
++
++      memset(snandc->data_buffer, 0xff, size);
++      snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
++      snandc->regs->addr1 = snandc->qspi->addr2;
++
++      cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
++              0 << CW_PER_PAGE;
++      cfg1 = ecc_cfg->cfg1_raw;
++      ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
++
++      snandc->regs->cmd = snandc->qspi->cmd;
++      snandc->regs->cfg0 = cpu_to_le32(cfg0);
++      snandc->regs->cfg1 = cpu_to_le32(cfg1);
++      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++      snandc->regs->exec = cpu_to_le32(1);
++
++      qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1);
++
++      qcom_spi_config_single_cw_page_read(snandc, false, num_cw - 1);
++
++      qcom_read_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, size, 0);
++
++      ret = qcom_submit_descs(snandc);
++      if (ret) {
++              dev_err(snandc->dev, "failed to read last cw\n");
++              return ret;
++      }
++
++      qcom_nandc_dev_to_mem(snandc, true);
++      u32 flash = le32_to_cpu(snandc->reg_read_buf[0]);
++
++      if (flash & (FS_OP_ERR | FS_MPU_ERR))
++              return -EIO;
++
++      bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
++
++      if (snandc->data_buffer[bbpos] == 0xff)
++              snandc->data_buffer[bbpos + 1] = 0xff;
++      if (snandc->data_buffer[bbpos] != 0xff)
++              snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos];
++
++      memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes);
++
++      return ret;
++}
++
++static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf)
++{
++      struct snandc_read_status *buf;
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      int i, num_cw = snandc->qspi->num_cw;
++      bool flash_op_err = false, erased;
++      unsigned int max_bitflips = 0;
++      unsigned int uncorrectable_cws = 0;
++
++      snandc->qspi->ecc_stats.failed = 0;
++      snandc->qspi->ecc_stats.corrected = 0;
++
++      qcom_nandc_dev_to_mem(snandc, true);
++      buf = (struct snandc_read_status *)snandc->reg_read_buf;
++
++      for (i = 0; i < num_cw; i++, buf++) {
++              u32 flash, buffer, erased_cw;
++              int data_len, oob_len;
++
++              if (i == (num_cw - 1)) {
++                      data_len = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
++                      oob_len = num_cw << 2;
++              } else {
++                      data_len = ecc_cfg->cw_data;
++                      oob_len = 0;
++              }
++
++              flash = le32_to_cpu(buf->snandc_flash);
++              buffer = le32_to_cpu(buf->snandc_buffer);
++              erased_cw = le32_to_cpu(buf->snandc_erased_cw);
++
++              if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
++                      if (ecc_cfg->bch_enabled)
++                              erased = (erased_cw & ERASED_CW) == ERASED_CW;
++                      else
++                              erased = false;
++
++                      if (!erased)
++                              uncorrectable_cws |= BIT(i);
++
++              } else if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
++                      flash_op_err = true;
++              } else {
++                      unsigned int stat;
++
++                      stat = buffer & BS_CORRECTABLE_ERR_MSK;
++                      snandc->qspi->ecc_stats.corrected += stat;
++                      max_bitflips = max(max_bitflips, stat);
++              }
++
++              if (data_buf)
++                      data_buf += data_len;
++              if (oob_buf)
++                      oob_buf += oob_len + ecc_cfg->bytes;
++      }
++
++      if (flash_op_err)
++              return -EIO;
++
++      if (!uncorrectable_cws)
++              snandc->qspi->ecc_stats.bitflips = max_bitflips;
++      else
++              snandc->qspi->ecc_stats.failed++;
++
++      return 0;
++}
++
++static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt)
++{
++      int i;
++
++      qcom_nandc_dev_to_mem(snandc, true);
++
++      for (i = 0; i < cw_cnt; i++) {
++              u32 flash = le32_to_cpu(snandc->reg_read_buf[i]);
++
++              if (flash & (FS_OP_ERR | FS_MPU_ERR))
++                      return -EIO;
++      }
++
++      return 0;
++}
++
++static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf,
++                              u8 *oob_buf, int cw)
++{
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      struct mtd_info *mtd = snandc->qspi->mtd;
++      int data_size1, data_size2, oob_size1, oob_size2;
++      int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
++      int raw_cw = cw;
++      u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
++      int col;
++
++      snandc->buf_count = 0;
++      snandc->buf_start = 0;
++      qcom_clear_read_regs(snandc);
++      qcom_clear_bam_transaction(snandc);
++      raw_cw = num_cw - 1;
++
++      cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
++                              0 << CW_PER_PAGE;
++      cfg1 = ecc_cfg->cfg1_raw;
++      ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
++
++      col = ecc_cfg->cw_size * cw;
++
++      snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
++      snandc->regs->addr1 = snandc->qspi->addr2;
++      snandc->regs->cmd = snandc->qspi->cmd;
++      snandc->regs->cfg0 = cpu_to_le32(cfg0);
++      snandc->regs->cfg1 = cpu_to_le32(cfg1);
++      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++      snandc->regs->exec = cpu_to_le32(1);
++
++      qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
++                         NAND_ERASED_CW_DETECT_CFG, 1, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
++                         NAND_ERASED_CW_DETECT_CFG, 1,
++                         NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++
++      data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
++      oob_size1 = ecc_cfg->bbm_size;
++
++      if (cw == (num_cw - 1)) {
++              data_size2 = NANDC_STEP_SIZE - data_size1 -
++                           ((num_cw - 1) * 4);
++              oob_size2 = (num_cw * 4) + ecc_cfg->ecc_bytes_hw +
++                          ecc_cfg->spare_bytes;
++      } else {
++              data_size2 = ecc_cfg->cw_data - data_size1;
++              oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
++      }
++
++      qcom_spi_set_read_loc(snandc, cw, 0, read_loc, data_size1, 0);
++      read_loc += data_size1;
++
++      qcom_spi_set_read_loc(snandc, cw, 1, read_loc, oob_size1, 0);
++      read_loc += oob_size1;
++
++      qcom_spi_set_read_loc(snandc, cw, 2, read_loc, data_size2, 0);
++      read_loc += data_size2;
++
++      qcom_spi_set_read_loc(snandc, cw, 3, read_loc, oob_size2, 1);
++
++      qcom_spi_config_cw_read(snandc, false, raw_cw);
++
++      qcom_read_data_dma(snandc, reg_off, data_buf, data_size1, 0);
++      reg_off += data_size1;
++
++      qcom_read_data_dma(snandc, reg_off, oob_buf, oob_size1, 0);
++      reg_off += oob_size1;
++
++      qcom_read_data_dma(snandc, reg_off, data_buf + data_size1, data_size2, 0);
++      reg_off += data_size2;
++
++      qcom_read_data_dma(snandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
++
++      ret = qcom_submit_descs(snandc);
++      if (ret) {
++              dev_err(snandc->dev, "failure to read raw cw %d\n", cw);
++              return ret;
++      }
++
++      return qcom_spi_check_raw_flash_errors(snandc, 1);
++}
++
++static int qcom_spi_read_page_raw(struct qcom_nand_controller *snandc,
++                                const struct spi_mem_op *op)
++{
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      u8 *data_buf = NULL, *oob_buf = NULL;
++      int ret, cw;
++      u32 num_cw = snandc->qspi->num_cw;
++
++      if (snandc->qspi->page_rw)
++              data_buf = op->data.buf.in;
++
++      oob_buf = snandc->qspi->oob_buf;
++      memset(oob_buf, 0xff, OOB_BUF_SIZE);
++
++      for (cw = 0; cw < num_cw; cw++) {
++              ret = qcom_spi_read_cw_raw(snandc, data_buf, oob_buf, cw);
++              if (ret)
++                      return ret;
++
++              if (data_buf)
++                      data_buf += ecc_cfg->cw_data;
++              if (oob_buf)
++                      oob_buf += ecc_cfg->bytes;
++      }
++
++      return 0;
++}
++
++static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc,
++                                const struct spi_mem_op *op)
++{
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
++      int ret, i;
++      u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
++
++      data_buf = op->data.buf.in;
++      data_buf_start = data_buf;
++
++      oob_buf = snandc->qspi->oob_buf;
++      oob_buf_start = oob_buf;
++
++      snandc->buf_count = 0;
++      snandc->buf_start = 0;
++      qcom_clear_read_regs(snandc);
++
++      cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
++                              (num_cw - 1) << CW_PER_PAGE;
++      cfg1 = ecc_cfg->cfg1;
++      ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
++
++      snandc->regs->addr0 = snandc->qspi->addr1;
++      snandc->regs->addr1 = snandc->qspi->addr2;
++      snandc->regs->cmd = snandc->qspi->cmd;
++      snandc->regs->cfg0 = cpu_to_le32(cfg0);
++      snandc->regs->cfg1 = cpu_to_le32(cfg1);
++      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++      snandc->regs->exec = cpu_to_le32(1);
++
++      qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
++
++      qcom_clear_bam_transaction(snandc);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
++                         NAND_ERASED_CW_DETECT_CFG, 1, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
++                         NAND_ERASED_CW_DETECT_CFG, 1,
++                         NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++
++      for (i = 0; i < num_cw; i++) {
++              int data_size, oob_size;
++
++              if (i == (num_cw - 1)) {
++                      data_size = 512 - ((num_cw - 1) << 2);
++                      oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
++                                  ecc_cfg->spare_bytes;
++              } else {
++                      data_size = ecc_cfg->cw_data;
++                      oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
++              }
++
++              if (data_buf && oob_buf) {
++                      qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 0);
++                      qcom_spi_set_read_loc(snandc, i, 1, data_size, oob_size, 1);
++              } else if (data_buf) {
++                      qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 1);
++              } else {
++                      qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
++              }
++
++              qcom_spi_config_cw_read(snandc, true, i);
++
++              if (data_buf)
++                      qcom_read_data_dma(snandc, FLASH_BUF_ACC, data_buf,
++                                         data_size, 0);
++              if (oob_buf) {
++                      int j;
++
++                      for (j = 0; j < ecc_cfg->bbm_size; j++)
++                              *oob_buf++ = 0xff;
++
++                      qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
++                                         oob_buf, oob_size, 0);
++              }
++
++              if (data_buf)
++                      data_buf += data_size;
++              if (oob_buf)
++                      oob_buf += oob_size;
++      }
++
++      ret = qcom_submit_descs(snandc);
++      if (ret) {
++              dev_err(snandc->dev, "failure to read page\n");
++              return ret;
++      }
++
++      return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
++}
++
++static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc,
++                                const struct spi_mem_op *op)
++{
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
++      int ret, i;
++      u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
++
++      oob_buf = op->data.buf.in;
++      oob_buf_start = oob_buf;
++
++      data_buf_start = data_buf;
++
++      snandc->buf_count = 0;
++      snandc->buf_start = 0;
++      qcom_clear_read_regs(snandc);
++      qcom_clear_bam_transaction(snandc);
++
++      cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
++                              (num_cw - 1) << CW_PER_PAGE;
++      cfg1 = ecc_cfg->cfg1;
++      ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
++
++      snandc->regs->addr0 = snandc->qspi->addr1;
++      snandc->regs->addr1 = snandc->qspi->addr2;
++      snandc->regs->cmd = snandc->qspi->cmd;
++      snandc->regs->cfg0 = cpu_to_le32(cfg0);
++      snandc->regs->cfg1 = cpu_to_le32(cfg1);
++      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++      snandc->regs->exec = cpu_to_le32(1);
++
++      qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
++                         NAND_ERASED_CW_DETECT_CFG, 1, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
++                         NAND_ERASED_CW_DETECT_CFG, 1,
++                         NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++
++      for (i = 0; i < num_cw; i++) {
++              int data_size, oob_size;
++
++              if (i == (num_cw - 1)) {
++                      data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
++                      oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
++                                  ecc_cfg->spare_bytes;
++              } else {
++                      data_size = ecc_cfg->cw_data;
++                      oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
++              }
++
++              qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
++
++              qcom_spi_config_cw_read(snandc, true, i);
++
++              if (oob_buf) {
++                      int j;
++
++                      for (j = 0; j < ecc_cfg->bbm_size; j++)
++                              *oob_buf++ = 0xff;
++
++                      qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
++                                         oob_buf, oob_size, 0);
++              }
++
++              if (oob_buf)
++                      oob_buf += oob_size;
++      }
++
++      ret = qcom_submit_descs(snandc);
++      if (ret) {
++              dev_err(snandc->dev, "failure to read oob\n");
++              return ret;
++      }
++
++      return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
++}
++
++static int qcom_spi_read_page(struct qcom_nand_controller *snandc,
++                            const struct spi_mem_op *op)
++{
++      if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
++              return qcom_spi_read_page_raw(snandc, op);
++
++      if (snandc->qspi->page_rw)
++              return qcom_spi_read_page_ecc(snandc, op);
++
++      if (snandc->qspi->oob_rw && snandc->qspi->raw_rw)
++              return qcom_spi_read_last_cw(snandc, op);
++
++      if (snandc->qspi->oob_rw)
++              return qcom_spi_read_page_oob(snandc, op);
++
++      return 0;
++}
++
++static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc)
++{
++      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG,
++                         1, NAND_BAM_NEXT_SGL);
++}
++
++static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc)
++{
++      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++      qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
++      qcom_write_reg_dma(snandc, &snandc->regs->clrreadstatus, NAND_READ_STATUS, 1,
++                         NAND_BAM_NEXT_SGL);
++}
++
++static int qcom_spi_program_raw(struct qcom_nand_controller *snandc,
++                              const struct spi_mem_op *op)
++{
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      struct mtd_info *mtd = snandc->qspi->mtd;
++      u8 *data_buf = NULL, *oob_buf = NULL;
++      int i, ret;
++      int num_cw = snandc->qspi->num_cw;
++      u32 cfg0, cfg1, ecc_bch_cfg;
++
++      cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
++                      (num_cw - 1) << CW_PER_PAGE;
++      cfg1 = ecc_cfg->cfg1_raw;
++      ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
++
++      data_buf = snandc->qspi->data_buf;
++
++      oob_buf = snandc->qspi->oob_buf;
++      memset(oob_buf, 0xff, OOB_BUF_SIZE);
++
++      snandc->buf_count = 0;
++      snandc->buf_start = 0;
++      qcom_clear_read_regs(snandc);
++      qcom_clear_bam_transaction(snandc);
++
++      snandc->regs->addr0 = snandc->qspi->addr1;
++      snandc->regs->addr1 = snandc->qspi->addr2;
++      snandc->regs->cmd = snandc->qspi->cmd;
++      snandc->regs->cfg0 = cpu_to_le32(cfg0);
++      snandc->regs->cfg1 = cpu_to_le32(cfg1);
++      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
++      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
++      snandc->regs->exec = cpu_to_le32(1);
++
++      qcom_spi_config_page_write(snandc);
++
++      for (i = 0; i < num_cw; i++) {
++              int data_size1, data_size2, oob_size1, oob_size2;
++              int reg_off = FLASH_BUF_ACC;
++
++              data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
++              oob_size1 = ecc_cfg->bbm_size;
++
++              if (i == (num_cw - 1)) {
++                      data_size2 = NANDC_STEP_SIZE - data_size1 -
++                                   ((num_cw - 1) << 2);
++                      oob_size2 = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
++                                  ecc_cfg->spare_bytes;
++              } else {
++                      data_size2 = ecc_cfg->cw_data - data_size1;
++                      oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
++              }
++
++              qcom_write_data_dma(snandc, reg_off, data_buf, data_size1,
++                                  NAND_BAM_NO_EOT);
++              reg_off += data_size1;
++              data_buf += data_size1;
++
++              qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size1,
++                                  NAND_BAM_NO_EOT);
++              oob_buf += oob_size1;
++              reg_off += oob_size1;
++
++              qcom_write_data_dma(snandc, reg_off, data_buf, data_size2,
++                                  NAND_BAM_NO_EOT);
++              reg_off += data_size2;
++              data_buf += data_size2;
++
++              qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size2, 0);
++              oob_buf += oob_size2;
++
++              qcom_spi_config_cw_write(snandc);
++      }
++
++      ret = qcom_submit_descs(snandc);
++      if (ret) {
++              dev_err(snandc->dev, "failure to write raw page\n");
++              return ret;
++      }
++
++      return 0;
++}
++
++static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc,
++                              const struct spi_mem_op *op)
++{
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      u8 *data_buf = NULL, *oob_buf = NULL;
++      int i, ret;
++      int num_cw = snandc->qspi->num_cw;
++      u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
++
++      cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
++                              (num_cw - 1) << CW_PER_PAGE;
++      cfg1 = ecc_cfg->cfg1;
++      ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
++      ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
++
++      if (snandc->qspi->data_buf)
++              data_buf = snandc->qspi->data_buf;
++
++      oob_buf = snandc->qspi->oob_buf;
++
++      snandc->buf_count = 0;
++      snandc->buf_start = 0;
++      qcom_clear_read_regs(snandc);
++      qcom_clear_bam_transaction(snandc);
++
++      snandc->regs->addr0 = snandc->qspi->addr1;
++      snandc->regs->addr1 = snandc->qspi->addr2;
++      snandc->regs->cmd = snandc->qspi->cmd;
++      snandc->regs->cfg0 = cpu_to_le32(cfg0);
++      snandc->regs->cfg1 = cpu_to_le32(cfg1);
++      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++      snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
++      snandc->regs->exec = cpu_to_le32(1);
++
++      qcom_spi_config_page_write(snandc);
++
++      for (i = 0; i < num_cw; i++) {
++              int data_size, oob_size;
++
++              if (i == (num_cw - 1)) {
++                      data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
++                      oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
++                                  ecc_cfg->spare_bytes;
++              } else {
++                      data_size = ecc_cfg->cw_data;
++                      oob_size = ecc_cfg->bytes;
++              }
++
++              if (data_buf)
++                      qcom_write_data_dma(snandc, FLASH_BUF_ACC, data_buf, data_size,
++                                          i == (num_cw - 1) ? NAND_BAM_NO_EOT : 0);
++
++              if (i == (num_cw - 1)) {
++                      if (oob_buf) {
++                              oob_buf += ecc_cfg->bbm_size;
++                              qcom_write_data_dma(snandc, FLASH_BUF_ACC + data_size,
++                                                  oob_buf, oob_size, 0);
++                      }
++              }
++
++              qcom_spi_config_cw_write(snandc);
++
++              if (data_buf)
++                      data_buf += data_size;
++              if (oob_buf)
++                      oob_buf += oob_size;
++      }
++
++      ret = qcom_submit_descs(snandc);
++      if (ret) {
++              dev_err(snandc->dev, "failure to write page\n");
++              return ret;
++      }
++
++      return 0;
++}
++
++static int qcom_spi_program_oob(struct qcom_nand_controller *snandc,
++                              const struct spi_mem_op *op)
++{
++      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
++      u8 *oob_buf = NULL;
++      int ret, col, data_size, oob_size;
++      int num_cw = snandc->qspi->num_cw;
++      u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
++
++      cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
++                              (num_cw - 1) << CW_PER_PAGE;
++      cfg1 = ecc_cfg->cfg1;
++      ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
++      ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
++
++      col = ecc_cfg->cw_size * (num_cw - 1);
++
++      oob_buf = snandc->qspi->data_buf;
++
++      snandc->buf_count = 0;
++      snandc->buf_start = 0;
++      qcom_clear_read_regs(snandc);
++      qcom_clear_bam_transaction(snandc);
++      snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
++      snandc->regs->addr1 = snandc->qspi->addr2;
++      snandc->regs->cmd = snandc->qspi->cmd;
++      snandc->regs->cfg0 = cpu_to_le32(cfg0);
++      snandc->regs->cfg1 = cpu_to_le32(cfg1);
++      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
++      snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
++      snandc->regs->exec = cpu_to_le32(1);
++
++      /* calculate the data and oob size for the last codeword/step */
++      data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
++      oob_size = snandc->qspi->mtd->oobavail;
++
++      memset(snandc->data_buffer, 0xff, ecc_cfg->cw_data);
++      /* override new oob content to last codeword */
++      mtd_ooblayout_get_databytes(snandc->qspi->mtd, snandc->data_buffer + data_size,
++                                  oob_buf, 0, snandc->qspi->mtd->oobavail);
++      qcom_spi_config_page_write(snandc);
++      qcom_write_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, data_size + oob_size, 0);
++      qcom_spi_config_cw_write(snandc);
++
++      ret = qcom_submit_descs(snandc);
++      if (ret) {
++              dev_err(snandc->dev, "failure to write oob\n");
++              return ret;
++      }
++
++      return 0;
++}
++
++static int qcom_spi_program_execute(struct qcom_nand_controller *snandc,
++                                  const struct spi_mem_op *op)
++{
++      if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
++              return qcom_spi_program_raw(snandc, op);
++
++      if (snandc->qspi->page_rw)
++              return qcom_spi_program_ecc(snandc, op);
++
++      if (snandc->qspi->oob_rw)
++              return qcom_spi_program_oob(snandc, op);
++
++      return 0;
++}
++
++static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd)
++{
++      switch (opcode) {
++      case SPINAND_RESET:
++              *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE);
++              break;
++      case SPINAND_READID:
++              *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID);
++              break;
++      case SPINAND_GET_FEATURE:
++              *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE);
++              break;
++      case SPINAND_SET_FEATURE:
++              *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE |
++                      QPIC_SET_FEATURE);
++              break;
++      case SPINAND_READ:
++              if (snandc->qspi->raw_rw) {
++                      *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
++                                      SPI_WP | SPI_HOLD | OP_PAGE_READ);
++              } else {
++                      *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
++                                      SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC);
++              }
++
++              break;
++      case SPINAND_ERASE:
++              *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP |
++                      SPI_HOLD | SPI_TRANSFER_MODE_x1;
++              break;
++      case SPINAND_WRITE_EN:
++              *cmd = SPINAND_WRITE_EN;
++              break;
++      case SPINAND_PROGRAM_EXECUTE:
++              *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
++                              SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
++              break;
++      case SPINAND_PROGRAM_LOAD:
++              *cmd = SPINAND_PROGRAM_LOAD;
++              break;
++      default:
++              dev_err(snandc->dev, "Opcode not supported: %u\n", opcode);
++              return -EOPNOTSUPP;
++      }
++
++      return 0;
++}
++
++static int qcom_spi_write_page(struct qcom_nand_controller *snandc,
++                             const struct spi_mem_op *op)
++{
++      int ret;
++      u32 cmd;
++
++      ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
++      if (ret < 0)
++              return ret;
++
++      if (op->cmd.opcode == SPINAND_PROGRAM_LOAD)
++              snandc->qspi->data_buf = (u8 *)op->data.buf.out;
++
++      return 0;
++}
++
++static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
++                               const struct spi_mem_op *op)
++{
++      struct qpic_snand_op s_op = {};
++      u32 cmd;
++      int ret, opcode;
++
++      ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
++      if (ret < 0)
++              return ret;
++
++      s_op.cmd_reg = cmd;
++      s_op.addr1_reg = op->addr.val;
++      s_op.addr2_reg = 0;
++
++      opcode = op->cmd.opcode;
++
++      switch (opcode) {
++      case SPINAND_WRITE_EN:
++              return 0;
++      case SPINAND_PROGRAM_EXECUTE:
++              s_op.addr1_reg = op->addr.val << 16;
++              s_op.addr2_reg = op->addr.val >> 16 & 0xff;
++              snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
++              snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
++              snandc->qspi->cmd = cpu_to_le32(cmd);
++              return qcom_spi_program_execute(snandc, op);
++      case SPINAND_READ:
++              s_op.addr1_reg = (op->addr.val << 16);
++              s_op.addr2_reg = op->addr.val >> 16 & 0xff;
++              snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
++              snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
++              snandc->qspi->cmd = cpu_to_le32(cmd);
++              return 0;
++      case SPINAND_ERASE:
++              s_op.addr2_reg = (op->addr.val >> 16) & 0xffff;
++              s_op.addr1_reg = op->addr.val;
++              snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16);
++              snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
++              snandc->qspi->cmd = cpu_to_le32(cmd);
++              qcom_spi_block_erase(snandc);
++              return 0;
++      default:
++              break;
++      }
++
++      snandc->buf_count = 0;
++      snandc->buf_start = 0;
++      qcom_clear_read_regs(snandc);
++      qcom_clear_bam_transaction(snandc);
++
++      snandc->regs->cmd = cpu_to_le32(s_op.cmd_reg);
++      snandc->regs->exec = cpu_to_le32(1);
++      snandc->regs->addr0 = cpu_to_le32(s_op.addr1_reg);
++      snandc->regs->addr1 = cpu_to_le32(s_op.addr2_reg);
++
++      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
++      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++      ret = qcom_submit_descs(snandc);
++      if (ret)
++              dev_err(snandc->dev, "failure in submitting cmd descriptor\n");
++
++      return ret;
++}
++
++static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_mem_op *op)
++{
++      int ret, val, opcode;
++      bool copy = false, copy_ftr = false;
++
++      ret = qcom_spi_send_cmdaddr(snandc, op);
++      if (ret)
++              return ret;
++
++      snandc->buf_count = 0;
++      snandc->buf_start = 0;
++      qcom_clear_read_regs(snandc);
++      qcom_clear_bam_transaction(snandc);
++      opcode = op->cmd.opcode;
++
++      switch (opcode) {
++      case SPINAND_READID:
++              snandc->buf_count = 4;
++              qcom_read_reg_dma(snandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
++              copy = true;
++              break;
++      case SPINAND_GET_FEATURE:
++              snandc->buf_count = 4;
++              qcom_read_reg_dma(snandc, NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
++              copy_ftr = true;
++              break;
++      case SPINAND_SET_FEATURE:
++              snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out);
++              qcom_write_reg_dma(snandc, &snandc->regs->flash_feature,
++                                 NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
++              break;
++      case SPINAND_PROGRAM_EXECUTE:
++      case SPINAND_WRITE_EN:
++      case SPINAND_RESET:
++      case SPINAND_ERASE:
++      case SPINAND_READ:
++              return 0;
++      default:
++              return -EOPNOTSUPP;
++      }
++
++      ret = qcom_submit_descs(snandc);
++      if (ret)
++              dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode);
++
++      if (copy) {
++              qcom_nandc_dev_to_mem(snandc, true);
++              memcpy(op->data.buf.in, snandc->reg_read_buf, snandc->buf_count);
++      }
++
++      if (copy_ftr) {
++              qcom_nandc_dev_to_mem(snandc, true);
++              val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf);
++              val >>= 8;
++              memcpy(op->data.buf.in, &val, snandc->buf_count);
++      }
++
++      return ret;
++}
++
++static bool qcom_spi_is_page_op(const struct spi_mem_op *op)
++{
++      if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && op->addr.buswidth != 4)
++              return false;
++
++      if (op->data.dir == SPI_MEM_DATA_IN) {
++              if (op->addr.buswidth == 4 && op->data.buswidth == 4)
++                      return true;
++
++              if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
++                      return true;
++
++      } else if (op->data.dir == SPI_MEM_DATA_OUT) {
++              if (op->data.buswidth == 4)
++                      return true;
++              if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
++                      return true;
++      }
++
++      return false;
++}
++
++static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
++{
++      if (!spi_mem_default_supports_op(mem, op))
++              return false;
++
++      if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1)
++              return false;
++
++      if (qcom_spi_is_page_op(op))
++              return true;
++
++      return ((!op->addr.nbytes || op->addr.buswidth == 1) &&
++              (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
++              (!op->data.nbytes || op->data.buswidth == 1));
++}
++
++static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
++{
++      struct qcom_nand_controller *snandc = spi_controller_get_devdata(mem->spi->controller);
++
++      dev_dbg(snandc->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode,
++              op->addr.val, op->addr.buswidth, op->addr.nbytes,
++              op->data.buswidth, op->data.nbytes);
++
++      if (qcom_spi_is_page_op(op)) {
++              if (op->data.dir == SPI_MEM_DATA_IN)
++                      return qcom_spi_read_page(snandc, op);
++              if (op->data.dir == SPI_MEM_DATA_OUT)
++                      return qcom_spi_write_page(snandc, op);
++      } else {
++              return qcom_spi_io_op(snandc, op);
++      }
++
++      return 0;
++}
++
++static const struct spi_controller_mem_ops qcom_spi_mem_ops = {
++      .supports_op = qcom_spi_supports_op,
++      .exec_op = qcom_spi_exec_op,
++};
++
++static const struct spi_controller_mem_caps qcom_spi_mem_caps = {
++      .ecc = true,
++};
++
++static int qcom_spi_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct spi_controller *ctlr;
++      struct qcom_nand_controller *snandc;
++      struct qpic_spi_nand *qspi;
++      struct qpic_ecc *ecc;
++      struct resource *res;
++      const void *dev_data;
++      int ret;
++
++      ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
++      if (!ecc)
++              return -ENOMEM;
++
++      qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
++      if (!qspi)
++              return -ENOMEM;
++
++      ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false);
++      if (!ctlr)
++              return -ENOMEM;
++
++      platform_set_drvdata(pdev, ctlr);
++
++      snandc = spi_controller_get_devdata(ctlr);
++      qspi->snandc = snandc;
++
++      snandc->dev = dev;
++      snandc->qspi = qspi;
++      snandc->qspi->ctlr = ctlr;
++      snandc->qspi->ecc = ecc;
++
++      dev_data = of_device_get_match_data(dev);
++      if (!dev_data) {
++              dev_err(&pdev->dev, "failed to get device data\n");
++              return -ENODEV;
++      }
++
++      snandc->props = dev_data;
++      snandc->dev = &pdev->dev;
++
++      snandc->core_clk = devm_clk_get(dev, "core");
++      if (IS_ERR(snandc->core_clk))
++              return PTR_ERR(snandc->core_clk);
++
++      snandc->aon_clk = devm_clk_get(dev, "aon");
++      if (IS_ERR(snandc->aon_clk))
++              return PTR_ERR(snandc->aon_clk);
++
++      snandc->qspi->iomacro_clk = devm_clk_get(dev, "iom");
++      if (IS_ERR(snandc->qspi->iomacro_clk))
++              return PTR_ERR(snandc->qspi->iomacro_clk);
++
++      snandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
++      if (IS_ERR(snandc->base))
++              return PTR_ERR(snandc->base);
++
++      snandc->base_phys = res->start;
++      snandc->base_dma = dma_map_resource(dev, res->start, resource_size(res),
++                                          DMA_BIDIRECTIONAL, 0);
++      if (dma_mapping_error(dev, snandc->base_dma))
++              return -ENXIO;
++
++      ret = clk_prepare_enable(snandc->core_clk);
++      if (ret)
++              goto err_dis_core_clk;
++
++      ret = clk_prepare_enable(snandc->aon_clk);
++      if (ret)
++              goto err_dis_aon_clk;
++
++      ret = clk_prepare_enable(snandc->qspi->iomacro_clk);
++      if (ret)
++              goto err_dis_iom_clk;
++
++      ret = qcom_nandc_alloc(snandc);
++      if (ret)
++              goto err_snand_alloc;
++
++      ret = qcom_spi_init(snandc);
++      if (ret)
++              goto err_spi_init;
++
++      /* setup ECC engine */
++      snandc->qspi->ecc_eng.dev = &pdev->dev;
++      snandc->qspi->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
++      snandc->qspi->ecc_eng.ops = &qcom_spi_ecc_engine_ops_pipelined;
++      snandc->qspi->ecc_eng.priv = snandc;
++
++      ret = nand_ecc_register_on_host_hw_engine(&snandc->qspi->ecc_eng);
++      if (ret) {
++              dev_err(&pdev->dev, "failed to register ecc engine:%d\n", ret);
++              goto err_spi_init;
++      }
++
++      ctlr->num_chipselect = QPIC_QSPI_NUM_CS;
++      ctlr->mem_ops = &qcom_spi_mem_ops;
++      ctlr->mem_caps = &qcom_spi_mem_caps;
++      ctlr->dev.of_node = pdev->dev.of_node;
++      ctlr->mode_bits = SPI_TX_DUAL | SPI_RX_DUAL |
++                          SPI_TX_QUAD | SPI_RX_QUAD;
++
++      ret = spi_register_controller(ctlr);
++      if (ret) {
++              dev_err(&pdev->dev, "spi_register_controller failed.\n");
++              goto err_spi_init;
++      }
++
++      return 0;
++
++err_spi_init:
++      qcom_nandc_unalloc(snandc);
++err_snand_alloc:
++      clk_disable_unprepare(snandc->qspi->iomacro_clk);
++err_dis_iom_clk:
++      clk_disable_unprepare(snandc->aon_clk);
++err_dis_aon_clk:
++      clk_disable_unprepare(snandc->core_clk);
++err_dis_core_clk:
++      dma_unmap_resource(dev, res->start, resource_size(res),
++                         DMA_BIDIRECTIONAL, 0);
++      return ret;
++}
++
++static void qcom_spi_remove(struct platform_device *pdev)
++{
++      struct spi_controller *ctlr = platform_get_drvdata(pdev);
++      struct qcom_nand_controller *snandc = spi_controller_get_devdata(ctlr);
++      struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++      spi_unregister_controller(ctlr);
++
++      qcom_nandc_unalloc(snandc);
++
++      clk_disable_unprepare(snandc->aon_clk);
++      clk_disable_unprepare(snandc->core_clk);
++      clk_disable_unprepare(snandc->qspi->iomacro_clk);
++
++      dma_unmap_resource(&pdev->dev, snandc->base_dma, resource_size(res),
++                         DMA_BIDIRECTIONAL, 0);
++}
++
++static const struct qcom_nandc_props ipq9574_snandc_props = {
++      .dev_cmd_reg_start = 0x7000,
++      .supports_bam = true,
++};
++
++static const struct of_device_id qcom_snandc_of_match[] = {
++      {
++              .compatible = "qcom,ipq9574-snand",
++              .data = &ipq9574_snandc_props,
++      },
++      {}
++}
++MODULE_DEVICE_TABLE(of, qcom_snandc_of_match);
++
++static struct platform_driver qcom_spi_driver = {
++      .driver = {
++              .name           = "qcom_snand",
++              .of_match_table = qcom_snandc_of_match,
++      },
++      .probe = qcom_spi_probe,
++      .remove_new = qcom_spi_remove,
++};
++module_platform_driver(qcom_spi_driver);
++
++MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores");
++MODULE_AUTHOR("Md Sadre Alam <[email protected]>");
++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 (file)
index 0000000..ad43f8d
--- /dev/null
@@ -0,0 +1,28 @@
+From cf1ba3cb245020459f2ca446b7a7b199839f5d83 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <[email protected]>
+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 <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Mark Brown <[email protected]>
+---
+ 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 (file)
index 0000000..1e2a3b0
--- /dev/null
@@ -0,0 +1,35 @@
+From d450cdd9c4398add1f2aa7200f2c95f1e3b9f9fa Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <[email protected]>
+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 <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Mark Brown <[email protected]>
+---
+ 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 (file)
index 0000000..5e92048
--- /dev/null
@@ -0,0 +1,49 @@
+From d32c4e58545f17caaa854415f854691e32d42075 Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <[email protected]>
+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 <[email protected]>
+Link: https://patch.msgid.link/b63db431cbf35223a4400e44c296293d32c4543c.1742998909.git.geert+renesas@glider.be
+Signed-off-by: Mark Brown <[email protected]>
+---
+ 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 (file)
index 0000000..9da531b
--- /dev/null
@@ -0,0 +1,36 @@
+From: Gabor Juhos <[email protected]>
+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 <[email protected]>
+Reviewed-by: Abel Vesa <[email protected]>
+Reviewed-by: Md Sadre Alam <[email protected]>
+---
+ 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 (file)
index 0000000..a2cd636
--- /dev/null
@@ -0,0 +1,35 @@
+From: Gabor Juhos <[email protected]>
+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 <[email protected]>
+Reviewed-by: Md Sadre Alam <[email protected]>
+---
+ 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 (file)
index 0000000..5a3d498
--- /dev/null
@@ -0,0 +1,29 @@
+From f48d80503504257682e493dc17408f2f0b47bcfa Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <[email protected]>
+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 <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Mark Brown <[email protected]>
+---
+ 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 (file)
index 0000000..55e84da
--- /dev/null
@@ -0,0 +1,30 @@
+From: Gabor Juhos <[email protected]>
+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 <[email protected]>
+---
+ 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 (file)
index 7dd0031..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-From 03cb793b26834ddca170ba87057c8f883772dd45 Mon Sep 17 00:00:00 2001
-From: Christian Marangi <[email protected]>
-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 <[email protected]>
-Reviewed-by: Christoph Hellwig <[email protected]>
-Link: https://lore.kernel.org/r/[email protected]
-Signed-off-by: Jens Axboe <[email protected]>
----
- 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 (file)
index b9fabe6..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-From e5f587242b6072ffab4f4a084a459a59f3035873 Mon Sep 17 00:00:00 2001
-From: Christian Marangi <[email protected]>
-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 <[email protected]>
-Reviewed-by: Christoph Hellwig <[email protected]>
-Link: https://lore.kernel.org/r/[email protected]
-Signed-off-by: Jens Axboe <[email protected]>
----
- 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 (file)
index 0bdeaa8..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-From 45ff6c340ddfc2dade74d5b7a8962c778ab7042c Mon Sep 17 00:00:00 2001
-From: Christian Marangi <[email protected]>
-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 <[email protected]>
-Reviewed-by: Linus Walleij <[email protected]>
-Link: https://lore.kernel.org/r/[email protected]
-Signed-off-by: Jens Axboe <[email protected]>
----
- 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 (file)
index d260be1..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-From 884555b557e5e6d41c866e2cd8d7b32f50ec974b Mon Sep 17 00:00:00 2001
-From: Christian Marangi <[email protected]>
-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 <[email protected]>
-Reviewed-by: Christoph Hellwig <[email protected]>
-Link: https://lore.kernel.org/r/[email protected]
-Signed-off-by: Jens Axboe <[email protected]>
----
- block/partitions/Kconfig  |   9 ++++
- block/partitions/Makefile |   1 +
- block/partitions/check.h  |   1 +
- block/partitions/core.c   |   3 ++
- block/partitions/of.c     | 110 ++++++++++++++++++++++++++++++++++++++
- 5 files changed, 124 insertions(+)
- create mode 100644 block/partitions/of.c
-
---- a/block/partitions/Kconfig
-+++ b/block/partitions/Kconfig
-@@ -270,4 +270,13 @@ config CMDLINE_PARTITION
-         Say Y here if you want to read the partition table from bootargs.
-         The format for the command line is just like mtdparts.
-+config OF_PARTITION
-+      bool "Device Tree partition support" if PARTITION_ADVANCED
-+      depends on OF
-+      help
-+        Say Y here if you want to enable support for partition table
-+        defined in Device Tree. (mainly for eMMC)
-+        The format for the device tree node is just like MTD fixed-partition
-+        schema.
-+
- endmenu
---- a/block/partitions/Makefile
-+++ b/block/partitions/Makefile
-@@ -12,6 +12,7 @@ obj-$(CONFIG_CMDLINE_PARTITION) += cmdli
- obj-$(CONFIG_MAC_PARTITION) += mac.o
- obj-$(CONFIG_LDM_PARTITION) += ldm.o
- obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
-+obj-$(CONFIG_OF_PARTITION) += of.o
- obj-$(CONFIG_OSF_PARTITION) += osf.o
- obj-$(CONFIG_SGI_PARTITION) += sgi.o
- obj-$(CONFIG_SUN_PARTITION) += sun.o
---- a/block/partitions/check.h
-+++ b/block/partitions/check.h
-@@ -62,6 +62,7 @@ int karma_partition(struct parsed_partit
- int ldm_partition(struct parsed_partitions *state);
- int mac_partition(struct parsed_partitions *state);
- int msdos_partition(struct parsed_partitions *state);
-+int of_partition(struct parsed_partitions *state);
- int osf_partition(struct parsed_partitions *state);
- int sgi_partition(struct parsed_partitions *state);
- int sun_partition(struct parsed_partitions *state);
---- a/block/partitions/core.c
-+++ b/block/partitions/core.c
-@@ -43,6 +43,9 @@ static int (*const check_part[])(struct
- #ifdef CONFIG_CMDLINE_PARTITION
-       cmdline_partition,
- #endif
-+#ifdef CONFIG_OF_PARTITION
-+      of_partition,           /* cmdline have priority to OF */
-+#endif
- #ifdef CONFIG_EFI_PARTITION
-       efi_partition,          /* this must come before msdos */
- #endif
---- /dev/null
-+++ b/block/partitions/of.c
-@@ -0,0 +1,110 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+#include <linux/blkdev.h>
-+#include <linux/major.h>
-+#include <linux/of.h>
-+#include <linux/string.h>
-+#include "check.h"
-+
-+static int validate_of_partition(struct device_node *np, int slot)
-+{
-+      u64 offset, size;
-+      int len;
-+
-+      const __be32 *reg = of_get_property(np, "reg", &len);
-+      int a_cells = of_n_addr_cells(np);
-+      int s_cells = of_n_size_cells(np);
-+
-+      /* Make sure reg len match the expected addr and size cells */
-+      if (len / sizeof(*reg) != a_cells + s_cells)
-+              return -EINVAL;
-+
-+      /* Validate offset conversion from bytes to sectors */
-+      offset = of_read_number(reg, a_cells);
-+      if (offset % SECTOR_SIZE)
-+              return -EINVAL;
-+
-+      /* Validate size conversion from bytes to sectors */
-+      size = of_read_number(reg + a_cells, s_cells);
-+      if (!size || size % SECTOR_SIZE)
-+              return -EINVAL;
-+
-+      return 0;
-+}
-+
-+static void add_of_partition(struct parsed_partitions *state, int slot,
-+                           struct device_node *np)
-+{
-+      struct partition_meta_info *info;
-+      char tmp[sizeof(info->volname) + 4];
-+      const char *partname;
-+      int len;
-+
-+      const __be32 *reg = of_get_property(np, "reg", &len);
-+      int a_cells = of_n_addr_cells(np);
-+      int s_cells = of_n_size_cells(np);
-+
-+      /* Convert bytes to sector size */
-+      u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE;
-+      u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE;
-+
-+      put_partition(state, slot, offset, size);
-+
-+      if (of_property_read_bool(np, "read-only"))
-+              state->parts[slot].flags |= ADDPART_FLAG_READONLY;
-+
-+      /*
-+       * Follow MTD label logic, search for label property,
-+       * fallback to node name if not found.
-+       */
-+      info = &state->parts[slot].info;
-+      partname = of_get_property(np, "label", &len);
-+      if (!partname)
-+              partname = of_get_property(np, "name", &len);
-+      strscpy(info->volname, partname, sizeof(info->volname));
-+
-+      snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
-+      strlcat(state->pp_buf, tmp, PAGE_SIZE);
-+}
-+
-+int of_partition(struct parsed_partitions *state)
-+{
-+      struct device *ddev = disk_to_dev(state->disk);
-+      struct device_node *np;
-+      int slot;
-+
-+      struct device_node *partitions_np = of_node_get(ddev->of_node);
-+
-+      if (!partitions_np ||
-+          !of_device_is_compatible(partitions_np, "fixed-partitions"))
-+              return 0;
-+
-+      slot = 1;
-+      /* Validate parition offset and size */
-+      for_each_child_of_node(partitions_np, np) {
-+              if (validate_of_partition(np, slot)) {
-+                      of_node_put(np);
-+                      of_node_put(partitions_np);
-+
-+                      return -1;
-+              }
-+
-+              slot++;
-+      }
-+
-+      slot = 1;
-+      for_each_child_of_node(partitions_np, np) {
-+              if (slot >= state->limit) {
-+                      of_node_put(np);
-+                      break;
-+              }
-+
-+              add_of_partition(state, slot, np);
-+
-+              slot++;
-+      }
-+
-+      strlcat(state->pp_buf, "\n", PAGE_SIZE);
-+
-+      return 1;
-+}
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 (file)
index 84b3b2a..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From ae461cde5c559675fc4c0ba351c7c31ace705f56 Mon Sep 17 00:00:00 2001
-From: Bohdan Chubuk <[email protected]>
-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 <[email protected]>
-Signed-off-by: Miquel Raynal <[email protected]>
----
- 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 (file)
index 8c5457a..0000000
+++ /dev/null
@@ -1,1013 +0,0 @@
-From 8c52932da5e6756fa66f52f0720da283fba13aa6 Mon Sep 17 00:00:00 2001
-From: Md Sadre Alam <[email protected]>
-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 <[email protected]>
-Signed-off-by: Miquel Raynal <[email protected]>
----
- 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 &regs->cmd;
--      case NAND_ADDR0:
--              return &regs->addr0;
--      case NAND_ADDR1:
--              return &regs->addr1;
--      case NAND_FLASH_CHIP_SELECT:
--              return &regs->chip_sel;
--      case NAND_EXEC_CMD:
--              return &regs->exec;
--      case NAND_FLASH_STATUS:
--              return &regs->clrflashstatus;
--      case NAND_DEV0_CFG0:
--              return &regs->cfg0;
--      case NAND_DEV0_CFG1:
--              return &regs->cfg1;
--      case NAND_DEV0_ECC_CFG:
--              return &regs->ecc_bch_cfg;
--      case NAND_READ_STATUS:
--              return &regs->clrreadstatus;
--      case NAND_DEV_CMD1:
--              return &regs->cmd1;
--      case NAND_DEV_CMD1_RESTORE:
--              return &regs->orig_cmd1;
--      case NAND_DEV_CMD_VLD:
--              return &regs->vld;
--      case NAND_DEV_CMD_VLD_RESTORE:
--              return &regs->orig_vld;
--      case NAND_EBI2_ECC_BUF_CFG:
--              return &regs->ecc_buf_cfg;
--      case NAND_READ_LOCATION_0:
--              return &regs->read_location0;
--      case NAND_READ_LOCATION_1:
--              return &regs->read_location1;
--      case NAND_READ_LOCATION_2:
--              return &regs->read_location2;
--      case NAND_READ_LOCATION_3:
--              return &regs->read_location3;
--      case NAND_READ_LOCATION_LAST_CW_0:
--              return &regs->read_location_last0;
--      case NAND_READ_LOCATION_LAST_CW_1:
--              return &regs->read_location_last1;
--      case NAND_READ_LOCATION_LAST_CW_2:
--              return &regs->read_location_last2;
--      case NAND_READ_LOCATION_LAST_CW_3:
--              return &regs->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 = &regs->erased_cw_detect_cfg_set;
--              else
--                      vaddr = &regs->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 (file)
index 078a56c..0000000
+++ /dev/null
@@ -1,880 +0,0 @@
-From 1d479f5b345e0c3650fec4dddeef9fc6fab30c8b Mon Sep 17 00:00:00 2001
-From: Md Sadre Alam <[email protected]>
-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 <[email protected]>
-Signed-off-by: Md Sadre Alam <[email protected]>
-Signed-off-by: Miquel Raynal <[email protected]>
----
- 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 (file)
index 2621146..0000000
+++ /dev/null
@@ -1,2436 +0,0 @@
-From fdf3ee5c6e5278dab4f60b998b47ed2d510bf80f Mon Sep 17 00:00:00 2001
-From: Md Sadre Alam <[email protected]>
-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 <[email protected]>
-Signed-off-by: Miquel Raynal <[email protected]>
----
- drivers/mtd/nand/Makefile            |    2 +-
- drivers/mtd/nand/qpic_common.c       |  759 ++++++++++++++++++
- drivers/mtd/nand/raw/qcom_nandc.c    | 1092 +-------------------------
- include/linux/mtd/nand-qpic-common.h |  468 +++++++++++
- 4 files changed, 1240 insertions(+), 1081 deletions(-)
- create mode 100644 drivers/mtd/nand/qpic_common.c
- create mode 100644 include/linux/mtd/nand-qpic-common.h
-
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -3,7 +3,7 @@
- nandcore-objs := core.o bbt.o
- obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
- obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
--
-+obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o
- obj-y += onenand/
- obj-y += raw/
- obj-y += spi/
---- /dev/null
-+++ b/drivers/mtd/nand/qpic_common.c
-@@ -0,0 +1,759 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved
-+ */
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/dmaengine.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma/qcom_adm.h>
-+#include <linux/dma/qcom_bam_dma.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/nand-qpic-common.h>
-+
-+/**
-+ * qcom_free_bam_transaction() - Frees the BAM transaction memory
-+ * @nandc: qpic nand controller
-+ *
-+ * This function frees the bam transaction memory
-+ */
-+void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
-+{
-+      struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+      kfree(bam_txn);
-+}
-+EXPORT_SYMBOL(qcom_free_bam_transaction);
-+
-+/**
-+ * qcom_alloc_bam_transaction() - allocate BAM transaction
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will allocate and initialize the BAM transaction structure
-+ */
-+struct bam_transaction *
-+qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
-+{
-+      struct bam_transaction *bam_txn;
-+      size_t bam_txn_size;
-+      unsigned int num_cw = nandc->max_cwperpage;
-+      void *bam_txn_buf;
-+
-+      bam_txn_size =
-+              sizeof(*bam_txn) + num_cw *
-+              ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
-+              (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
-+              (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
-+
-+      bam_txn_buf = kzalloc(bam_txn_size, GFP_KERNEL);
-+      if (!bam_txn_buf)
-+              return NULL;
-+
-+      bam_txn = bam_txn_buf;
-+      bam_txn_buf += sizeof(*bam_txn);
-+
-+      bam_txn->bam_ce = bam_txn_buf;
-+      bam_txn_buf +=
-+              sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
-+
-+      bam_txn->cmd_sgl = bam_txn_buf;
-+      bam_txn_buf +=
-+              sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
-+
-+      bam_txn->data_sgl = bam_txn_buf;
-+
-+      init_completion(&bam_txn->txn_done);
-+
-+      return bam_txn;
-+}
-+EXPORT_SYMBOL(qcom_alloc_bam_transaction);
-+
-+/**
-+ * qcom_clear_bam_transaction() - Clears the BAM transaction
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will clear the BAM transaction indexes.
-+ */
-+void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
-+{
-+      struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+      if (!nandc->props->supports_bam)
-+              return;
-+
-+      memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
-+      bam_txn->last_data_desc = NULL;
-+
-+      sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
-+                    QPIC_PER_CW_CMD_SGL);
-+      sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
-+                    QPIC_PER_CW_DATA_SGL);
-+
-+      reinit_completion(&bam_txn->txn_done);
-+}
-+EXPORT_SYMBOL(qcom_clear_bam_transaction);
-+
-+/**
-+ * qcom_qpic_bam_dma_done() - Callback for DMA descriptor completion
-+ * @data: data pointer
-+ *
-+ * This function is a callback for DMA descriptor completion
-+ */
-+void qcom_qpic_bam_dma_done(void *data)
-+{
-+      struct bam_transaction *bam_txn = data;
-+
-+      complete(&bam_txn->txn_done);
-+}
-+EXPORT_SYMBOL(qcom_qpic_bam_dma_done);
-+
-+/**
-+ * qcom_nandc_dev_to_mem() - Check for dma sync for cpu or device
-+ * @nandc: qpic nand controller
-+ * @is_cpu: cpu or Device
-+ *
-+ * This function will check for dma sync for cpu or device
-+ */
-+inline void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
-+{
-+      if (!nandc->props->supports_bam)
-+              return;
-+
-+      if (is_cpu)
-+              dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
-+                                      MAX_REG_RD *
-+                                      sizeof(*nandc->reg_read_buf),
-+                                      DMA_FROM_DEVICE);
-+      else
-+              dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
-+                                         MAX_REG_RD *
-+                                         sizeof(*nandc->reg_read_buf),
-+                                         DMA_FROM_DEVICE);
-+}
-+EXPORT_SYMBOL(qcom_nandc_dev_to_mem);
-+
-+/**
-+ * qcom_prepare_bam_async_desc() - Prepare DMA descriptor
-+ * @nandc: qpic nand controller
-+ * @chan: dma channel
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function maps the scatter gather list for DMA transfer and forms the
-+ * DMA descriptor for BAM.This descriptor will be added in the NAND DMA
-+ * descriptor queue which will be submitted to DMA engine.
-+ */
-+int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-+                              struct dma_chan *chan, unsigned long flags)
-+{
-+      struct desc_info *desc;
-+      struct scatterlist *sgl;
-+      unsigned int sgl_cnt;
-+      int ret;
-+      struct bam_transaction *bam_txn = nandc->bam_txn;
-+      enum dma_transfer_direction dir_eng;
-+      struct dma_async_tx_descriptor *dma_desc;
-+
-+      desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-+      if (!desc)
-+              return -ENOMEM;
-+
-+      if (chan == nandc->cmd_chan) {
-+              sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
-+              sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
-+              bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
-+              dir_eng = DMA_MEM_TO_DEV;
-+              desc->dir = DMA_TO_DEVICE;
-+      } else if (chan == nandc->tx_chan) {
-+              sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
-+              sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
-+              bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
-+              dir_eng = DMA_MEM_TO_DEV;
-+              desc->dir = DMA_TO_DEVICE;
-+      } else {
-+              sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
-+              sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
-+              bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
-+              dir_eng = DMA_DEV_TO_MEM;
-+              desc->dir = DMA_FROM_DEVICE;
-+      }
-+
-+      sg_mark_end(sgl + sgl_cnt - 1);
-+      ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-+      if (ret == 0) {
-+              dev_err(nandc->dev, "failure in mapping desc\n");
-+              kfree(desc);
-+              return -ENOMEM;
-+      }
-+
-+      desc->sgl_cnt = sgl_cnt;
-+      desc->bam_sgl = sgl;
-+
-+      dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
-+                                         flags);
-+
-+      if (!dma_desc) {
-+              dev_err(nandc->dev, "failure in prep desc\n");
-+              dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-+              kfree(desc);
-+              return -EINVAL;
-+      }
-+
-+      desc->dma_desc = dma_desc;
-+
-+      /* update last data/command descriptor */
-+      if (chan == nandc->cmd_chan)
-+              bam_txn->last_cmd_desc = dma_desc;
-+      else
-+              bam_txn->last_data_desc = dma_desc;
-+
-+      list_add_tail(&desc->node, &nandc->desc_list);
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(qcom_prepare_bam_async_desc);
-+
-+/**
-+ * qcom_prep_bam_dma_desc_cmd() - Prepares the command descriptor for BAM DMA
-+ * @nandc: qpic nand controller
-+ * @read: read or write type
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares the command descriptor for BAM DMA
-+ * which will be used for NAND register reads and writes.
-+ */
-+int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-+                             int reg_off, const void *vaddr,
-+                             int size, unsigned int flags)
-+{
-+      int bam_ce_size;
-+      int i, ret;
-+      struct bam_cmd_element *bam_ce_buffer;
-+      struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+      bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
-+
-+      /* fill the command desc */
-+      for (i = 0; i < size; i++) {
-+              if (read)
-+                      bam_prep_ce(&bam_ce_buffer[i],
-+                                  nandc_reg_phys(nandc, reg_off + 4 * i),
-+                                  BAM_READ_COMMAND,
-+                                  reg_buf_dma_addr(nandc,
-+                                                   (__le32 *)vaddr + i));
-+              else
-+                      bam_prep_ce_le32(&bam_ce_buffer[i],
-+                                       nandc_reg_phys(nandc, reg_off + 4 * i),
-+                                       BAM_WRITE_COMMAND,
-+                                       *((__le32 *)vaddr + i));
-+      }
-+
-+      bam_txn->bam_ce_pos += size;
-+
-+      /* use the separate sgl after this command */
-+      if (flags & NAND_BAM_NEXT_SGL) {
-+              bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
-+              bam_ce_size = (bam_txn->bam_ce_pos -
-+                              bam_txn->bam_ce_start) *
-+                              sizeof(struct bam_cmd_element);
-+              sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
-+                         bam_ce_buffer, bam_ce_size);
-+              bam_txn->cmd_sgl_pos++;
-+              bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
-+
-+              if (flags & NAND_BAM_NWD) {
-+                      ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+                                                        DMA_PREP_FENCE | DMA_PREP_CMD);
-+                      if (ret)
-+                              return ret;
-+              }
-+      }
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(qcom_prep_bam_dma_desc_cmd);
-+
-+/**
-+ * qcom_prep_bam_dma_desc_data() - Prepares the data descriptor for BAM DMA
-+ * @nandc: qpic nand controller
-+ * @read: read or write type
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares the data descriptor for BAM DMA which
-+ * will be used for NAND data reads and writes.
-+ */
-+int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-+                              const void *vaddr, int size, unsigned int flags)
-+{
-+      int ret;
-+      struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+      if (read) {
-+              sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
-+                         vaddr, size);
-+              bam_txn->rx_sgl_pos++;
-+      } else {
-+              sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
-+                         vaddr, size);
-+              bam_txn->tx_sgl_pos++;
-+
-+              /*
-+               * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
-+               * is not set, form the DMA descriptor
-+               */
-+              if (!(flags & NAND_BAM_NO_EOT)) {
-+                      ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+                                                        DMA_PREP_INTERRUPT);
-+                      if (ret)
-+                              return ret;
-+              }
-+      }
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(qcom_prep_bam_dma_desc_data);
-+
-+/**
-+ * qcom_prep_adm_dma_desc() - Prepare descriptor for adma
-+ * @nandc: qpic nand controller
-+ * @read: read or write type
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: adm dma transaction size in bytes
-+ * @flow_control: flow controller
-+ *
-+ * This function will prepare descriptor for adma
-+ */
-+int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-+                         int reg_off, const void *vaddr, int size,
-+                         bool flow_control)
-+{
-+      struct qcom_adm_peripheral_config periph_conf = {};
-+      struct dma_async_tx_descriptor *dma_desc;
-+      struct dma_slave_config slave_conf = {0};
-+      enum dma_transfer_direction dir_eng;
-+      struct desc_info *desc;
-+      struct scatterlist *sgl;
-+      int ret;
-+
-+      desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-+      if (!desc)
-+              return -ENOMEM;
-+
-+      sgl = &desc->adm_sgl;
-+
-+      sg_init_one(sgl, vaddr, size);
-+
-+      if (read) {
-+              dir_eng = DMA_DEV_TO_MEM;
-+              desc->dir = DMA_FROM_DEVICE;
-+      } else {
-+              dir_eng = DMA_MEM_TO_DEV;
-+              desc->dir = DMA_TO_DEVICE;
-+      }
-+
-+      ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
-+      if (!ret) {
-+              ret = -ENOMEM;
-+              goto err;
-+      }
-+
-+      slave_conf.device_fc = flow_control;
-+      if (read) {
-+              slave_conf.src_maxburst = 16;
-+              slave_conf.src_addr = nandc->base_dma + reg_off;
-+              if (nandc->data_crci) {
-+                      periph_conf.crci = nandc->data_crci;
-+                      slave_conf.peripheral_config = &periph_conf;
-+                      slave_conf.peripheral_size = sizeof(periph_conf);
-+              }
-+      } else {
-+              slave_conf.dst_maxburst = 16;
-+              slave_conf.dst_addr = nandc->base_dma + reg_off;
-+              if (nandc->cmd_crci) {
-+                      periph_conf.crci = nandc->cmd_crci;
-+                      slave_conf.peripheral_config = &periph_conf;
-+                      slave_conf.peripheral_size = sizeof(periph_conf);
-+              }
-+      }
-+
-+      ret = dmaengine_slave_config(nandc->chan, &slave_conf);
-+      if (ret) {
-+              dev_err(nandc->dev, "failed to configure dma channel\n");
-+              goto err;
-+      }
-+
-+      dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
-+      if (!dma_desc) {
-+              dev_err(nandc->dev, "failed to prepare desc\n");
-+              ret = -EINVAL;
-+              goto err;
-+      }
-+
-+      desc->dma_desc = dma_desc;
-+
-+      list_add_tail(&desc->node, &nandc->desc_list);
-+
-+      return 0;
-+err:
-+      kfree(desc);
-+
-+      return ret;
-+}
-+EXPORT_SYMBOL(qcom_prep_adm_dma_desc);
-+
-+/**
-+ * qcom_read_reg_dma() - read a given number of registers to the reg_read_buf pointer
-+ * @nandc: qpic nand controller
-+ * @first: offset of the first register in the contiguous block
-+ * @num_regs: number of registers to read
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a descriptor to read a given number of
-+ * contiguous registers to the reg_read_buf pointer.
-+ */
-+int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
-+                    int num_regs, unsigned int flags)
-+{
-+      bool flow_control = false;
-+      void *vaddr;
-+
-+      vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
-+      nandc->reg_read_pos += num_regs;
-+
-+      if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
-+              first = dev_cmd_reg_addr(nandc, first);
-+
-+      if (nandc->props->supports_bam)
-+              return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
-+                                           num_regs, flags);
-+
-+      if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
-+              flow_control = true;
-+
-+      return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
-+                                    num_regs * sizeof(u32), flow_control);
-+}
-+EXPORT_SYMBOL(qcom_read_reg_dma);
-+
-+/**
-+ * qcom_write_reg_dma() - write a given number of registers
-+ * @nandc: qpic nand controller
-+ * @vaddr: contiguous memory from where register value will
-+ *       be written
-+ * @first: offset of the first register in the contiguous block
-+ * @num_regs: number of registers to write
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a descriptor to write a given number of
-+ * contiguous registers
-+ */
-+int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-+                     int first, int num_regs, unsigned int flags)
-+{
-+      bool flow_control = false;
-+
-+      if (first == NAND_EXEC_CMD)
-+              flags |= NAND_BAM_NWD;
-+
-+      if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
-+              first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
-+
-+      if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
-+              first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
-+
-+      if (nandc->props->supports_bam)
-+              return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
-+                                                num_regs, flags);
-+
-+      if (first == NAND_FLASH_CMD)
-+              flow_control = true;
-+
-+      return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
-+                                    num_regs * sizeof(u32), flow_control);
-+}
-+EXPORT_SYMBOL(qcom_write_reg_dma);
-+
-+/**
-+ * qcom_read_data_dma() - transfer data
-+ * @nandc: qpic nand controller
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a DMA descriptor to transfer data from the
-+ * controller's internal buffer to the buffer 'vaddr'
-+ */
-+int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+                     const u8 *vaddr, int size, unsigned int flags)
-+{
-+      if (nandc->props->supports_bam)
-+              return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-+
-+      return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
-+}
-+EXPORT_SYMBOL(qcom_read_data_dma);
-+
-+/**
-+ * qcom_write_data_dma() - transfer data
-+ * @nandc: qpic nand controller
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to read from
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a DMA descriptor to transfer data from
-+ * 'vaddr' to the controller's internal buffer
-+ */
-+int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+                      const u8 *vaddr, int size, unsigned int flags)
-+{
-+      if (nandc->props->supports_bam)
-+              return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-+
-+      return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
-+}
-+EXPORT_SYMBOL(qcom_write_data_dma);
-+
-+/**
-+ * qcom_submit_descs() - submit dma descriptor
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will submit all the prepared dma descriptor
-+ * cmd or data descriptor
-+ */
-+int qcom_submit_descs(struct qcom_nand_controller *nandc)
-+{
-+      struct desc_info *desc, *n;
-+      dma_cookie_t cookie = 0;
-+      struct bam_transaction *bam_txn = nandc->bam_txn;
-+      int ret = 0;
-+
-+      if (nandc->props->supports_bam) {
-+              if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
-+                      ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
-+                      if (ret)
-+                              goto err_unmap_free_desc;
-+              }
-+
-+              if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
-+                      ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+                                                        DMA_PREP_INTERRUPT);
-+                      if (ret)
-+                              goto err_unmap_free_desc;
-+              }
-+
-+              if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-+                      ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+                                                        DMA_PREP_CMD);
-+                      if (ret)
-+                              goto err_unmap_free_desc;
-+              }
-+      }
-+
-+      list_for_each_entry(desc, &nandc->desc_list, node)
-+              cookie = dmaengine_submit(desc->dma_desc);
-+
-+      if (nandc->props->supports_bam) {
-+              bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
-+              bam_txn->last_cmd_desc->callback_param = bam_txn;
-+
-+              dma_async_issue_pending(nandc->tx_chan);
-+              dma_async_issue_pending(nandc->rx_chan);
-+              dma_async_issue_pending(nandc->cmd_chan);
-+
-+              if (!wait_for_completion_timeout(&bam_txn->txn_done,
-+                                               QPIC_NAND_COMPLETION_TIMEOUT))
-+                      ret = -ETIMEDOUT;
-+      } else {
-+              if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
-+                      ret = -ETIMEDOUT;
-+      }
-+
-+err_unmap_free_desc:
-+      /*
-+       * Unmap the dma sg_list and free the desc allocated by both
-+       * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
-+       */
-+      list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
-+              list_del(&desc->node);
-+
-+              if (nandc->props->supports_bam)
-+                      dma_unmap_sg(nandc->dev, desc->bam_sgl,
-+                                   desc->sgl_cnt, desc->dir);
-+              else
-+                      dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
-+                                   desc->dir);
-+
-+              kfree(desc);
-+      }
-+
-+      return ret;
-+}
-+EXPORT_SYMBOL(qcom_submit_descs);
-+
-+/**
-+ * qcom_clear_read_regs() - reset the read register buffer
-+ * @nandc: qpic nand controller
-+ *
-+ * This function reset the register read buffer for next NAND operation
-+ */
-+void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
-+{
-+      nandc->reg_read_pos = 0;
-+      qcom_nandc_dev_to_mem(nandc, false);
-+}
-+EXPORT_SYMBOL(qcom_clear_read_regs);
-+
-+/**
-+ * qcom_nandc_unalloc() - unallocate qpic nand controller
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will unallocate memory alloacted for qpic nand controller
-+ */
-+void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
-+{
-+      if (nandc->props->supports_bam) {
-+              if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
-+                      dma_unmap_single(nandc->dev, nandc->reg_read_dma,
-+                                       MAX_REG_RD *
-+                                       sizeof(*nandc->reg_read_buf),
-+                                       DMA_FROM_DEVICE);
-+
-+              if (nandc->tx_chan)
-+                      dma_release_channel(nandc->tx_chan);
-+
-+              if (nandc->rx_chan)
-+                      dma_release_channel(nandc->rx_chan);
-+
-+              if (nandc->cmd_chan)
-+                      dma_release_channel(nandc->cmd_chan);
-+      } else {
-+              if (nandc->chan)
-+                      dma_release_channel(nandc->chan);
-+      }
-+}
-+EXPORT_SYMBOL(qcom_nandc_unalloc);
-+
-+/**
-+ * qcom_nandc_alloc() - Allocate qpic nand controller
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will allocate memory for qpic nand controller
-+ */
-+int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
-+{
-+      int ret;
-+
-+      ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
-+      if (ret) {
-+              dev_err(nandc->dev, "failed to set DMA mask\n");
-+              return ret;
-+      }
-+
-+      /*
-+       * we use the internal buffer for reading ONFI params, reading small
-+       * data like ID and status, and preforming read-copy-write operations
-+       * when writing to a codeword partially. 532 is the maximum possible
-+       * size of a codeword for our nand controller
-+       */
-+      nandc->buf_size = 532;
-+
-+      nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
-+      if (!nandc->data_buffer)
-+              return -ENOMEM;
-+
-+      nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
-+      if (!nandc->regs)
-+              return -ENOMEM;
-+
-+      nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
-+                                         sizeof(*nandc->reg_read_buf),
-+                                         GFP_KERNEL);
-+      if (!nandc->reg_read_buf)
-+              return -ENOMEM;
-+
-+      if (nandc->props->supports_bam) {
-+              nandc->reg_read_dma =
-+                      dma_map_single(nandc->dev, nandc->reg_read_buf,
-+                                     MAX_REG_RD *
-+                                     sizeof(*nandc->reg_read_buf),
-+                                     DMA_FROM_DEVICE);
-+              if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
-+                      dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
-+                      return -EIO;
-+              }
-+
-+              nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
-+              if (IS_ERR(nandc->tx_chan)) {
-+                      ret = PTR_ERR(nandc->tx_chan);
-+                      nandc->tx_chan = NULL;
-+                      dev_err_probe(nandc->dev, ret,
-+                                    "tx DMA channel request failed\n");
-+                      goto unalloc;
-+              }
-+
-+              nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
-+              if (IS_ERR(nandc->rx_chan)) {
-+                      ret = PTR_ERR(nandc->rx_chan);
-+                      nandc->rx_chan = NULL;
-+                      dev_err_probe(nandc->dev, ret,
-+                                    "rx DMA channel request failed\n");
-+                      goto unalloc;
-+              }
-+
-+              nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
-+              if (IS_ERR(nandc->cmd_chan)) {
-+                      ret = PTR_ERR(nandc->cmd_chan);
-+                      nandc->cmd_chan = NULL;
-+                      dev_err_probe(nandc->dev, ret,
-+                                    "cmd DMA channel request failed\n");
-+                      goto unalloc;
-+              }
-+
-+              /*
-+               * Initially allocate BAM transaction to read ONFI param page.
-+               * After detecting all the devices, this BAM transaction will
-+               * be freed and the next BAM transaction will be allocated with
-+               * maximum codeword size
-+               */
-+              nandc->max_cwperpage = 1;
-+              nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
-+              if (!nandc->bam_txn) {
-+                      dev_err(nandc->dev,
-+                              "failed to allocate bam transaction\n");
-+                      ret = -ENOMEM;
-+                      goto unalloc;
-+              }
-+      } else {
-+              nandc->chan = dma_request_chan(nandc->dev, "rxtx");
-+              if (IS_ERR(nandc->chan)) {
-+                      ret = PTR_ERR(nandc->chan);
-+                      nandc->chan = NULL;
-+                      dev_err_probe(nandc->dev, ret,
-+                                    "rxtx DMA channel request failed\n");
-+                      return ret;
-+              }
-+      }
-+
-+      INIT_LIST_HEAD(&nandc->desc_list);
-+      INIT_LIST_HEAD(&nandc->host_list);
-+
-+      return 0;
-+unalloc:
-+      qcom_nandc_unalloc(nandc);
-+      return ret;
-+}
-+EXPORT_SYMBOL(qcom_nandc_alloc);
-+
-+MODULE_DESCRIPTION("QPIC controller common api");
-+MODULE_LICENSE("GPL");
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -15,417 +15,7 @@
- #include <linux/of.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
--
--/* NANDc reg offsets */
--#define       NAND_FLASH_CMD                  0x00
--#define       NAND_ADDR0                      0x04
--#define       NAND_ADDR1                      0x08
--#define       NAND_FLASH_CHIP_SELECT          0x0c
--#define       NAND_EXEC_CMD                   0x10
--#define       NAND_FLASH_STATUS               0x14
--#define       NAND_BUFFER_STATUS              0x18
--#define       NAND_DEV0_CFG0                  0x20
--#define       NAND_DEV0_CFG1                  0x24
--#define       NAND_DEV0_ECC_CFG               0x28
--#define       NAND_AUTO_STATUS_EN             0x2c
--#define       NAND_DEV1_CFG0                  0x30
--#define       NAND_DEV1_CFG1                  0x34
--#define       NAND_READ_ID                    0x40
--#define       NAND_READ_STATUS                0x44
--#define       NAND_DEV_CMD0                   0xa0
--#define       NAND_DEV_CMD1                   0xa4
--#define       NAND_DEV_CMD2                   0xa8
--#define       NAND_DEV_CMD_VLD                0xac
--#define       SFLASHC_BURST_CFG               0xe0
--#define       NAND_ERASED_CW_DETECT_CFG       0xe8
--#define       NAND_ERASED_CW_DETECT_STATUS    0xec
--#define       NAND_EBI2_ECC_BUF_CFG           0xf0
--#define       FLASH_BUF_ACC                   0x100
--
--#define       NAND_CTRL                       0xf00
--#define       NAND_VERSION                    0xf08
--#define       NAND_READ_LOCATION_0            0xf20
--#define       NAND_READ_LOCATION_1            0xf24
--#define       NAND_READ_LOCATION_2            0xf28
--#define       NAND_READ_LOCATION_3            0xf2c
--#define       NAND_READ_LOCATION_LAST_CW_0    0xf40
--#define       NAND_READ_LOCATION_LAST_CW_1    0xf44
--#define       NAND_READ_LOCATION_LAST_CW_2    0xf48
--#define       NAND_READ_LOCATION_LAST_CW_3    0xf4c
--
--/* dummy register offsets, used by qcom_write_reg_dma */
--#define       NAND_DEV_CMD1_RESTORE           0xdead
--#define       NAND_DEV_CMD_VLD_RESTORE        0xbeef
--
--/* NAND_FLASH_CMD bits */
--#define       PAGE_ACC                        BIT(4)
--#define       LAST_PAGE                       BIT(5)
--
--/* NAND_FLASH_CHIP_SELECT bits */
--#define       NAND_DEV_SEL                    0
--#define       DM_EN                           BIT(2)
--
--/* NAND_FLASH_STATUS bits */
--#define       FS_OP_ERR                       BIT(4)
--#define       FS_READY_BSY_N                  BIT(5)
--#define       FS_MPU_ERR                      BIT(8)
--#define       FS_DEVICE_STS_ERR               BIT(16)
--#define       FS_DEVICE_WP                    BIT(23)
--
--/* NAND_BUFFER_STATUS bits */
--#define       BS_UNCORRECTABLE_BIT            BIT(8)
--#define       BS_CORRECTABLE_ERR_MSK          0x1f
--
--/* NAND_DEVn_CFG0 bits */
--#define       DISABLE_STATUS_AFTER_WRITE      4
--#define       CW_PER_PAGE                     6
--#define       UD_SIZE_BYTES                   9
--#define       UD_SIZE_BYTES_MASK              GENMASK(18, 9)
--#define       ECC_PARITY_SIZE_BYTES_RS        19
--#define       SPARE_SIZE_BYTES                23
--#define       SPARE_SIZE_BYTES_MASK           GENMASK(26, 23)
--#define       NUM_ADDR_CYCLES                 27
--#define       STATUS_BFR_READ                 30
--#define       SET_RD_MODE_AFTER_STATUS        31
--
--/* NAND_DEVn_CFG0 bits */
--#define       DEV0_CFG1_ECC_DISABLE           0
--#define       WIDE_FLASH                      1
--#define       NAND_RECOVERY_CYCLES            2
--#define       CS_ACTIVE_BSY                   5
--#define       BAD_BLOCK_BYTE_NUM              6
--#define       BAD_BLOCK_IN_SPARE_AREA         16
--#define       WR_RD_BSY_GAP                   17
--#define       ENABLE_BCH_ECC                  27
--
--/* NAND_DEV0_ECC_CFG bits */
--#define       ECC_CFG_ECC_DISABLE             0
--#define       ECC_SW_RESET                    1
--#define       ECC_MODE                        4
--#define       ECC_PARITY_SIZE_BYTES_BCH       8
--#define       ECC_NUM_DATA_BYTES              16
--#define       ECC_NUM_DATA_BYTES_MASK         GENMASK(25, 16)
--#define       ECC_FORCE_CLK_OPEN              30
--
--/* NAND_DEV_CMD1 bits */
--#define       READ_ADDR                       0
--
--/* NAND_DEV_CMD_VLD bits */
--#define       READ_START_VLD                  BIT(0)
--#define       READ_STOP_VLD                   BIT(1)
--#define       WRITE_START_VLD                 BIT(2)
--#define       ERASE_START_VLD                 BIT(3)
--#define       SEQ_READ_START_VLD              BIT(4)
--
--/* NAND_EBI2_ECC_BUF_CFG bits */
--#define       NUM_STEPS                       0
--
--/* NAND_ERASED_CW_DETECT_CFG bits */
--#define       ERASED_CW_ECC_MASK              1
--#define       AUTO_DETECT_RES                 0
--#define       MASK_ECC                        BIT(ERASED_CW_ECC_MASK)
--#define       RESET_ERASED_DET                BIT(AUTO_DETECT_RES)
--#define       ACTIVE_ERASED_DET               (0 << AUTO_DETECT_RES)
--#define       CLR_ERASED_PAGE_DET             (RESET_ERASED_DET | MASK_ECC)
--#define       SET_ERASED_PAGE_DET             (ACTIVE_ERASED_DET | MASK_ECC)
--
--/* NAND_ERASED_CW_DETECT_STATUS bits */
--#define       PAGE_ALL_ERASED                 BIT(7)
--#define       CODEWORD_ALL_ERASED             BIT(6)
--#define       PAGE_ERASED                     BIT(5)
--#define       CODEWORD_ERASED                 BIT(4)
--#define       ERASED_PAGE                     (PAGE_ALL_ERASED | PAGE_ERASED)
--#define       ERASED_CW                       (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
--
--/* NAND_READ_LOCATION_n bits */
--#define READ_LOCATION_OFFSET          0
--#define READ_LOCATION_SIZE            16
--#define READ_LOCATION_LAST            31
--
--/* Version Mask */
--#define       NAND_VERSION_MAJOR_MASK         0xf0000000
--#define       NAND_VERSION_MAJOR_SHIFT        28
--#define       NAND_VERSION_MINOR_MASK         0x0fff0000
--#define       NAND_VERSION_MINOR_SHIFT        16
--
--/* NAND OP_CMDs */
--#define       OP_PAGE_READ                    0x2
--#define       OP_PAGE_READ_WITH_ECC           0x3
--#define       OP_PAGE_READ_WITH_ECC_SPARE     0x4
--#define       OP_PAGE_READ_ONFI_READ          0x5
--#define       OP_PROGRAM_PAGE                 0x6
--#define       OP_PAGE_PROGRAM_WITH_ECC        0x7
--#define       OP_PROGRAM_PAGE_SPARE           0x9
--#define       OP_BLOCK_ERASE                  0xa
--#define       OP_CHECK_STATUS                 0xc
--#define       OP_FETCH_ID                     0xb
--#define       OP_RESET_DEVICE                 0xd
--
--/* Default Value for NAND_DEV_CMD_VLD */
--#define NAND_DEV_CMD_VLD_VAL          (READ_START_VLD | WRITE_START_VLD | \
--                                       ERASE_START_VLD | SEQ_READ_START_VLD)
--
--/* NAND_CTRL bits */
--#define       BAM_MODE_EN                     BIT(0)
--
--/*
-- * the NAND controller performs reads/writes with ECC in 516 byte chunks.
-- * the driver calls the chunks 'step' or 'codeword' interchangeably
-- */
--#define       NANDC_STEP_SIZE                 512
--
--/*
-- * the largest page size we support is 8K, this will have 16 steps/codewords
-- * of 512 bytes each
-- */
--#define       MAX_NUM_STEPS                   (SZ_8K / NANDC_STEP_SIZE)
--
--/* we read at most 3 registers per codeword scan */
--#define       MAX_REG_RD                      (3 * MAX_NUM_STEPS)
--
--/* ECC modes supported by the controller */
--#define       ECC_NONE        BIT(0)
--#define       ECC_RS_4BIT     BIT(1)
--#define       ECC_BCH_4BIT    BIT(2)
--#define       ECC_BCH_8BIT    BIT(3)
--
--/*
-- * Returns the actual register address for all NAND_DEV_ registers
-- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
-- */
--#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
--
--/* Returns the NAND register physical address */
--#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
--
--/* Returns the dma address for reg read buffer */
--#define reg_buf_dma_addr(chip, vaddr) \
--      ((chip)->reg_read_dma + \
--      ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
--
--#define QPIC_PER_CW_CMD_ELEMENTS      32
--#define QPIC_PER_CW_CMD_SGL           32
--#define QPIC_PER_CW_DATA_SGL          8
--
--#define QPIC_NAND_COMPLETION_TIMEOUT  msecs_to_jiffies(2000)
--
--/*
-- * Flags used in DMA descriptor preparation helper functions
-- * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
-- */
--/* Don't set the EOT in current tx BAM sgl */
--#define NAND_BAM_NO_EOT                       BIT(0)
--/* Set the NWD flag in current BAM sgl */
--#define NAND_BAM_NWD                  BIT(1)
--/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
--#define NAND_BAM_NEXT_SGL             BIT(2)
--/*
-- * Erased codeword status is being used two times in single transfer so this
-- * flag will determine the current value of erased codeword status register
-- */
--#define NAND_ERASED_CW_SET            BIT(4)
--
--#define MAX_ADDRESS_CYCLE             5
--
--/*
-- * This data type corresponds to the BAM transaction which will be used for all
-- * NAND transfers.
-- * @bam_ce - the array of BAM command elements
-- * @cmd_sgl - sgl for NAND BAM command pipe
-- * @data_sgl - sgl for NAND BAM consumer/producer pipe
-- * @last_data_desc - last DMA desc in data channel (tx/rx).
-- * @last_cmd_desc - last DMA desc in command channel.
-- * @txn_done - completion for NAND transfer.
-- * @bam_ce_pos - the index in bam_ce which is available for next sgl
-- * @bam_ce_start - the index in bam_ce which marks the start position ce
-- *               for current sgl. It will be used for size calculation
-- *               for current sgl
-- * @cmd_sgl_pos - current index in command sgl.
-- * @cmd_sgl_start - start index in command sgl.
-- * @tx_sgl_pos - current index in data sgl for tx.
-- * @tx_sgl_start - start index in data sgl for tx.
-- * @rx_sgl_pos - current index in data sgl for rx.
-- * @rx_sgl_start - start index in data sgl for rx.
-- */
--struct bam_transaction {
--      struct bam_cmd_element *bam_ce;
--      struct scatterlist *cmd_sgl;
--      struct scatterlist *data_sgl;
--      struct dma_async_tx_descriptor *last_data_desc;
--      struct dma_async_tx_descriptor *last_cmd_desc;
--      struct completion txn_done;
--      u32 bam_ce_pos;
--      u32 bam_ce_start;
--      u32 cmd_sgl_pos;
--      u32 cmd_sgl_start;
--      u32 tx_sgl_pos;
--      u32 tx_sgl_start;
--      u32 rx_sgl_pos;
--      u32 rx_sgl_start;
--};
--
--/*
-- * This data type corresponds to the nand dma descriptor
-- * @dma_desc - low level DMA engine descriptor
-- * @list - list for desc_info
-- *
-- * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
-- *          ADM
-- * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
-- * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
-- * @dir - DMA transfer direction
-- */
--struct desc_info {
--      struct dma_async_tx_descriptor *dma_desc;
--      struct list_head node;
--
--      union {
--              struct scatterlist adm_sgl;
--              struct {
--                      struct scatterlist *bam_sgl;
--                      int sgl_cnt;
--              };
--      };
--      enum dma_data_direction dir;
--};
--
--/*
-- * holds the current register values that we want to write. acts as a contiguous
-- * chunk of memory which we use to write the controller registers through DMA.
-- */
--struct nandc_regs {
--      __le32 cmd;
--      __le32 addr0;
--      __le32 addr1;
--      __le32 chip_sel;
--      __le32 exec;
--
--      __le32 cfg0;
--      __le32 cfg1;
--      __le32 ecc_bch_cfg;
--
--      __le32 clrflashstatus;
--      __le32 clrreadstatus;
--
--      __le32 cmd1;
--      __le32 vld;
--
--      __le32 orig_cmd1;
--      __le32 orig_vld;
--
--      __le32 ecc_buf_cfg;
--      __le32 read_location0;
--      __le32 read_location1;
--      __le32 read_location2;
--      __le32 read_location3;
--      __le32 read_location_last0;
--      __le32 read_location_last1;
--      __le32 read_location_last2;
--      __le32 read_location_last3;
--
--      __le32 erased_cw_detect_cfg_clr;
--      __le32 erased_cw_detect_cfg_set;
--};
--
--/*
-- * NAND controller data struct
-- *
-- * @dev:                      parent device
-- *
-- * @base:                     MMIO base
-- *
-- * @core_clk:                 controller clock
-- * @aon_clk:                  another controller clock
-- *
-- * @regs:                     a contiguous chunk of memory for DMA register
-- *                            writes. contains the register values to be
-- *                            written to controller
-- *
-- * @props:                    properties of current NAND controller,
-- *                            initialized via DT match data
-- *
-- * @controller:                       base controller structure
-- * @host_list:                        list containing all the chips attached to the
-- *                            controller
-- *
-- * @chan:                     dma channel
-- * @cmd_crci:                 ADM DMA CRCI for command flow control
-- * @data_crci:                        ADM DMA CRCI for data flow control
-- *
-- * @desc_list:                        DMA descriptor list (list of desc_infos)
-- *
-- * @data_buffer:              our local DMA buffer for page read/writes,
-- *                            used when we can't use the buffer provided
-- *                            by upper layers directly
-- * @reg_read_buf:             local buffer for reading back registers via DMA
-- *
-- * @base_phys:                        physical base address of controller registers
-- * @base_dma:                 dma base address of controller registers
-- * @reg_read_dma:             contains dma address for register read buffer
-- *
-- * @buf_size/count/start:     markers for chip->legacy.read_buf/write_buf
-- *                            functions
-- * @max_cwperpage:            maximum QPIC codewords required. calculated
-- *                            from all connected NAND devices pagesize
-- *
-- * @reg_read_pos:             marker for data read in reg_read_buf
-- *
-- * @cmd1/vld:                 some fixed controller register values
-- *
-- * @exec_opwrite:             flag to select correct number of code word
-- *                            while reading status
-- */
--struct qcom_nand_controller {
--      struct device *dev;
--
--      void __iomem *base;
--
--      struct clk *core_clk;
--      struct clk *aon_clk;
--
--      struct nandc_regs *regs;
--      struct bam_transaction *bam_txn;
--
--      const struct qcom_nandc_props *props;
--
--      struct nand_controller controller;
--      struct list_head host_list;
--
--      union {
--              /* will be used only by QPIC for BAM DMA */
--              struct {
--                      struct dma_chan *tx_chan;
--                      struct dma_chan *rx_chan;
--                      struct dma_chan *cmd_chan;
--              };
--
--              /* will be used only by EBI2 for ADM DMA */
--              struct {
--                      struct dma_chan *chan;
--                      unsigned int cmd_crci;
--                      unsigned int data_crci;
--              };
--      };
--
--      struct list_head desc_list;
--
--      u8              *data_buffer;
--      __le32          *reg_read_buf;
--
--      phys_addr_t base_phys;
--      dma_addr_t base_dma;
--      dma_addr_t reg_read_dma;
--
--      int             buf_size;
--      int             buf_count;
--      int             buf_start;
--      unsigned int    max_cwperpage;
--
--      int reg_read_pos;
--
--      u32 cmd1, vld;
--      bool exec_opwrite;
--};
-+#include <linux/mtd/nand-qpic-common.h>
- /*
-  * NAND special boot partitions
-@@ -530,97 +120,6 @@ struct qcom_nand_host {
-       bool bch_enabled;
- };
--/*
-- * This data type corresponds to the NAND controller properties which varies
-- * among different NAND controllers.
-- * @ecc_modes - ecc mode for NAND
-- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
-- * @supports_bam - whether NAND controller is using Bus Access Manager (BAM)
-- * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
-- * @qpic_version2 - flag to indicate QPIC IP version 2
-- * @use_codeword_fixup - whether NAND has different layout for boot partitions
-- */
--struct qcom_nandc_props {
--      u32 ecc_modes;
--      u32 dev_cmd_reg_start;
--      bool supports_bam;
--      bool nandc_part_of_qpic;
--      bool qpic_version2;
--      bool use_codeword_fixup;
--};
--
--/* Frees the BAM transaction memory */
--static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
--{
--      struct bam_transaction *bam_txn = nandc->bam_txn;
--
--      devm_kfree(nandc->dev, bam_txn);
--}
--
--/* Allocates and Initializes the BAM transaction */
--static struct bam_transaction *
--qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
--{
--      struct bam_transaction *bam_txn;
--      size_t bam_txn_size;
--      unsigned int num_cw = nandc->max_cwperpage;
--      void *bam_txn_buf;
--
--      bam_txn_size =
--              sizeof(*bam_txn) + num_cw *
--              ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
--              (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
--              (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
--
--      bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
--      if (!bam_txn_buf)
--              return NULL;
--
--      bam_txn = bam_txn_buf;
--      bam_txn_buf += sizeof(*bam_txn);
--
--      bam_txn->bam_ce = bam_txn_buf;
--      bam_txn_buf +=
--              sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
--
--      bam_txn->cmd_sgl = bam_txn_buf;
--      bam_txn_buf +=
--              sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
--
--      bam_txn->data_sgl = bam_txn_buf;
--
--      init_completion(&bam_txn->txn_done);
--
--      return bam_txn;
--}
--
--/* Clears the BAM transaction indexes */
--static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
--{
--      struct bam_transaction *bam_txn = nandc->bam_txn;
--
--      if (!nandc->props->supports_bam)
--              return;
--
--      memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
--      bam_txn->last_data_desc = NULL;
--
--      sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
--                    QPIC_PER_CW_CMD_SGL);
--      sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
--                    QPIC_PER_CW_DATA_SGL);
--
--      reinit_completion(&bam_txn->txn_done);
--}
--
--/* Callback for DMA descriptor completion */
--static void qcom_qpic_bam_dma_done(void *data)
--{
--      struct bam_transaction *bam_txn = data;
--
--      complete(&bam_txn->txn_done);
--}
--
- static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
- {
-       return container_of(chip, struct qcom_nand_host, chip);
-@@ -629,8 +128,8 @@ static struct qcom_nand_host *to_qcom_na
- static struct qcom_nand_controller *
- get_qcom_nand_controller(struct nand_chip *chip)
- {
--      return container_of(chip->controller, struct qcom_nand_controller,
--                          controller);
-+      return (struct qcom_nand_controller *)
-+              ((u8 *)chip->controller - sizeof(struct qcom_nand_controller));
- }
- static u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
-@@ -644,23 +143,6 @@ static void nandc_write(struct qcom_nand
-       iowrite32(val, nandc->base + offset);
- }
--static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
--{
--      if (!nandc->props->supports_bam)
--              return;
--
--      if (is_cpu)
--              dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
--                                      MAX_REG_RD *
--                                      sizeof(*nandc->reg_read_buf),
--                                      DMA_FROM_DEVICE);
--      else
--              dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
--                                         MAX_REG_RD *
--                                         sizeof(*nandc->reg_read_buf),
--                                         DMA_FROM_DEVICE);
--}
--
- /* Helper to check whether this is the last CW or not */
- static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
- {
-@@ -820,356 +302,6 @@ static void update_rw_regs(struct qcom_n
- }
- /*
-- * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
-- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
-- * which will be submitted to DMA engine.
-- */
--static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
--                                     struct dma_chan *chan,
--                                     unsigned long flags)
--{
--      struct desc_info *desc;
--      struct scatterlist *sgl;
--      unsigned int sgl_cnt;
--      int ret;
--      struct bam_transaction *bam_txn = nandc->bam_txn;
--      enum dma_transfer_direction dir_eng;
--      struct dma_async_tx_descriptor *dma_desc;
--
--      desc = kzalloc(sizeof(*desc), GFP_KERNEL);
--      if (!desc)
--              return -ENOMEM;
--
--      if (chan == nandc->cmd_chan) {
--              sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
--              sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
--              bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
--              dir_eng = DMA_MEM_TO_DEV;
--              desc->dir = DMA_TO_DEVICE;
--      } else if (chan == nandc->tx_chan) {
--              sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
--              sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
--              bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
--              dir_eng = DMA_MEM_TO_DEV;
--              desc->dir = DMA_TO_DEVICE;
--      } else {
--              sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
--              sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
--              bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
--              dir_eng = DMA_DEV_TO_MEM;
--              desc->dir = DMA_FROM_DEVICE;
--      }
--
--      sg_mark_end(sgl + sgl_cnt - 1);
--      ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
--      if (ret == 0) {
--              dev_err(nandc->dev, "failure in mapping desc\n");
--              kfree(desc);
--              return -ENOMEM;
--      }
--
--      desc->sgl_cnt = sgl_cnt;
--      desc->bam_sgl = sgl;
--
--      dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
--                                         flags);
--
--      if (!dma_desc) {
--              dev_err(nandc->dev, "failure in prep desc\n");
--              dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
--              kfree(desc);
--              return -EINVAL;
--      }
--
--      desc->dma_desc = dma_desc;
--
--      /* update last data/command descriptor */
--      if (chan == nandc->cmd_chan)
--              bam_txn->last_cmd_desc = dma_desc;
--      else
--              bam_txn->last_data_desc = dma_desc;
--
--      list_add_tail(&desc->node, &nandc->desc_list);
--
--      return 0;
--}
--
--/*
-- * Prepares the command descriptor for BAM DMA which will be used for NAND
-- * register reads and writes. The command descriptor requires the command
-- * to be formed in command element type so this function uses the command
-- * element from bam transaction ce array and fills the same with required
-- * data. A single SGL can contain multiple command elements so
-- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
-- * after the current command element.
-- */
--static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
--                                    int reg_off, const void *vaddr,
--                                    int size, unsigned int flags)
--{
--      int bam_ce_size;
--      int i, ret;
--      struct bam_cmd_element *bam_ce_buffer;
--      struct bam_transaction *bam_txn = nandc->bam_txn;
--
--      bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
--
--      /* fill the command desc */
--      for (i = 0; i < size; i++) {
--              if (read)
--                      bam_prep_ce(&bam_ce_buffer[i],
--                                  nandc_reg_phys(nandc, reg_off + 4 * i),
--                                  BAM_READ_COMMAND,
--                                  reg_buf_dma_addr(nandc,
--                                                   (__le32 *)vaddr + i));
--              else
--                      bam_prep_ce_le32(&bam_ce_buffer[i],
--                                       nandc_reg_phys(nandc, reg_off + 4 * i),
--                                       BAM_WRITE_COMMAND,
--                                       *((__le32 *)vaddr + i));
--      }
--
--      bam_txn->bam_ce_pos += size;
--
--      /* use the separate sgl after this command */
--      if (flags & NAND_BAM_NEXT_SGL) {
--              bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
--              bam_ce_size = (bam_txn->bam_ce_pos -
--                              bam_txn->bam_ce_start) *
--                              sizeof(struct bam_cmd_element);
--              sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
--                         bam_ce_buffer, bam_ce_size);
--              bam_txn->cmd_sgl_pos++;
--              bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
--
--              if (flags & NAND_BAM_NWD) {
--                      ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
--                                                        DMA_PREP_FENCE |
--                                                        DMA_PREP_CMD);
--                      if (ret)
--                              return ret;
--              }
--      }
--
--      return 0;
--}
--
--/*
-- * Prepares the data descriptor for BAM DMA which will be used for NAND
-- * data reads and writes.
-- */
--static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
--                                     const void *vaddr, int size, unsigned int flags)
--{
--      int ret;
--      struct bam_transaction *bam_txn = nandc->bam_txn;
--
--      if (read) {
--              sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
--                         vaddr, size);
--              bam_txn->rx_sgl_pos++;
--      } else {
--              sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
--                         vaddr, size);
--              bam_txn->tx_sgl_pos++;
--
--              /*
--               * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
--               * is not set, form the DMA descriptor
--               */
--              if (!(flags & NAND_BAM_NO_EOT)) {
--                      ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
--                                                        DMA_PREP_INTERRUPT);
--                      if (ret)
--                              return ret;
--              }
--      }
--
--      return 0;
--}
--
--static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
--                                int reg_off, const void *vaddr, int size,
--                                bool flow_control)
--{
--      struct desc_info *desc;
--      struct dma_async_tx_descriptor *dma_desc;
--      struct scatterlist *sgl;
--      struct dma_slave_config slave_conf;
--      struct qcom_adm_peripheral_config periph_conf = {};
--      enum dma_transfer_direction dir_eng;
--      int ret;
--
--      desc = kzalloc(sizeof(*desc), GFP_KERNEL);
--      if (!desc)
--              return -ENOMEM;
--
--      sgl = &desc->adm_sgl;
--
--      sg_init_one(sgl, vaddr, size);
--
--      if (read) {
--              dir_eng = DMA_DEV_TO_MEM;
--              desc->dir = DMA_FROM_DEVICE;
--      } else {
--              dir_eng = DMA_MEM_TO_DEV;
--              desc->dir = DMA_TO_DEVICE;
--      }
--
--      ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
--      if (ret == 0) {
--              ret = -ENOMEM;
--              goto err;
--      }
--
--      memset(&slave_conf, 0x00, sizeof(slave_conf));
--
--      slave_conf.device_fc = flow_control;
--      if (read) {
--              slave_conf.src_maxburst = 16;
--              slave_conf.src_addr = nandc->base_dma + reg_off;
--              if (nandc->data_crci) {
--                      periph_conf.crci = nandc->data_crci;
--                      slave_conf.peripheral_config = &periph_conf;
--                      slave_conf.peripheral_size = sizeof(periph_conf);
--              }
--      } else {
--              slave_conf.dst_maxburst = 16;
--              slave_conf.dst_addr = nandc->base_dma + reg_off;
--              if (nandc->cmd_crci) {
--                      periph_conf.crci = nandc->cmd_crci;
--                      slave_conf.peripheral_config = &periph_conf;
--                      slave_conf.peripheral_size = sizeof(periph_conf);
--              }
--      }
--
--      ret = dmaengine_slave_config(nandc->chan, &slave_conf);
--      if (ret) {
--              dev_err(nandc->dev, "failed to configure dma channel\n");
--              goto err;
--      }
--
--      dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
--      if (!dma_desc) {
--              dev_err(nandc->dev, "failed to prepare desc\n");
--              ret = -EINVAL;
--              goto err;
--      }
--
--      desc->dma_desc = dma_desc;
--
--      list_add_tail(&desc->node, &nandc->desc_list);
--
--      return 0;
--err:
--      kfree(desc);
--
--      return ret;
--}
--
--/*
-- * qcom_read_reg_dma: prepares a descriptor to read a given number of
-- *                    contiguous registers to the reg_read_buf pointer
-- *
-- * @first:            offset of the first register in the contiguous block
-- * @num_regs:         number of registers to read
-- * @flags:            flags to control DMA descriptor preparation
-- */
--static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
--                           int num_regs, unsigned int flags)
--{
--      bool flow_control = false;
--      void *vaddr;
--
--      vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
--      nandc->reg_read_pos += num_regs;
--
--      if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
--              first = dev_cmd_reg_addr(nandc, first);
--
--      if (nandc->props->supports_bam)
--              return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
--                                           num_regs, flags);
--
--      if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
--              flow_control = true;
--
--      return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
--                               num_regs * sizeof(u32), flow_control);
--}
--
--/*
-- * qcom_write_reg_dma:        prepares a descriptor to write a given number of
-- *                    contiguous registers
-- *
-- * @vaddr:            contiguous memory from where register value will
-- *                    be written
-- * @first:            offset of the first register in the contiguous block
-- * @num_regs:         number of registers to write
-- * @flags:            flags to control DMA descriptor preparation
-- */
--static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
--                            int first, int num_regs, unsigned int flags)
--{
--      bool flow_control = false;
--
--      if (first == NAND_EXEC_CMD)
--              flags |= NAND_BAM_NWD;
--
--      if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
--              first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
--
--      if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
--              first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
--
--      if (nandc->props->supports_bam)
--              return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
--                                           num_regs, flags);
--
--      if (first == NAND_FLASH_CMD)
--              flow_control = true;
--
--      return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
--                               num_regs * sizeof(u32), flow_control);
--}
--
--/*
-- * qcom_read_data_dma:        prepares a DMA descriptor to transfer data from the
-- *                    controller's internal buffer to the buffer 'vaddr'
-- *
-- * @reg_off:          offset within the controller's data buffer
-- * @vaddr:            virtual address of the buffer we want to write to
-- * @size:             DMA transaction size in bytes
-- * @flags:            flags to control DMA descriptor preparation
-- */
--static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
--                            const u8 *vaddr, int size, unsigned int flags)
--{
--      if (nandc->props->supports_bam)
--              return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
--
--      return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
--}
--
--/*
-- * qcom_write_data_dma:       prepares a DMA descriptor to transfer data from
-- *                    'vaddr' to the controller's internal buffer
-- *
-- * @reg_off:          offset within the controller's data buffer
-- * @vaddr:            virtual address of the buffer we want to read from
-- * @size:             DMA transaction size in bytes
-- * @flags:            flags to control DMA descriptor preparation
-- */
--static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
--                             const u8 *vaddr, int size, unsigned int flags)
--{
--      if (nandc->props->supports_bam)
--              return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
--
--      return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
--}
--
--/*
-  * Helper to prepare DMA descriptors for configuring registers
-  * before reading a NAND page.
-  */
-@@ -1262,83 +394,6 @@ static void config_nand_cw_write(struct
-                          NAND_BAM_NEXT_SGL);
- }
--/* helpers to submit/free our list of dma descriptors */
--static int qcom_submit_descs(struct qcom_nand_controller *nandc)
--{
--      struct desc_info *desc, *n;
--      dma_cookie_t cookie = 0;
--      struct bam_transaction *bam_txn = nandc->bam_txn;
--      int ret = 0;
--
--      if (nandc->props->supports_bam) {
--              if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
--                      ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
--                      if (ret)
--                              goto err_unmap_free_desc;
--              }
--
--              if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
--                      ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
--                                                        DMA_PREP_INTERRUPT);
--                      if (ret)
--                              goto err_unmap_free_desc;
--              }
--
--              if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
--                      ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
--                                                        DMA_PREP_CMD);
--                      if (ret)
--                              goto err_unmap_free_desc;
--              }
--      }
--
--      list_for_each_entry(desc, &nandc->desc_list, node)
--              cookie = dmaengine_submit(desc->dma_desc);
--
--      if (nandc->props->supports_bam) {
--              bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
--              bam_txn->last_cmd_desc->callback_param = bam_txn;
--
--              dma_async_issue_pending(nandc->tx_chan);
--              dma_async_issue_pending(nandc->rx_chan);
--              dma_async_issue_pending(nandc->cmd_chan);
--
--              if (!wait_for_completion_timeout(&bam_txn->txn_done,
--                                               QPIC_NAND_COMPLETION_TIMEOUT))
--                      ret = -ETIMEDOUT;
--      } else {
--              if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
--                      ret = -ETIMEDOUT;
--      }
--
--err_unmap_free_desc:
--      /*
--       * Unmap the dma sg_list and free the desc allocated by both
--       * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
--       */
--      list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
--              list_del(&desc->node);
--
--              if (nandc->props->supports_bam)
--                      dma_unmap_sg(nandc->dev, desc->bam_sgl,
--                                   desc->sgl_cnt, desc->dir);
--              else
--                      dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
--                                   desc->dir);
--
--              kfree(desc);
--      }
--
--      return ret;
--}
--
--/* reset the register read buffer for next NAND operation */
--static void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
--{
--      nandc->reg_read_pos = 0;
--      qcom_nandc_dev_to_mem(nandc, false);
--}
--
- /*
-  * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
-  * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
-@@ -2967,141 +2022,14 @@ static const struct nand_controller_ops
-       .exec_op = qcom_nand_exec_op,
- };
--static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
--{
--      if (nandc->props->supports_bam) {
--              if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
--                      dma_unmap_single(nandc->dev, nandc->reg_read_dma,
--                                       MAX_REG_RD *
--                                       sizeof(*nandc->reg_read_buf),
--                                       DMA_FROM_DEVICE);
--
--              if (nandc->tx_chan)
--                      dma_release_channel(nandc->tx_chan);
--
--              if (nandc->rx_chan)
--                      dma_release_channel(nandc->rx_chan);
--
--              if (nandc->cmd_chan)
--                      dma_release_channel(nandc->cmd_chan);
--      } else {
--              if (nandc->chan)
--                      dma_release_channel(nandc->chan);
--      }
--}
--
--static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
--{
--      int ret;
--
--      ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
--      if (ret) {
--              dev_err(nandc->dev, "failed to set DMA mask\n");
--              return ret;
--      }
--
--      /*
--       * we use the internal buffer for reading ONFI params, reading small
--       * data like ID and status, and preforming read-copy-write operations
--       * when writing to a codeword partially. 532 is the maximum possible
--       * size of a codeword for our nand controller
--       */
--      nandc->buf_size = 532;
--
--      nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
--      if (!nandc->data_buffer)
--              return -ENOMEM;
--
--      nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
--      if (!nandc->regs)
--              return -ENOMEM;
--
--      nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
--                                         sizeof(*nandc->reg_read_buf),
--                                         GFP_KERNEL);
--      if (!nandc->reg_read_buf)
--              return -ENOMEM;
--
--      if (nandc->props->supports_bam) {
--              nandc->reg_read_dma =
--                      dma_map_single(nandc->dev, nandc->reg_read_buf,
--                                     MAX_REG_RD *
--                                     sizeof(*nandc->reg_read_buf),
--                                     DMA_FROM_DEVICE);
--              if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
--                      dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
--                      return -EIO;
--              }
--
--              nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
--              if (IS_ERR(nandc->tx_chan)) {
--                      ret = PTR_ERR(nandc->tx_chan);
--                      nandc->tx_chan = NULL;
--                      dev_err_probe(nandc->dev, ret,
--                                    "tx DMA channel request failed\n");
--                      goto unalloc;
--              }
--
--              nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
--              if (IS_ERR(nandc->rx_chan)) {
--                      ret = PTR_ERR(nandc->rx_chan);
--                      nandc->rx_chan = NULL;
--                      dev_err_probe(nandc->dev, ret,
--                                    "rx DMA channel request failed\n");
--                      goto unalloc;
--              }
--
--              nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
--              if (IS_ERR(nandc->cmd_chan)) {
--                      ret = PTR_ERR(nandc->cmd_chan);
--                      nandc->cmd_chan = NULL;
--                      dev_err_probe(nandc->dev, ret,
--                                    "cmd DMA channel request failed\n");
--                      goto unalloc;
--              }
--
--              /*
--               * Initially allocate BAM transaction to read ONFI param page.
--               * After detecting all the devices, this BAM transaction will
--               * be freed and the next BAM transaction will be allocated with
--               * maximum codeword size
--               */
--              nandc->max_cwperpage = 1;
--              nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
--              if (!nandc->bam_txn) {
--                      dev_err(nandc->dev,
--                              "failed to allocate bam transaction\n");
--                      ret = -ENOMEM;
--                      goto unalloc;
--              }
--      } else {
--              nandc->chan = dma_request_chan(nandc->dev, "rxtx");
--              if (IS_ERR(nandc->chan)) {
--                      ret = PTR_ERR(nandc->chan);
--                      nandc->chan = NULL;
--                      dev_err_probe(nandc->dev, ret,
--                                    "rxtx DMA channel request failed\n");
--                      return ret;
--              }
--      }
--
--      INIT_LIST_HEAD(&nandc->desc_list);
--      INIT_LIST_HEAD(&nandc->host_list);
--
--      nand_controller_init(&nandc->controller);
--      nandc->controller.ops = &qcom_nandc_ops;
--
--      return 0;
--unalloc:
--      qcom_nandc_unalloc(nandc);
--      return ret;
--}
--
- /* one time setup of a few nand controller registers */
- static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
- {
-       u32 nand_ctrl;
-+      nand_controller_init(nandc->controller);
-+      nandc->controller->ops = &qcom_nandc_ops;
-+
-       /* kill onenand */
-       if (!nandc->props->nandc_part_of_qpic)
-               nandc_write(nandc, SFLASHC_BURST_CFG, 0);
-@@ -3240,7 +2168,7 @@ static int qcom_nand_host_init_and_regis
-       chip->legacy.block_bad          = qcom_nandc_block_bad;
-       chip->legacy.block_markbad      = qcom_nandc_block_markbad;
--      chip->controller = &nandc->controller;
-+      chip->controller = nandc->controller;
-       chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA |
-                        NAND_SKIP_BBTSCAN;
-@@ -3323,17 +2251,21 @@ static int qcom_nandc_parse_dt(struct pl
- static int qcom_nandc_probe(struct platform_device *pdev)
- {
-       struct qcom_nand_controller *nandc;
-+      struct nand_controller *controller;
-       const void *dev_data;
-       struct device *dev = &pdev->dev;
-       struct resource *res;
-       int ret;
--      nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
-+      nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc) + sizeof(*controller),
-+                           GFP_KERNEL);
-       if (!nandc)
-               return -ENOMEM;
-+      controller = (struct nand_controller *)&nandc[1];
-       platform_set_drvdata(pdev, nandc);
-       nandc->dev = dev;
-+      nandc->controller = controller;
-       dev_data = of_device_get_match_data(dev);
-       if (!dev_data) {
---- /dev/null
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -0,0 +1,468 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * QCOM QPIC common APIs header file
-+ *
-+ * Copyright (c) 2023 Qualcomm Inc.
-+ * Authors:   Md sadre Alam   <[email protected]>
-+ *
-+ */
-+#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 (file)
index b375074..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-From 0c08080fd71cd5dd59643104b39d3c89d793ab3c Mon Sep 17 00:00:00 2001
-From: Md Sadre Alam <[email protected]>
-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 <[email protected]>
-Signed-off-by: Md Sadre Alam <[email protected]>
-Signed-off-by: Miquel Raynal <[email protected]>
----
- 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 (file)
index a6a4db2..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-From 9d4ffbcfde283f2a87ea45128ddf7e6651facdd9 Mon Sep 17 00:00:00 2001
-From: Christian Marangi <[email protected]>
-Date: Fri, 7 Feb 2025 20:42:38 +0100
-Subject: [PATCH] mtd: rawnand: qcom: fix broken config in
- qcom_param_page_type_exec
-
-Fix broken config in qcom_param_page_type_exec caused by copy-paste error
-from commit 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
-
-In qcom_param_page_type_exec the value needs to be set to
-nandc->regs->cfg0 instead of host->cfg0. This wrong configuration caused
-the Qcom NANDC driver to malfunction on any device that makes use of it
-(IPQ806x, IPQ40xx, IPQ807x, IPQ60xx) with the following error:
-
-[    0.885369] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xaa
-[    0.885909] nand: Micron NAND 256MiB 1,8V 8-bit
-[    0.892499] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
-[    0.896823] nand: ECC (step, strength) = (512, 8) does not fit in OOB
-[    0.896836] qcom-nandc 79b0000.nand-controller: No valid ECC settings possible
-[    0.910996] bam-dma-engine 7984000.dma-controller: Cannot free busy channel
-[    0.918070] qcom-nandc: probe of 79b0000.nand-controller failed with error -28
-
-Restore original configuration fix the problem and makes the driver work
-again.
-
-Fixes: 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
-Signed-off-by: Christian Marangi <[email protected]>
----
- 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 (file)
index 67beed3..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-From b9371866799d67a80be0ea9e01bd41987db22f26 Mon Sep 17 00:00:00 2001
-From: Md Sadre Alam <[email protected]>
-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 <[email protected]>
-Signed-off-by: Miquel Raynal <[email protected]>
----
- 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 (file)
index 310d902..0000000
+++ /dev/null
@@ -1,1737 +0,0 @@
-From 7304d1909080ef0c9da703500a97f46c98393fcd Mon Sep 17 00:00:00 2001
-From: Md Sadre Alam <[email protected]>
-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 <[email protected]>
-Signed-off-by: Sricharan Ramabadhran <[email protected]>
-Co-developed-by: Varadarajan Narayanan <[email protected]>
-Signed-off-by: Varadarajan Narayanan <[email protected]>
-Signed-off-by: Md Sadre Alam <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Mark Brown <[email protected]>
----
- 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 <[email protected]>
-+ *    Sricharan R <[email protected]>
-+ *    Varadarajan Narayanan <[email protected]>
-+ */
-+#include <linux/bitops.h>
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/dmaengine.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma/qcom_adm.h>
-+#include <linux/dma/qcom_bam_dma.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/nand-qpic-common.h>
-+#include <linux/mtd/spinand.h>
-+#include <linux/bitfield.h>
-+
-+#define NAND_FLASH_SPI_CFG            0xc0
-+#define NAND_NUM_ADDR_CYCLES          0xc4
-+#define NAND_BUSY_CHECK_WAIT_CNT      0xc8
-+#define NAND_FLASH_FEATURES           0xf64
-+
-+/* QSPI NAND config reg bits */
-+#define LOAD_CLK_CNTR_INIT_EN         BIT(28)
-+#define CLK_CNTR_INIT_VAL_VEC         0x924
-+#define CLK_CNTR_INIT_VAL_VEC_MASK    GENMASK(27, 16)
-+#define FEA_STATUS_DEV_ADDR           0xc0
-+#define FEA_STATUS_DEV_ADDR_MASK      GENMASK(15, 8)
-+#define SPI_CFG                               BIT(0)
-+#define SPI_NUM_ADDR                  0xDA4DB
-+#define SPI_WAIT_CNT                  0x10
-+#define QPIC_QSPI_NUM_CS              1
-+#define SPI_TRANSFER_MODE_x1          BIT(29)
-+#define SPI_TRANSFER_MODE_x4          (3 << 29)
-+#define SPI_WP                                BIT(28)
-+#define SPI_HOLD                      BIT(27)
-+#define QPIC_SET_FEATURE              BIT(31)
-+
-+#define SPINAND_RESET                 0xff
-+#define SPINAND_READID                        0x9f
-+#define SPINAND_GET_FEATURE           0x0f
-+#define SPINAND_SET_FEATURE           0x1f
-+#define SPINAND_READ                  0x13
-+#define SPINAND_ERASE                 0xd8
-+#define SPINAND_WRITE_EN              0x06
-+#define SPINAND_PROGRAM_EXECUTE               0x10
-+#define SPINAND_PROGRAM_LOAD          0x84
-+
-+#define ACC_FEATURE                   0xe
-+#define BAD_BLOCK_MARKER_SIZE         0x2
-+#define OOB_BUF_SIZE                  128
-+#define ecceng_to_qspi(eng)           container_of(eng, struct qpic_spi_nand, ecc_eng)
-+
-+struct qpic_snand_op {
-+      u32 cmd_reg;
-+      u32 addr1_reg;
-+      u32 addr2_reg;
-+};
-+
-+struct snandc_read_status {
-+      __le32 snandc_flash;
-+      __le32 snandc_buffer;
-+      __le32 snandc_erased_cw;
-+};
-+
-+/*
-+ * ECC state struct
-+ * @corrected:                ECC corrected
-+ * @bitflips:         Max bit flip
-+ * @failed:           ECC failed
-+ */
-+struct qcom_ecc_stats {
-+      u32 corrected;
-+      u32 bitflips;
-+      u32 failed;
-+};
-+
-+struct qpic_ecc {
-+      struct device *dev;
-+      int ecc_bytes_hw;
-+      int spare_bytes;
-+      int bbm_size;
-+      int ecc_mode;
-+      int bytes;
-+      int steps;
-+      int step_size;
-+      int strength;
-+      int cw_size;
-+      int cw_data;
-+      u32 cfg0;
-+      u32 cfg1;
-+      u32 cfg0_raw;
-+      u32 cfg1_raw;
-+      u32 ecc_buf_cfg;
-+      u32 ecc_bch_cfg;
-+      u32 clrflashstatus;
-+      u32 clrreadstatus;
-+      bool bch_enabled;
-+};
-+
-+struct qpic_spi_nand {
-+      struct qcom_nand_controller *snandc;
-+      struct spi_controller *ctlr;
-+      struct mtd_info *mtd;
-+      struct clk *iomacro_clk;
-+      struct qpic_ecc *ecc;
-+      struct qcom_ecc_stats ecc_stats;
-+      struct nand_ecc_engine ecc_eng;
-+      u8 *data_buf;
-+      u8 *oob_buf;
-+      u32 wlen;
-+      __le32 addr1;
-+      __le32 addr2;
-+      __le32 cmd;
-+      u32 num_cw;
-+      bool oob_rw;
-+      bool page_rw;
-+      bool raw_rw;
-+};
-+
-+static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc,
-+                                      int reg, int cw_offset, int read_size,
-+                                      int is_last_read_loc)
-+{
-+      __le32 locreg_val;
-+      u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+                ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
-+                << READ_LOCATION_LAST));
-+
-+      locreg_val = cpu_to_le32(val);
-+
-+      if (reg == NAND_READ_LOCATION_0)
-+              snandc->regs->read_location0 = locreg_val;
-+      else if (reg == NAND_READ_LOCATION_1)
-+              snandc->regs->read_location1 = locreg_val;
-+      else if (reg == NAND_READ_LOCATION_2)
-+              snandc->regs->read_location1 = locreg_val;
-+      else if (reg == NAND_READ_LOCATION_3)
-+              snandc->regs->read_location3 = locreg_val;
-+}
-+
-+static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc,
-+                                     int reg, int cw_offset, int read_size,
-+                                     int is_last_read_loc)
-+{
-+      __le32 locreg_val;
-+      u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+                ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
-+                << READ_LOCATION_LAST));
-+
-+      locreg_val = cpu_to_le32(val);
-+
-+      if (reg == NAND_READ_LOCATION_LAST_CW_0)
-+              snandc->regs->read_location_last0 = locreg_val;
-+      else if (reg == NAND_READ_LOCATION_LAST_CW_1)
-+              snandc->regs->read_location_last1 = locreg_val;
-+      else if (reg == NAND_READ_LOCATION_LAST_CW_2)
-+              snandc->regs->read_location_last2 = locreg_val;
-+      else if (reg == NAND_READ_LOCATION_LAST_CW_3)
-+              snandc->regs->read_location_last3 = locreg_val;
-+}
-+
-+static struct qcom_nand_controller *nand_to_qcom_snand(struct nand_device *nand)
-+{
-+      struct nand_ecc_engine *eng = nand->ecc.engine;
-+      struct qpic_spi_nand *qspi = ecceng_to_qspi(eng);
-+
-+      return qspi->snandc;
-+}
-+
-+static int qcom_spi_init(struct qcom_nand_controller *snandc)
-+{
-+      u32 snand_cfg_val = 0x0;
-+      int ret;
-+
-+      snand_cfg_val = FIELD_PREP(CLK_CNTR_INIT_VAL_VEC_MASK, CLK_CNTR_INIT_VAL_VEC) |
-+                      FIELD_PREP(LOAD_CLK_CNTR_INIT_EN, 0) |
-+                      FIELD_PREP(FEA_STATUS_DEV_ADDR_MASK, FEA_STATUS_DEV_ADDR) |
-+                      FIELD_PREP(SPI_CFG, 0);
-+
-+      snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
-+      snandc->regs->num_addr_cycle = cpu_to_le32(SPI_NUM_ADDR);
-+      snandc->regs->busy_wait_cnt = cpu_to_le32(SPI_WAIT_CNT);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
-+
-+      snand_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN;
-+      snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->num_addr_cycle, NAND_NUM_ADDR_CYCLES, 1, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->busy_wait_cnt, NAND_BUSY_CHECK_WAIT_CNT, 1,
-+                         NAND_BAM_NEXT_SGL);
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret) {
-+              dev_err(snandc->dev, "failure in submitting spi init descriptor\n");
-+              return ret;
-+      }
-+
-+      return ret;
-+}
-+
-+static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section,
-+                                struct mtd_oob_region *oobregion)
-+{
-+      struct nand_device *nand = mtd_to_nanddev(mtd);
-+      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+      struct qpic_ecc *qecc = snandc->qspi->ecc;
-+
-+      if (section > 1)
-+              return -ERANGE;
-+
-+      oobregion->length = qecc->ecc_bytes_hw + qecc->spare_bytes;
-+      oobregion->offset = mtd->oobsize - oobregion->length;
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section,
-+                                 struct mtd_oob_region *oobregion)
-+{
-+      struct nand_device *nand = mtd_to_nanddev(mtd);
-+      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+      struct qpic_ecc *qecc = snandc->qspi->ecc;
-+
-+      if (section)
-+              return -ERANGE;
-+
-+      oobregion->length = qecc->steps * 4;
-+      oobregion->offset = ((qecc->steps - 1) * qecc->bytes) + qecc->bbm_size;
-+
-+      return 0;
-+}
-+
-+static const struct mtd_ooblayout_ops qcom_spi_ooblayout = {
-+      .ecc = qcom_spi_ooblayout_ecc,
-+      .free = qcom_spi_ooblayout_free,
-+};
-+
-+static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
-+{
-+      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+      struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
-+      struct mtd_info *mtd = nanddev_to_mtd(nand);
-+      int cwperpage, bad_block_byte;
-+      struct qpic_ecc *ecc_cfg;
-+
-+      cwperpage = mtd->writesize / NANDC_STEP_SIZE;
-+      snandc->qspi->num_cw = cwperpage;
-+
-+      ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
-+      if (!ecc_cfg)
-+              return -ENOMEM;
-+      snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
-+                                      GFP_KERNEL);
-+      if (!snandc->qspi->oob_buf)
-+              return -ENOMEM;
-+
-+      memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
-+
-+      nand->ecc.ctx.priv = ecc_cfg;
-+      snandc->qspi->mtd = mtd;
-+
-+      ecc_cfg->ecc_bytes_hw = 7;
-+      ecc_cfg->spare_bytes = 4;
-+      ecc_cfg->bbm_size = 1;
-+      ecc_cfg->bch_enabled = true;
-+      ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
-+
-+      ecc_cfg->steps = 4;
-+      ecc_cfg->strength = 4;
-+      ecc_cfg->step_size = 512;
-+      ecc_cfg->cw_data = 516;
-+      ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
-+      bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;
-+
-+      mtd_set_ooblayout(mtd, &qcom_spi_ooblayout);
-+
-+      ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+                      FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) |
-+                      FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) |
-+                      FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
-+                      FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, ecc_cfg->ecc_bytes_hw) |
-+                      FIELD_PREP(STATUS_BFR_READ, 0) |
-+                      FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) |
-+                      FIELD_PREP(SPARE_SIZE_BYTES_MASK, ecc_cfg->spare_bytes);
-+
-+      ecc_cfg->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
-+                      FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+                      FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) |
-+                      FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) |
-+                      FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
-+                      FIELD_PREP(WIDE_FLASH, 0) |
-+                      FIELD_PREP(ENABLE_BCH_ECC, ecc_cfg->bch_enabled);
-+
-+      ecc_cfg->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+                          FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
-+                          FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_size) |
-+                          FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-+
-+      ecc_cfg->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
-+                          FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+                          FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-+                          FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-+                          FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
-+                          FIELD_PREP(WIDE_FLASH, 0) |
-+                          FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-+
-+      ecc_cfg->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !ecc_cfg->bch_enabled) |
-+                             FIELD_PREP(ECC_SW_RESET, 0) |
-+                             FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
-+                             FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
-+                             FIELD_PREP(ECC_MODE_MASK, 0) |
-+                             FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
-+
-+      ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
-+      ecc_cfg->clrflashstatus = FS_READY_BSY_N;
-+      ecc_cfg->clrreadstatus = 0xc0;
-+
-+      conf->step_size = ecc_cfg->step_size;
-+      conf->strength = ecc_cfg->strength;
-+
-+      snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET);
-+      snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET);
-+
-+      dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n",
-+              ecc_cfg->strength, ecc_cfg->step_size);
-+
-+      return 0;
-+}
-+
-+static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand)
-+{
-+      struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
-+
-+      kfree(ecc_cfg);
-+}
-+
-+static int qcom_spi_ecc_prepare_io_req_pipelined(struct nand_device *nand,
-+                                               struct nand_page_io_req *req)
-+{
-+      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+      struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
-+
-+      snandc->qspi->ecc = ecc_cfg;
-+      snandc->qspi->raw_rw = false;
-+      snandc->qspi->oob_rw = false;
-+      snandc->qspi->page_rw = false;
-+
-+      if (req->datalen)
-+              snandc->qspi->page_rw = true;
-+
-+      if (req->ooblen)
-+              snandc->qspi->oob_rw = true;
-+
-+      if (req->mode == MTD_OPS_RAW)
-+              snandc->qspi->raw_rw = true;
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_ecc_finish_io_req_pipelined(struct nand_device *nand,
-+                                              struct nand_page_io_req *req)
-+{
-+      struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+      struct mtd_info *mtd = nanddev_to_mtd(nand);
-+
-+      if (req->mode == MTD_OPS_RAW || req->type != NAND_PAGE_READ)
-+              return 0;
-+
-+      if (snandc->qspi->ecc_stats.failed)
-+              mtd->ecc_stats.failed += snandc->qspi->ecc_stats.failed;
-+      else
-+              mtd->ecc_stats.corrected += snandc->qspi->ecc_stats.corrected;
-+
-+      if (snandc->qspi->ecc_stats.failed)
-+              return -EBADMSG;
-+      else
-+              return snandc->qspi->ecc_stats.bitflips;
-+}
-+
-+static struct nand_ecc_engine_ops qcom_spi_ecc_engine_ops_pipelined = {
-+      .init_ctx = qcom_spi_ecc_init_ctx_pipelined,
-+      .cleanup_ctx = qcom_spi_ecc_cleanup_ctx_pipelined,
-+      .prepare_io_req = qcom_spi_ecc_prepare_io_req_pipelined,
-+      .finish_io_req = qcom_spi_ecc_finish_io_req_pipelined,
-+};
-+
-+/* helper to configure location register values */
-+static void qcom_spi_set_read_loc(struct qcom_nand_controller *snandc, int cw, int reg,
-+                                int cw_offset, int read_size, int is_last_read_loc)
-+{
-+      int reg_base = NAND_READ_LOCATION_0;
-+      int num_cw = snandc->qspi->num_cw;
-+
-+      if (cw == (num_cw - 1))
-+              reg_base = NAND_READ_LOCATION_LAST_CW_0;
-+
-+      reg_base += reg * 4;
-+
-+      if (cw == (num_cw - 1))
-+              return qcom_spi_set_read_loc_last(snandc, reg_base, cw_offset,
-+                                                read_size, is_last_read_loc);
-+      else
-+              return qcom_spi_set_read_loc_first(snandc, reg_base, cw_offset,
-+                                                 read_size, is_last_read_loc);
-+}
-+
-+static void
-+qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int cw)
-+{
-+      __le32 *reg = &snandc->regs->read_location0;
-+      int num_cw = snandc->qspi->num_cw;
-+
-+      qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
-+      if (cw == (num_cw - 1)) {
-+              reg = &snandc->regs->read_location_last0;
-+              qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4,
-+                                 NAND_BAM_NEXT_SGL);
-+      }
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+      qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0);
-+      qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-+                        NAND_BAM_NEXT_SGL);
-+}
-+
-+static int qcom_spi_block_erase(struct qcom_nand_controller *snandc)
-+{
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      int ret;
-+
-+      snandc->buf_count = 0;
-+      snandc->buf_start = 0;
-+      qcom_clear_read_regs(snandc);
-+      qcom_clear_bam_transaction(snandc);
-+
-+      snandc->regs->cmd = snandc->qspi->cmd;
-+      snandc->regs->addr0 = snandc->qspi->addr1;
-+      snandc->regs->addr1 = snandc->qspi->addr2;
-+      snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE));
-+      snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw);
-+      snandc->regs->exec = cpu_to_le32(1);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
-+      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-+      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret) {
-+              dev_err(snandc->dev, "failure to erase block\n");
-+              return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *snandc,
-+                                              bool use_ecc, int cw)
-+{
-+      __le32 *reg = &snandc->regs->read_location0;
-+      int num_cw = snandc->qspi->num_cw;
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+                         NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+                         NAND_ERASED_CW_DETECT_CFG, 1,
-+                         NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+      if (cw == (num_cw - 1)) {
-+              reg = &snandc->regs->read_location_last0;
-+              qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, NAND_BAM_NEXT_SGL);
-+      }
-+      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+      qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0);
-+}
-+
-+static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc,
-+                               const struct spi_mem_op *op)
-+{
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      struct mtd_info *mtd = snandc->qspi->mtd;
-+      int size, ret = 0;
-+      int col,  bbpos;
-+      u32 cfg0, cfg1, ecc_bch_cfg;
-+      u32 num_cw = snandc->qspi->num_cw;
-+
-+      qcom_clear_bam_transaction(snandc);
-+      qcom_clear_read_regs(snandc);
-+
-+      size = ecc_cfg->cw_size;
-+      col = ecc_cfg->cw_size * (num_cw - 1);
-+
-+      memset(snandc->data_buffer, 0xff, size);
-+      snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
-+      snandc->regs->addr1 = snandc->qspi->addr2;
-+
-+      cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+              0 << CW_PER_PAGE;
-+      cfg1 = ecc_cfg->cfg1_raw;
-+      ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-+
-+      snandc->regs->cmd = snandc->qspi->cmd;
-+      snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+      snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+      snandc->regs->exec = cpu_to_le32(1);
-+
-+      qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1);
-+
-+      qcom_spi_config_single_cw_page_read(snandc, false, num_cw - 1);
-+
-+      qcom_read_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, size, 0);
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret) {
-+              dev_err(snandc->dev, "failed to read last cw\n");
-+              return ret;
-+      }
-+
-+      qcom_nandc_dev_to_mem(snandc, true);
-+      u32 flash = le32_to_cpu(snandc->reg_read_buf[0]);
-+
-+      if (flash & (FS_OP_ERR | FS_MPU_ERR))
-+              return -EIO;
-+
-+      bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
-+
-+      if (snandc->data_buffer[bbpos] == 0xff)
-+              snandc->data_buffer[bbpos + 1] = 0xff;
-+      if (snandc->data_buffer[bbpos] != 0xff)
-+              snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos];
-+
-+      memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes);
-+
-+      return ret;
-+}
-+
-+static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf)
-+{
-+      struct snandc_read_status *buf;
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      int i, num_cw = snandc->qspi->num_cw;
-+      bool flash_op_err = false, erased;
-+      unsigned int max_bitflips = 0;
-+      unsigned int uncorrectable_cws = 0;
-+
-+      snandc->qspi->ecc_stats.failed = 0;
-+      snandc->qspi->ecc_stats.corrected = 0;
-+
-+      qcom_nandc_dev_to_mem(snandc, true);
-+      buf = (struct snandc_read_status *)snandc->reg_read_buf;
-+
-+      for (i = 0; i < num_cw; i++, buf++) {
-+              u32 flash, buffer, erased_cw;
-+              int data_len, oob_len;
-+
-+              if (i == (num_cw - 1)) {
-+                      data_len = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+                      oob_len = num_cw << 2;
-+              } else {
-+                      data_len = ecc_cfg->cw_data;
-+                      oob_len = 0;
-+              }
-+
-+              flash = le32_to_cpu(buf->snandc_flash);
-+              buffer = le32_to_cpu(buf->snandc_buffer);
-+              erased_cw = le32_to_cpu(buf->snandc_erased_cw);
-+
-+              if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
-+                      if (ecc_cfg->bch_enabled)
-+                              erased = (erased_cw & ERASED_CW) == ERASED_CW;
-+                      else
-+                              erased = false;
-+
-+                      if (!erased)
-+                              uncorrectable_cws |= BIT(i);
-+
-+              } else if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
-+                      flash_op_err = true;
-+              } else {
-+                      unsigned int stat;
-+
-+                      stat = buffer & BS_CORRECTABLE_ERR_MSK;
-+                      snandc->qspi->ecc_stats.corrected += stat;
-+                      max_bitflips = max(max_bitflips, stat);
-+              }
-+
-+              if (data_buf)
-+                      data_buf += data_len;
-+              if (oob_buf)
-+                      oob_buf += oob_len + ecc_cfg->bytes;
-+      }
-+
-+      if (flash_op_err)
-+              return -EIO;
-+
-+      if (!uncorrectable_cws)
-+              snandc->qspi->ecc_stats.bitflips = max_bitflips;
-+      else
-+              snandc->qspi->ecc_stats.failed++;
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt)
-+{
-+      int i;
-+
-+      qcom_nandc_dev_to_mem(snandc, true);
-+
-+      for (i = 0; i < cw_cnt; i++) {
-+              u32 flash = le32_to_cpu(snandc->reg_read_buf[i]);
-+
-+              if (flash & (FS_OP_ERR | FS_MPU_ERR))
-+                      return -EIO;
-+      }
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf,
-+                              u8 *oob_buf, int cw)
-+{
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      struct mtd_info *mtd = snandc->qspi->mtd;
-+      int data_size1, data_size2, oob_size1, oob_size2;
-+      int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
-+      int raw_cw = cw;
-+      u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
-+      int col;
-+
-+      snandc->buf_count = 0;
-+      snandc->buf_start = 0;
-+      qcom_clear_read_regs(snandc);
-+      qcom_clear_bam_transaction(snandc);
-+      raw_cw = num_cw - 1;
-+
-+      cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+                              0 << CW_PER_PAGE;
-+      cfg1 = ecc_cfg->cfg1_raw;
-+      ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
-+
-+      col = ecc_cfg->cw_size * cw;
-+
-+      snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
-+      snandc->regs->addr1 = snandc->qspi->addr2;
-+      snandc->regs->cmd = snandc->qspi->cmd;
-+      snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+      snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+      snandc->regs->exec = cpu_to_le32(1);
-+
-+      qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+                         NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+                         NAND_ERASED_CW_DETECT_CFG, 1,
-+                         NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+      data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
-+      oob_size1 = ecc_cfg->bbm_size;
-+
-+      if (cw == (num_cw - 1)) {
-+              data_size2 = NANDC_STEP_SIZE - data_size1 -
-+                           ((num_cw - 1) * 4);
-+              oob_size2 = (num_cw * 4) + ecc_cfg->ecc_bytes_hw +
-+                          ecc_cfg->spare_bytes;
-+      } else {
-+              data_size2 = ecc_cfg->cw_data - data_size1;
-+              oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+      }
-+
-+      qcom_spi_set_read_loc(snandc, cw, 0, read_loc, data_size1, 0);
-+      read_loc += data_size1;
-+
-+      qcom_spi_set_read_loc(snandc, cw, 1, read_loc, oob_size1, 0);
-+      read_loc += oob_size1;
-+
-+      qcom_spi_set_read_loc(snandc, cw, 2, read_loc, data_size2, 0);
-+      read_loc += data_size2;
-+
-+      qcom_spi_set_read_loc(snandc, cw, 3, read_loc, oob_size2, 1);
-+
-+      qcom_spi_config_cw_read(snandc, false, raw_cw);
-+
-+      qcom_read_data_dma(snandc, reg_off, data_buf, data_size1, 0);
-+      reg_off += data_size1;
-+
-+      qcom_read_data_dma(snandc, reg_off, oob_buf, oob_size1, 0);
-+      reg_off += oob_size1;
-+
-+      qcom_read_data_dma(snandc, reg_off, data_buf + data_size1, data_size2, 0);
-+      reg_off += data_size2;
-+
-+      qcom_read_data_dma(snandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret) {
-+              dev_err(snandc->dev, "failure to read raw cw %d\n", cw);
-+              return ret;
-+      }
-+
-+      return qcom_spi_check_raw_flash_errors(snandc, 1);
-+}
-+
-+static int qcom_spi_read_page_raw(struct qcom_nand_controller *snandc,
-+                                const struct spi_mem_op *op)
-+{
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      u8 *data_buf = NULL, *oob_buf = NULL;
-+      int ret, cw;
-+      u32 num_cw = snandc->qspi->num_cw;
-+
-+      if (snandc->qspi->page_rw)
-+              data_buf = op->data.buf.in;
-+
-+      oob_buf = snandc->qspi->oob_buf;
-+      memset(oob_buf, 0xff, OOB_BUF_SIZE);
-+
-+      for (cw = 0; cw < num_cw; cw++) {
-+              ret = qcom_spi_read_cw_raw(snandc, data_buf, oob_buf, cw);
-+              if (ret)
-+                      return ret;
-+
-+              if (data_buf)
-+                      data_buf += ecc_cfg->cw_data;
-+              if (oob_buf)
-+                      oob_buf += ecc_cfg->bytes;
-+      }
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc,
-+                                const struct spi_mem_op *op)
-+{
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
-+      int ret, i;
-+      u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
-+
-+      data_buf = op->data.buf.in;
-+      data_buf_start = data_buf;
-+
-+      oob_buf = snandc->qspi->oob_buf;
-+      oob_buf_start = oob_buf;
-+
-+      snandc->buf_count = 0;
-+      snandc->buf_start = 0;
-+      qcom_clear_read_regs(snandc);
-+
-+      cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+                              (num_cw - 1) << CW_PER_PAGE;
-+      cfg1 = ecc_cfg->cfg1;
-+      ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+
-+      snandc->regs->addr0 = snandc->qspi->addr1;
-+      snandc->regs->addr1 = snandc->qspi->addr2;
-+      snandc->regs->cmd = snandc->qspi->cmd;
-+      snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+      snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+      snandc->regs->exec = cpu_to_le32(1);
-+
-+      qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
-+
-+      qcom_clear_bam_transaction(snandc);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+                         NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+                         NAND_ERASED_CW_DETECT_CFG, 1,
-+                         NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+      for (i = 0; i < num_cw; i++) {
-+              int data_size, oob_size;
-+
-+              if (i == (num_cw - 1)) {
-+                      data_size = 512 - ((num_cw - 1) << 2);
-+                      oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+                                  ecc_cfg->spare_bytes;
-+              } else {
-+                      data_size = ecc_cfg->cw_data;
-+                      oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+              }
-+
-+              if (data_buf && oob_buf) {
-+                      qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 0);
-+                      qcom_spi_set_read_loc(snandc, i, 1, data_size, oob_size, 1);
-+              } else if (data_buf) {
-+                      qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 1);
-+              } else {
-+                      qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
-+              }
-+
-+              qcom_spi_config_cw_read(snandc, true, i);
-+
-+              if (data_buf)
-+                      qcom_read_data_dma(snandc, FLASH_BUF_ACC, data_buf,
-+                                         data_size, 0);
-+              if (oob_buf) {
-+                      int j;
-+
-+                      for (j = 0; j < ecc_cfg->bbm_size; j++)
-+                              *oob_buf++ = 0xff;
-+
-+                      qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
-+                                         oob_buf, oob_size, 0);
-+              }
-+
-+              if (data_buf)
-+                      data_buf += data_size;
-+              if (oob_buf)
-+                      oob_buf += oob_size;
-+      }
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret) {
-+              dev_err(snandc->dev, "failure to read page\n");
-+              return ret;
-+      }
-+
-+      return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
-+}
-+
-+static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc,
-+                                const struct spi_mem_op *op)
-+{
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
-+      int ret, i;
-+      u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
-+
-+      oob_buf = op->data.buf.in;
-+      oob_buf_start = oob_buf;
-+
-+      data_buf_start = data_buf;
-+
-+      snandc->buf_count = 0;
-+      snandc->buf_start = 0;
-+      qcom_clear_read_regs(snandc);
-+      qcom_clear_bam_transaction(snandc);
-+
-+      cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+                              (num_cw - 1) << CW_PER_PAGE;
-+      cfg1 = ecc_cfg->cfg1;
-+      ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+
-+      snandc->regs->addr0 = snandc->qspi->addr1;
-+      snandc->regs->addr1 = snandc->qspi->addr2;
-+      snandc->regs->cmd = snandc->qspi->cmd;
-+      snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+      snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+      snandc->regs->exec = cpu_to_le32(1);
-+
-+      qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+                         NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+                         NAND_ERASED_CW_DETECT_CFG, 1,
-+                         NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+      for (i = 0; i < num_cw; i++) {
-+              int data_size, oob_size;
-+
-+              if (i == (num_cw - 1)) {
-+                      data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+                      oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+                                  ecc_cfg->spare_bytes;
-+              } else {
-+                      data_size = ecc_cfg->cw_data;
-+                      oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+              }
-+
-+              qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
-+
-+              qcom_spi_config_cw_read(snandc, true, i);
-+
-+              if (oob_buf) {
-+                      int j;
-+
-+                      for (j = 0; j < ecc_cfg->bbm_size; j++)
-+                              *oob_buf++ = 0xff;
-+
-+                      qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
-+                                         oob_buf, oob_size, 0);
-+              }
-+
-+              if (oob_buf)
-+                      oob_buf += oob_size;
-+      }
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret) {
-+              dev_err(snandc->dev, "failure to read oob\n");
-+              return ret;
-+      }
-+
-+      return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
-+}
-+
-+static int qcom_spi_read_page(struct qcom_nand_controller *snandc,
-+                            const struct spi_mem_op *op)
-+{
-+      if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
-+              return qcom_spi_read_page_raw(snandc, op);
-+
-+      if (snandc->qspi->page_rw)
-+              return qcom_spi_read_page_ecc(snandc, op);
-+
-+      if (snandc->qspi->oob_rw && snandc->qspi->raw_rw)
-+              return qcom_spi_read_last_cw(snandc, op);
-+
-+      if (snandc->qspi->oob_rw)
-+              return qcom_spi_read_page_oob(snandc, op);
-+
-+      return 0;
-+}
-+
-+static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc)
-+{
-+      qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG,
-+                         1, NAND_BAM_NEXT_SGL);
-+}
-+
-+static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc)
-+{
-+      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+      qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
-+      qcom_write_reg_dma(snandc, &snandc->regs->clrreadstatus, NAND_READ_STATUS, 1,
-+                         NAND_BAM_NEXT_SGL);
-+}
-+
-+static int qcom_spi_program_raw(struct qcom_nand_controller *snandc,
-+                              const struct spi_mem_op *op)
-+{
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      struct mtd_info *mtd = snandc->qspi->mtd;
-+      u8 *data_buf = NULL, *oob_buf = NULL;
-+      int i, ret;
-+      int num_cw = snandc->qspi->num_cw;
-+      u32 cfg0, cfg1, ecc_bch_cfg;
-+
-+      cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+                      (num_cw - 1) << CW_PER_PAGE;
-+      cfg1 = ecc_cfg->cfg1_raw;
-+      ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
-+
-+      data_buf = snandc->qspi->data_buf;
-+
-+      oob_buf = snandc->qspi->oob_buf;
-+      memset(oob_buf, 0xff, OOB_BUF_SIZE);
-+
-+      snandc->buf_count = 0;
-+      snandc->buf_start = 0;
-+      qcom_clear_read_regs(snandc);
-+      qcom_clear_bam_transaction(snandc);
-+
-+      snandc->regs->addr0 = snandc->qspi->addr1;
-+      snandc->regs->addr1 = snandc->qspi->addr2;
-+      snandc->regs->cmd = snandc->qspi->cmd;
-+      snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+      snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+      snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+      snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+      snandc->regs->exec = cpu_to_le32(1);
-+
-+      qcom_spi_config_page_write(snandc);
-+
-+      for (i = 0; i < num_cw; i++) {
-+              int data_size1, data_size2, oob_size1, oob_size2;
-+              int reg_off = FLASH_BUF_ACC;
-+
-+              data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
-+              oob_size1 = ecc_cfg->bbm_size;
-+
-+              if (i == (num_cw - 1)) {
-+                      data_size2 = NANDC_STEP_SIZE - data_size1 -
-+                                   ((num_cw - 1) << 2);
-+                      oob_size2 = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+                                  ecc_cfg->spare_bytes;
-+              } else {
-+                      data_size2 = ecc_cfg->cw_data - data_size1;
-+                      oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+              }
-+
-+              qcom_write_data_dma(snandc, reg_off, data_buf, data_size1,
-+                                  NAND_BAM_NO_EOT);
-+              reg_off += data_size1;
-+              data_buf += data_size1;
-+
-+              qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size1,
-+                                  NAND_BAM_NO_EOT);
-+              oob_buf += oob_size1;
-+              reg_off += oob_size1;
-+
-+              qcom_write_data_dma(snandc, reg_off, data_buf, data_size2,
-+                                  NAND_BAM_NO_EOT);
-+              reg_off += data_size2;
-+              data_buf += data_size2;
-+
-+              qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size2, 0);
-+              oob_buf += oob_size2;
-+
-+              qcom_spi_config_cw_write(snandc);
-+      }
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret) {
-+              dev_err(snandc->dev, "failure to write raw page\n");
-+              return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc,
-+                              const struct spi_mem_op *op)
-+{
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      u8 *data_buf = NULL, *oob_buf = NULL;
-+      int i, ret;
-+      int num_cw = snandc->qspi->num_cw;
-+      u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
-+
-+      cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+                              (num_cw - 1) << CW_PER_PAGE;
-+      cfg1 = ecc_cfg->cfg1;
-+      ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+      ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
-+
-+      if (snandc->qspi->data_buf)
-+              data_buf = snandc->qspi->data_buf;
-+
-+      oob_buf = snandc->qspi->oob_buf;
-+
-+      snandc->buf_count = 0;
-+      snandc->buf_start = 0;
-+      qcom_clear_read_regs(snandc);
-+      qcom_clear_bam_transaction(snandc);
-+
-+      snandc->regs->addr0 = snandc->qspi->addr1;
-+      snandc->regs->addr1 = snandc->qspi->addr2;
-+      snandc->regs->cmd = snandc->qspi->cmd;
-+      snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+      snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+      snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
-+      snandc->regs->exec = cpu_to_le32(1);
-+
-+      qcom_spi_config_page_write(snandc);
-+
-+      for (i = 0; i < num_cw; i++) {
-+              int data_size, oob_size;
-+
-+              if (i == (num_cw - 1)) {
-+                      data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+                      oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+                                  ecc_cfg->spare_bytes;
-+              } else {
-+                      data_size = ecc_cfg->cw_data;
-+                      oob_size = ecc_cfg->bytes;
-+              }
-+
-+              if (data_buf)
-+                      qcom_write_data_dma(snandc, FLASH_BUF_ACC, data_buf, data_size,
-+                                          i == (num_cw - 1) ? NAND_BAM_NO_EOT : 0);
-+
-+              if (i == (num_cw - 1)) {
-+                      if (oob_buf) {
-+                              oob_buf += ecc_cfg->bbm_size;
-+                              qcom_write_data_dma(snandc, FLASH_BUF_ACC + data_size,
-+                                                  oob_buf, oob_size, 0);
-+                      }
-+              }
-+
-+              qcom_spi_config_cw_write(snandc);
-+
-+              if (data_buf)
-+                      data_buf += data_size;
-+              if (oob_buf)
-+                      oob_buf += oob_size;
-+      }
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret) {
-+              dev_err(snandc->dev, "failure to write page\n");
-+              return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_program_oob(struct qcom_nand_controller *snandc,
-+                              const struct spi_mem_op *op)
-+{
-+      struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+      u8 *oob_buf = NULL;
-+      int ret, col, data_size, oob_size;
-+      int num_cw = snandc->qspi->num_cw;
-+      u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
-+
-+      cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+                              (num_cw - 1) << CW_PER_PAGE;
-+      cfg1 = ecc_cfg->cfg1;
-+      ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+      ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
-+
-+      col = ecc_cfg->cw_size * (num_cw - 1);
-+
-+      oob_buf = snandc->qspi->data_buf;
-+
-+      snandc->buf_count = 0;
-+      snandc->buf_start = 0;
-+      qcom_clear_read_regs(snandc);
-+      qcom_clear_bam_transaction(snandc);
-+      snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
-+      snandc->regs->addr1 = snandc->qspi->addr2;
-+      snandc->regs->cmd = snandc->qspi->cmd;
-+      snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+      snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+      snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+      snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
-+      snandc->regs->exec = cpu_to_le32(1);
-+
-+      /* calculate the data and oob size for the last codeword/step */
-+      data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+      oob_size = snandc->qspi->mtd->oobavail;
-+
-+      memset(snandc->data_buffer, 0xff, ecc_cfg->cw_data);
-+      /* override new oob content to last codeword */
-+      mtd_ooblayout_get_databytes(snandc->qspi->mtd, snandc->data_buffer + data_size,
-+                                  oob_buf, 0, snandc->qspi->mtd->oobavail);
-+      qcom_spi_config_page_write(snandc);
-+      qcom_write_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, data_size + oob_size, 0);
-+      qcom_spi_config_cw_write(snandc);
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret) {
-+              dev_err(snandc->dev, "failure to write oob\n");
-+              return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_program_execute(struct qcom_nand_controller *snandc,
-+                                  const struct spi_mem_op *op)
-+{
-+      if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
-+              return qcom_spi_program_raw(snandc, op);
-+
-+      if (snandc->qspi->page_rw)
-+              return qcom_spi_program_ecc(snandc, op);
-+
-+      if (snandc->qspi->oob_rw)
-+              return qcom_spi_program_oob(snandc, op);
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd)
-+{
-+      switch (opcode) {
-+      case SPINAND_RESET:
-+              *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE);
-+              break;
-+      case SPINAND_READID:
-+              *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID);
-+              break;
-+      case SPINAND_GET_FEATURE:
-+              *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE);
-+              break;
-+      case SPINAND_SET_FEATURE:
-+              *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE |
-+                      QPIC_SET_FEATURE);
-+              break;
-+      case SPINAND_READ:
-+              if (snandc->qspi->raw_rw) {
-+                      *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
-+                                      SPI_WP | SPI_HOLD | OP_PAGE_READ);
-+              } else {
-+                      *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
-+                                      SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC);
-+              }
-+
-+              break;
-+      case SPINAND_ERASE:
-+              *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP |
-+                      SPI_HOLD | SPI_TRANSFER_MODE_x1;
-+              break;
-+      case SPINAND_WRITE_EN:
-+              *cmd = SPINAND_WRITE_EN;
-+              break;
-+      case SPINAND_PROGRAM_EXECUTE:
-+              *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
-+                              SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
-+              break;
-+      case SPINAND_PROGRAM_LOAD:
-+              *cmd = SPINAND_PROGRAM_LOAD;
-+              break;
-+      default:
-+              dev_err(snandc->dev, "Opcode not supported: %u\n", opcode);
-+              return -EOPNOTSUPP;
-+      }
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_write_page(struct qcom_nand_controller *snandc,
-+                             const struct spi_mem_op *op)
-+{
-+      int ret;
-+      u32 cmd;
-+
-+      ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
-+      if (ret < 0)
-+              return ret;
-+
-+      if (op->cmd.opcode == SPINAND_PROGRAM_LOAD)
-+              snandc->qspi->data_buf = (u8 *)op->data.buf.out;
-+
-+      return 0;
-+}
-+
-+static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
-+                               const struct spi_mem_op *op)
-+{
-+      struct qpic_snand_op s_op = {};
-+      u32 cmd;
-+      int ret, opcode;
-+
-+      ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
-+      if (ret < 0)
-+              return ret;
-+
-+      s_op.cmd_reg = cmd;
-+      s_op.addr1_reg = op->addr.val;
-+      s_op.addr2_reg = 0;
-+
-+      opcode = op->cmd.opcode;
-+
-+      switch (opcode) {
-+      case SPINAND_WRITE_EN:
-+              return 0;
-+      case SPINAND_PROGRAM_EXECUTE:
-+              s_op.addr1_reg = op->addr.val << 16;
-+              s_op.addr2_reg = op->addr.val >> 16 & 0xff;
-+              snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
-+              snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
-+              snandc->qspi->cmd = cpu_to_le32(cmd);
-+              return qcom_spi_program_execute(snandc, op);
-+      case SPINAND_READ:
-+              s_op.addr1_reg = (op->addr.val << 16);
-+              s_op.addr2_reg = op->addr.val >> 16 & 0xff;
-+              snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
-+              snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
-+              snandc->qspi->cmd = cpu_to_le32(cmd);
-+              return 0;
-+      case SPINAND_ERASE:
-+              s_op.addr2_reg = (op->addr.val >> 16) & 0xffff;
-+              s_op.addr1_reg = op->addr.val;
-+              snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16);
-+              snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
-+              snandc->qspi->cmd = cpu_to_le32(cmd);
-+              qcom_spi_block_erase(snandc);
-+              return 0;
-+      default:
-+              break;
-+      }
-+
-+      snandc->buf_count = 0;
-+      snandc->buf_start = 0;
-+      qcom_clear_read_regs(snandc);
-+      qcom_clear_bam_transaction(snandc);
-+
-+      snandc->regs->cmd = cpu_to_le32(s_op.cmd_reg);
-+      snandc->regs->exec = cpu_to_le32(1);
-+      snandc->regs->addr0 = cpu_to_le32(s_op.addr1_reg);
-+      snandc->regs->addr1 = cpu_to_le32(s_op.addr2_reg);
-+
-+      qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
-+      qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret)
-+              dev_err(snandc->dev, "failure in submitting cmd descriptor\n");
-+
-+      return ret;
-+}
-+
-+static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_mem_op *op)
-+{
-+      int ret, val, opcode;
-+      bool copy = false, copy_ftr = false;
-+
-+      ret = qcom_spi_send_cmdaddr(snandc, op);
-+      if (ret)
-+              return ret;
-+
-+      snandc->buf_count = 0;
-+      snandc->buf_start = 0;
-+      qcom_clear_read_regs(snandc);
-+      qcom_clear_bam_transaction(snandc);
-+      opcode = op->cmd.opcode;
-+
-+      switch (opcode) {
-+      case SPINAND_READID:
-+              snandc->buf_count = 4;
-+              qcom_read_reg_dma(snandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-+              copy = true;
-+              break;
-+      case SPINAND_GET_FEATURE:
-+              snandc->buf_count = 4;
-+              qcom_read_reg_dma(snandc, NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
-+              copy_ftr = true;
-+              break;
-+      case SPINAND_SET_FEATURE:
-+              snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out);
-+              qcom_write_reg_dma(snandc, &snandc->regs->flash_feature,
-+                                 NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
-+              break;
-+      case SPINAND_PROGRAM_EXECUTE:
-+      case SPINAND_WRITE_EN:
-+      case SPINAND_RESET:
-+      case SPINAND_ERASE:
-+      case SPINAND_READ:
-+              return 0;
-+      default:
-+              return -EOPNOTSUPP;
-+      }
-+
-+      ret = qcom_submit_descs(snandc);
-+      if (ret)
-+              dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode);
-+
-+      if (copy) {
-+              qcom_nandc_dev_to_mem(snandc, true);
-+              memcpy(op->data.buf.in, snandc->reg_read_buf, snandc->buf_count);
-+      }
-+
-+      if (copy_ftr) {
-+              qcom_nandc_dev_to_mem(snandc, true);
-+              val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf);
-+              val >>= 8;
-+              memcpy(op->data.buf.in, &val, snandc->buf_count);
-+      }
-+
-+      return ret;
-+}
-+
-+static bool qcom_spi_is_page_op(const struct spi_mem_op *op)
-+{
-+      if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && op->addr.buswidth != 4)
-+              return false;
-+
-+      if (op->data.dir == SPI_MEM_DATA_IN) {
-+              if (op->addr.buswidth == 4 && op->data.buswidth == 4)
-+                      return true;
-+
-+              if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
-+                      return true;
-+
-+      } else if (op->data.dir == SPI_MEM_DATA_OUT) {
-+              if (op->data.buswidth == 4)
-+                      return true;
-+              if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
-+                      return true;
-+      }
-+
-+      return false;
-+}
-+
-+static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
-+{
-+      if (!spi_mem_default_supports_op(mem, op))
-+              return false;
-+
-+      if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1)
-+              return false;
-+
-+      if (qcom_spi_is_page_op(op))
-+              return true;
-+
-+      return ((!op->addr.nbytes || op->addr.buswidth == 1) &&
-+              (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
-+              (!op->data.nbytes || op->data.buswidth == 1));
-+}
-+
-+static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
-+{
-+      struct qcom_nand_controller *snandc = spi_controller_get_devdata(mem->spi->controller);
-+
-+      dev_dbg(snandc->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode,
-+              op->addr.val, op->addr.buswidth, op->addr.nbytes,
-+              op->data.buswidth, op->data.nbytes);
-+
-+      if (qcom_spi_is_page_op(op)) {
-+              if (op->data.dir == SPI_MEM_DATA_IN)
-+                      return qcom_spi_read_page(snandc, op);
-+              if (op->data.dir == SPI_MEM_DATA_OUT)
-+                      return qcom_spi_write_page(snandc, op);
-+      } else {
-+              return qcom_spi_io_op(snandc, op);
-+      }
-+
-+      return 0;
-+}
-+
-+static const struct spi_controller_mem_ops qcom_spi_mem_ops = {
-+      .supports_op = qcom_spi_supports_op,
-+      .exec_op = qcom_spi_exec_op,
-+};
-+
-+static const struct spi_controller_mem_caps qcom_spi_mem_caps = {
-+      .ecc = true,
-+};
-+
-+static int qcom_spi_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct spi_controller *ctlr;
-+      struct qcom_nand_controller *snandc;
-+      struct qpic_spi_nand *qspi;
-+      struct qpic_ecc *ecc;
-+      struct resource *res;
-+      const void *dev_data;
-+      int ret;
-+
-+      ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
-+      if (!ecc)
-+              return -ENOMEM;
-+
-+      qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
-+      if (!qspi)
-+              return -ENOMEM;
-+
-+      ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false);
-+      if (!ctlr)
-+              return -ENOMEM;
-+
-+      platform_set_drvdata(pdev, ctlr);
-+
-+      snandc = spi_controller_get_devdata(ctlr);
-+      qspi->snandc = snandc;
-+
-+      snandc->dev = dev;
-+      snandc->qspi = qspi;
-+      snandc->qspi->ctlr = ctlr;
-+      snandc->qspi->ecc = ecc;
-+
-+      dev_data = of_device_get_match_data(dev);
-+      if (!dev_data) {
-+              dev_err(&pdev->dev, "failed to get device data\n");
-+              return -ENODEV;
-+      }
-+
-+      snandc->props = dev_data;
-+      snandc->dev = &pdev->dev;
-+
-+      snandc->core_clk = devm_clk_get(dev, "core");
-+      if (IS_ERR(snandc->core_clk))
-+              return PTR_ERR(snandc->core_clk);
-+
-+      snandc->aon_clk = devm_clk_get(dev, "aon");
-+      if (IS_ERR(snandc->aon_clk))
-+              return PTR_ERR(snandc->aon_clk);
-+
-+      snandc->qspi->iomacro_clk = devm_clk_get(dev, "iom");
-+      if (IS_ERR(snandc->qspi->iomacro_clk))
-+              return PTR_ERR(snandc->qspi->iomacro_clk);
-+
-+      snandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-+      if (IS_ERR(snandc->base))
-+              return PTR_ERR(snandc->base);
-+
-+      snandc->base_phys = res->start;
-+      snandc->base_dma = dma_map_resource(dev, res->start, resource_size(res),
-+                                          DMA_BIDIRECTIONAL, 0);
-+      if (dma_mapping_error(dev, snandc->base_dma))
-+              return -ENXIO;
-+
-+      ret = clk_prepare_enable(snandc->core_clk);
-+      if (ret)
-+              goto err_dis_core_clk;
-+
-+      ret = clk_prepare_enable(snandc->aon_clk);
-+      if (ret)
-+              goto err_dis_aon_clk;
-+
-+      ret = clk_prepare_enable(snandc->qspi->iomacro_clk);
-+      if (ret)
-+              goto err_dis_iom_clk;
-+
-+      ret = qcom_nandc_alloc(snandc);
-+      if (ret)
-+              goto err_snand_alloc;
-+
-+      ret = qcom_spi_init(snandc);
-+      if (ret)
-+              goto err_spi_init;
-+
-+      /* setup ECC engine */
-+      snandc->qspi->ecc_eng.dev = &pdev->dev;
-+      snandc->qspi->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
-+      snandc->qspi->ecc_eng.ops = &qcom_spi_ecc_engine_ops_pipelined;
-+      snandc->qspi->ecc_eng.priv = snandc;
-+
-+      ret = nand_ecc_register_on_host_hw_engine(&snandc->qspi->ecc_eng);
-+      if (ret) {
-+              dev_err(&pdev->dev, "failed to register ecc engine:%d\n", ret);
-+              goto err_spi_init;
-+      }
-+
-+      ctlr->num_chipselect = QPIC_QSPI_NUM_CS;
-+      ctlr->mem_ops = &qcom_spi_mem_ops;
-+      ctlr->mem_caps = &qcom_spi_mem_caps;
-+      ctlr->dev.of_node = pdev->dev.of_node;
-+      ctlr->mode_bits = SPI_TX_DUAL | SPI_RX_DUAL |
-+                          SPI_TX_QUAD | SPI_RX_QUAD;
-+
-+      ret = spi_register_controller(ctlr);
-+      if (ret) {
-+              dev_err(&pdev->dev, "spi_register_controller failed.\n");
-+              goto err_spi_init;
-+      }
-+
-+      return 0;
-+
-+err_spi_init:
-+      qcom_nandc_unalloc(snandc);
-+err_snand_alloc:
-+      clk_disable_unprepare(snandc->qspi->iomacro_clk);
-+err_dis_iom_clk:
-+      clk_disable_unprepare(snandc->aon_clk);
-+err_dis_aon_clk:
-+      clk_disable_unprepare(snandc->core_clk);
-+err_dis_core_clk:
-+      dma_unmap_resource(dev, res->start, resource_size(res),
-+                         DMA_BIDIRECTIONAL, 0);
-+      return ret;
-+}
-+
-+static void qcom_spi_remove(struct platform_device *pdev)
-+{
-+      struct spi_controller *ctlr = platform_get_drvdata(pdev);
-+      struct qcom_nand_controller *snandc = spi_controller_get_devdata(ctlr);
-+      struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+
-+      spi_unregister_controller(ctlr);
-+
-+      qcom_nandc_unalloc(snandc);
-+
-+      clk_disable_unprepare(snandc->aon_clk);
-+      clk_disable_unprepare(snandc->core_clk);
-+      clk_disable_unprepare(snandc->qspi->iomacro_clk);
-+
-+      dma_unmap_resource(&pdev->dev, snandc->base_dma, resource_size(res),
-+                         DMA_BIDIRECTIONAL, 0);
-+}
-+
-+static const struct qcom_nandc_props ipq9574_snandc_props = {
-+      .dev_cmd_reg_start = 0x7000,
-+      .supports_bam = true,
-+};
-+
-+static const struct of_device_id qcom_snandc_of_match[] = {
-+      {
-+              .compatible = "qcom,ipq9574-snand",
-+              .data = &ipq9574_snandc_props,
-+      },
-+      {}
-+}
-+MODULE_DEVICE_TABLE(of, qcom_snandc_of_match);
-+
-+static struct platform_driver qcom_spi_driver = {
-+      .driver = {
-+              .name           = "qcom_snand",
-+              .of_match_table = qcom_snandc_of_match,
-+      },
-+      .probe = qcom_spi_probe,
-+      .remove_new = qcom_spi_remove,
-+};
-+module_platform_driver(qcom_spi_driver);
-+
-+MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores");
-+MODULE_AUTHOR("Md Sadre Alam <[email protected]>");
-+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 (file)
index ad43f8d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-From cf1ba3cb245020459f2ca446b7a7b199839f5d83 Mon Sep 17 00:00:00 2001
-From: Dan Carpenter <[email protected]>
-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 <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Mark Brown <[email protected]>
----
- 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 (file)
index 1e2a3b0..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From d450cdd9c4398add1f2aa7200f2c95f1e3b9f9fa Mon Sep 17 00:00:00 2001
-From: Gabor Juhos <[email protected]>
-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 <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Mark Brown <[email protected]>
----
- 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 (file)
index 5e92048..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-From d32c4e58545f17caaa854415f854691e32d42075 Mon Sep 17 00:00:00 2001
-From: Geert Uytterhoeven <[email protected]>
-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 <[email protected]>
-Link: https://patch.msgid.link/b63db431cbf35223a4400e44c296293d32c4543c.1742998909.git.geert+renesas@glider.be
-Signed-off-by: Mark Brown <[email protected]>
----
- 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 (file)
index 9da531b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From: Gabor Juhos <[email protected]>
-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 <[email protected]>
-Reviewed-by: Abel Vesa <[email protected]>
-Reviewed-by: Md Sadre Alam <[email protected]>
----
- 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 (file)
index a2cd636..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From: Gabor Juhos <[email protected]>
-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 <[email protected]>
-Reviewed-by: Md Sadre Alam <[email protected]>
----
- 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 (file)
index 5a3d498..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From f48d80503504257682e493dc17408f2f0b47bcfa Mon Sep 17 00:00:00 2001
-From: Gabor Juhos <[email protected]>
-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 <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Mark Brown <[email protected]>
----
- 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 (file)
index 55e84da..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From: Gabor Juhos <[email protected]>
-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 <[email protected]>
----
- 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 (file)
index 0000000..7dd0031
--- /dev/null
@@ -0,0 +1,53 @@
+From 03cb793b26834ddca170ba87057c8f883772dd45 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Christoph Hellwig <[email protected]>
+Link: https://lore.kernel.org/r/[email protected]
+Signed-off-by: Jens Axboe <[email protected]>
+---
+ 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 (file)
index 0000000..b9fabe6
--- /dev/null
@@ -0,0 +1,94 @@
+From e5f587242b6072ffab4f4a084a459a59f3035873 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Christoph Hellwig <[email protected]>
+Link: https://lore.kernel.org/r/[email protected]
+Signed-off-by: Jens Axboe <[email protected]>
+---
+ 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 (file)
index 0000000..0bdeaa8
--- /dev/null
@@ -0,0 +1,104 @@
+From 45ff6c340ddfc2dade74d5b7a8962c778ab7042c Mon Sep 17 00:00:00 2001
+From: Christian Marangi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Linus Walleij <[email protected]>
+Link: https://lore.kernel.org/r/[email protected]
+Signed-off-by: Jens Axboe <[email protected]>
+---
+ 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 (file)
index 0000000..d260be1
--- /dev/null
@@ -0,0 +1,200 @@
+From 884555b557e5e6d41c866e2cd8d7b32f50ec974b Mon Sep 17 00:00:00 2001
+From: Christian Marangi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Christoph Hellwig <[email protected]>
+Link: https://lore.kernel.org/r/[email protected]
+Signed-off-by: Jens Axboe <[email protected]>
+---
+ block/partitions/Kconfig  |   9 ++++
+ block/partitions/Makefile |   1 +
+ block/partitions/check.h  |   1 +
+ block/partitions/core.c   |   3 ++
+ block/partitions/of.c     | 110 ++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 124 insertions(+)
+ create mode 100644 block/partitions/of.c
+
+--- a/block/partitions/Kconfig
++++ b/block/partitions/Kconfig
+@@ -270,4 +270,13 @@ config CMDLINE_PARTITION
+         Say Y here if you want to read the partition table from bootargs.
+         The format for the command line is just like mtdparts.
++config OF_PARTITION
++      bool "Device Tree partition support" if PARTITION_ADVANCED
++      depends on OF
++      help
++        Say Y here if you want to enable support for partition table
++        defined in Device Tree. (mainly for eMMC)
++        The format for the device tree node is just like MTD fixed-partition
++        schema.
++
+ endmenu
+--- a/block/partitions/Makefile
++++ b/block/partitions/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_CMDLINE_PARTITION) += cmdli
+ obj-$(CONFIG_MAC_PARTITION) += mac.o
+ obj-$(CONFIG_LDM_PARTITION) += ldm.o
+ obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
++obj-$(CONFIG_OF_PARTITION) += of.o
+ obj-$(CONFIG_OSF_PARTITION) += osf.o
+ obj-$(CONFIG_SGI_PARTITION) += sgi.o
+ obj-$(CONFIG_SUN_PARTITION) += sun.o
+--- a/block/partitions/check.h
++++ b/block/partitions/check.h
+@@ -62,6 +62,7 @@ int karma_partition(struct parsed_partit
+ int ldm_partition(struct parsed_partitions *state);
+ int mac_partition(struct parsed_partitions *state);
+ int msdos_partition(struct parsed_partitions *state);
++int of_partition(struct parsed_partitions *state);
+ int osf_partition(struct parsed_partitions *state);
+ int sgi_partition(struct parsed_partitions *state);
+ int sun_partition(struct parsed_partitions *state);
+--- a/block/partitions/core.c
++++ b/block/partitions/core.c
+@@ -43,6 +43,9 @@ static int (*const check_part[])(struct
+ #ifdef CONFIG_CMDLINE_PARTITION
+       cmdline_partition,
+ #endif
++#ifdef CONFIG_OF_PARTITION
++      of_partition,           /* cmdline have priority to OF */
++#endif
+ #ifdef CONFIG_EFI_PARTITION
+       efi_partition,          /* this must come before msdos */
+ #endif
+--- /dev/null
++++ b/block/partitions/of.c
+@@ -0,0 +1,110 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <linux/blkdev.h>
++#include <linux/major.h>
++#include <linux/of.h>
++#include <linux/string.h>
++#include "check.h"
++
++static int validate_of_partition(struct device_node *np, int slot)
++{
++      u64 offset, size;
++      int len;
++
++      const __be32 *reg = of_get_property(np, "reg", &len);
++      int a_cells = of_n_addr_cells(np);
++      int s_cells = of_n_size_cells(np);
++
++      /* Make sure reg len match the expected addr and size cells */
++      if (len / sizeof(*reg) != a_cells + s_cells)
++              return -EINVAL;
++
++      /* Validate offset conversion from bytes to sectors */
++      offset = of_read_number(reg, a_cells);
++      if (offset % SECTOR_SIZE)
++              return -EINVAL;
++
++      /* Validate size conversion from bytes to sectors */
++      size = of_read_number(reg + a_cells, s_cells);
++      if (!size || size % SECTOR_SIZE)
++              return -EINVAL;
++
++      return 0;
++}
++
++static void add_of_partition(struct parsed_partitions *state, int slot,
++                           struct device_node *np)
++{
++      struct partition_meta_info *info;
++      char tmp[sizeof(info->volname) + 4];
++      const char *partname;
++      int len;
++
++      const __be32 *reg = of_get_property(np, "reg", &len);
++      int a_cells = of_n_addr_cells(np);
++      int s_cells = of_n_size_cells(np);
++
++      /* Convert bytes to sector size */
++      u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE;
++      u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE;
++
++      put_partition(state, slot, offset, size);
++
++      if (of_property_read_bool(np, "read-only"))
++              state->parts[slot].flags |= ADDPART_FLAG_READONLY;
++
++      /*
++       * Follow MTD label logic, search for label property,
++       * fallback to node name if not found.
++       */
++      info = &state->parts[slot].info;
++      partname = of_get_property(np, "label", &len);
++      if (!partname)
++              partname = of_get_property(np, "name", &len);
++      strscpy(info->volname, partname, sizeof(info->volname));
++
++      snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
++      strlcat(state->pp_buf, tmp, PAGE_SIZE);
++}
++
++int of_partition(struct parsed_partitions *state)
++{
++      struct device *ddev = disk_to_dev(state->disk);
++      struct device_node *np;
++      int slot;
++
++      struct device_node *partitions_np = of_node_get(ddev->of_node);
++
++      if (!partitions_np ||
++          !of_device_is_compatible(partitions_np, "fixed-partitions"))
++              return 0;
++
++      slot = 1;
++      /* Validate parition offset and size */
++      for_each_child_of_node(partitions_np, np) {
++              if (validate_of_partition(np, slot)) {
++                      of_node_put(np);
++                      of_node_put(partitions_np);
++
++                      return -1;
++              }
++
++              slot++;
++      }
++
++      slot = 1;
++      for_each_child_of_node(partitions_np, np) {
++              if (slot >= state->limit) {
++                      of_node_put(np);
++                      break;
++              }
++
++              add_of_partition(state, slot, np);
++
++              slot++;
++      }
++
++      strlcat(state->pp_buf, "\n", PAGE_SIZE);
++
++      return 1;
++}
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 (file)
index 0000000..446f918
--- /dev/null
@@ -0,0 +1,54 @@
+From 9723a77318b7c0cfd06ea207e52a042f8c815318 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <[email protected]>
+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) <[email protected]>
+Reviewed-by: Florian Fainelli <[email protected]>
+Reviewed-by: Vladimir Oltean <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..d7342da
--- /dev/null
@@ -0,0 +1,53 @@
+From 99379f587278c818777cb4778e2c79c6c1440c65 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <[email protected]>
+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) <[email protected]>
+Reviewed-by: Florian Fainelli <[email protected]>
+Reviewed-by: Vladimir Oltean <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..003a896
--- /dev/null
@@ -0,0 +1,30 @@
+From f12b363887c706c40611fba645265527a8415832 Mon Sep 17 00:00:00 2001
+From: Rosen Penev <[email protected]>
+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 <[email protected]>
+(for hellcreek driver)
+Reviewed-by: Kurt Kanzenbach <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..ca0f610
--- /dev/null
@@ -0,0 +1,69 @@
+From c86692fc2cb77d94dd8c166c2b9017f196d02a84 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <[email protected]>
+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) <[email protected]>
+Reviewed-by: Florian Fainelli <[email protected]>
+Reviewed-by: Vladimir Oltean <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..900117a
--- /dev/null
@@ -0,0 +1,76 @@
+From c4f873c2b65c839ff5e7c996bd9ef5a1e7eae11a Mon Sep 17 00:00:00 2001
+From: Torben Nielsen <[email protected]>
+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 <[email protected]>
+Signed-off-by: Claus Stovgaard <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..75b5b04
--- /dev/null
@@ -0,0 +1,105 @@
+From e39d14a760c039af0653e3df967e7525413924a0 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <[email protected]>
+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 <[email protected]>
+Reviewed-by: Florian Fainelli <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ drivers/net/dsa/b53/b53_common.c | 28 ++++++++++++++++++++++++++++
+ drivers/net/dsa/b53/b53_priv.h   |  1 +
+ drivers/net/dsa/b53/b53_regs.h   |  7 +++++++
+ 3 files changed, 36 insertions(+)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -21,6 +21,7 @@
+ #include <linux/export.h>
+ #include <linux/gpio.h>
+ #include <linux/kernel.h>
++#include <linux/math.h>
+ #include <linux/module.h>
+ #include <linux/platform_data/b53.h>
+ #include <linux/phy.h>
+@@ -1202,6 +1203,10 @@ static int b53_setup(struct dsa_switch *
+        */
+       ds->untag_vlan_aware_bridge_pvid = true;
++      /* Ageing time is set in seconds */
++      ds->ageing_time_min = 1 * 1000;
++      ds->ageing_time_max = AGE_TIME_MAX * 1000;
++
+       ret = b53_reset_switch(dev);
+       if (ret) {
+               dev_err(ds->dev, "failed to reset switch\n");
+@@ -2412,6 +2417,28 @@ static int b53_get_max_mtu(struct dsa_sw
+       return B53_MAX_MTU;
+ }
++int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
++{
++      struct b53_device *dev = ds->priv;
++      u32 atc;
++      int reg;
++
++      if (is63xx(dev))
++              reg = B53_AGING_TIME_CONTROL_63XX;
++      else
++              reg = B53_AGING_TIME_CONTROL;
++
++      atc = DIV_ROUND_CLOSEST(msecs, 1000);
++
++      if (!is5325(dev) && !is5365(dev))
++              atc |= AGE_CHANGE;
++
++      b53_write32(dev, B53_MGMT_PAGE, reg, atc);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(b53_set_ageing_time);
++
+ static const struct phylink_mac_ops b53_phylink_mac_ops = {
+       .mac_select_pcs = b53_phylink_mac_select_pcs,
+       .mac_config     = b53_phylink_mac_config,
+@@ -2436,6 +2463,7 @@ static const struct dsa_switch_ops b53_s
+       .support_eee            = b53_support_eee,
+       .get_mac_eee            = b53_get_mac_eee,
+       .set_mac_eee            = b53_set_mac_eee,
++      .set_ageing_time        = b53_set_ageing_time,
+       .port_bridge_join       = b53_br_join,
+       .port_bridge_leave      = b53_br_leave,
+       .port_pre_bridge_flags  = b53_br_flags_pre,
+--- a/drivers/net/dsa/b53/b53_priv.h
++++ b/drivers/net/dsa/b53/b53_priv.h
+@@ -343,6 +343,7 @@ void b53_get_strings(struct dsa_switch *
+ void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
+ int b53_get_sset_count(struct dsa_switch *ds, int port, int sset);
+ void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data);
++int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs);
+ int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
+               bool *tx_fwd_offload, struct netlink_ext_ack *extack);
+ void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge);
+--- a/drivers/net/dsa/b53/b53_regs.h
++++ b/drivers/net/dsa/b53/b53_regs.h
+@@ -220,6 +220,13 @@
+ #define   BRCM_HDR_P5_EN              BIT(1) /* Enable tagging on port 5 */
+ #define   BRCM_HDR_P7_EN              BIT(2) /* Enable tagging on port 7 */
++/* Aging Time control register (32 bit) */
++#define B53_AGING_TIME_CONTROL                0x06
++#define B53_AGING_TIME_CONTROL_63XX   0x08
++#define  AGE_CHANGE                   BIT(20)
++#define  AGE_TIME_MASK                        0x7ffff
++#define  AGE_TIME_MAX                 1048575
++
+ /* Mirror capture control register (16 bit) */
+ #define B53_MIR_CAP_CTL                       0x10
+ #define  CAP_PORT_MASK                        0xf
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 (file)
index 0000000..9a53b70
--- /dev/null
@@ -0,0 +1,47 @@
+From 1237c2d4a8db79dfd4369bff6930b0e385ed7d5c Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <[email protected]>
+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 <[email protected]>
+Tested-by: Álvaro Fernández Rojas <[email protected]>
+Signed-off-by: Jonas Gorski <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Paolo Abeni <[email protected]>
+---
+ 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 (file)
index 0000000..6f15ea3
--- /dev/null
@@ -0,0 +1,49 @@
+From 4af523551d876ab8b8057d1e5303a860fd736fcb Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <[email protected]>
+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 <[email protected]>
+Reviewed-by: Florian Fainelli <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Paolo Abeni <[email protected]>
+---
+ 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 (file)
index 0000000..739e1b7
--- /dev/null
@@ -0,0 +1,70 @@
+From 75f4f7b2b13008803f84768ff90396f9d7553221 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <[email protected]>
+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 <[email protected]>
+Reviewed-by: Florian Fainelli <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Paolo Abeni <[email protected]>
+---
+ drivers/net/dsa/b53/b53_common.c | 22 ++++++++--------------
+ 1 file changed, 8 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -22,6 +22,7 @@
+ #include <linux/gpio.h>
+ #include <linux/kernel.h>
+ #include <linux/math.h>
++#include <linux/minmax.h>
+ #include <linux/module.h>
+ #include <linux/platform_data/b53.h>
+ #include <linux/phy.h>
+@@ -1322,24 +1323,17 @@ static void b53_adjust_63xx_rgmii(struct
+                                 phy_interface_t interface)
+ {
+       struct b53_device *dev = ds->priv;
+-      u8 rgmii_ctrl = 0, off;
++      u8 rgmii_ctrl = 0;
+-      if (port == dev->imp_port)
+-              off = B53_RGMII_CTRL_IMP;
+-      else
+-              off = B53_RGMII_CTRL_P(port);
+-
+-      b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
++      b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl);
+       rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
+-      if (port != dev->imp_port) {
+-              if (is63268(dev))
+-                      rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
++      if (is63268(dev))
++              rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
+-              rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
+-      }
++      rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
+-      b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl);
++      b53_write8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), rgmii_ctrl);
+       dev_dbg(ds->dev, "Configured port %d for %s\n", port,
+               phy_modes(interface));
+@@ -1484,7 +1478,7 @@ static void b53_phylink_mac_config(struc
+       struct b53_device *dev = ds->priv;
+       int port = dp->index;
+-      if (is63xx(dev) && port >= B53_63XX_RGMII0)
++      if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4))
+               b53_adjust_63xx_rgmii(ds, port, interface);
+       if (mode == MLO_AN_FIXED) {
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 (file)
index 0000000..9b74dd1
--- /dev/null
@@ -0,0 +1,36 @@
+From 5ea0d42c1980e6d10e5cb56a78021db5bfcebaaf Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <[email protected]>
+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 <[email protected]>
+Signed-off-by: Jonas Gorski <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Paolo Abeni <[email protected]>
+---
+ 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 (file)
index 0000000..9f2143d
--- /dev/null
@@ -0,0 +1,59 @@
+From bc1a65eb81a21e2aa3c3dca058ee8adf687b6ef5 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <[email protected]>
+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 <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Paolo Abeni <[email protected]>
+---
+ 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 (file)
index 0000000..9fa88d2
--- /dev/null
@@ -0,0 +1,31 @@
+From efdddc4484859082da6c7877ed144c8121c8ea55 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <[email protected]>
+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 <[email protected]>
+Reviewed-by: Florian Fainelli <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 446f918..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-From 9723a77318b7c0cfd06ea207e52a042f8c815318 Mon Sep 17 00:00:00 2001
-From: "Russell King (Oracle)" <[email protected]>
-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) <[email protected]>
-Reviewed-by: Florian Fainelli <[email protected]>
-Reviewed-by: Vladimir Oltean <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index d7342da..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-From 99379f587278c818777cb4778e2c79c6c1440c65 Mon Sep 17 00:00:00 2001
-From: "Russell King (Oracle)" <[email protected]>
-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) <[email protected]>
-Reviewed-by: Florian Fainelli <[email protected]>
-Reviewed-by: Vladimir Oltean <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 003a896..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From f12b363887c706c40611fba645265527a8415832 Mon Sep 17 00:00:00 2001
-From: Rosen Penev <[email protected]>
-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 <[email protected]>
-(for hellcreek driver)
-Reviewed-by: Kurt Kanzenbach <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index ca0f610..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-From c86692fc2cb77d94dd8c166c2b9017f196d02a84 Mon Sep 17 00:00:00 2001
-From: "Russell King (Oracle)" <[email protected]>
-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) <[email protected]>
-Reviewed-by: Florian Fainelli <[email protected]>
-Reviewed-by: Vladimir Oltean <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 900117a..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-From c4f873c2b65c839ff5e7c996bd9ef5a1e7eae11a Mon Sep 17 00:00:00 2001
-From: Torben Nielsen <[email protected]>
-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 <[email protected]>
-Signed-off-by: Claus Stovgaard <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 75b5b04..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-From e39d14a760c039af0653e3df967e7525413924a0 Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <[email protected]>
-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 <[email protected]>
-Reviewed-by: Florian Fainelli <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- drivers/net/dsa/b53/b53_common.c | 28 ++++++++++++++++++++++++++++
- drivers/net/dsa/b53/b53_priv.h   |  1 +
- drivers/net/dsa/b53/b53_regs.h   |  7 +++++++
- 3 files changed, 36 insertions(+)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -21,6 +21,7 @@
- #include <linux/export.h>
- #include <linux/gpio.h>
- #include <linux/kernel.h>
-+#include <linux/math.h>
- #include <linux/module.h>
- #include <linux/platform_data/b53.h>
- #include <linux/phy.h>
-@@ -1202,6 +1203,10 @@ static int b53_setup(struct dsa_switch *
-        */
-       ds->untag_vlan_aware_bridge_pvid = true;
-+      /* Ageing time is set in seconds */
-+      ds->ageing_time_min = 1 * 1000;
-+      ds->ageing_time_max = AGE_TIME_MAX * 1000;
-+
-       ret = b53_reset_switch(dev);
-       if (ret) {
-               dev_err(ds->dev, "failed to reset switch\n");
-@@ -2412,6 +2417,28 @@ static int b53_get_max_mtu(struct dsa_sw
-       return B53_MAX_MTU;
- }
-+int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
-+{
-+      struct b53_device *dev = ds->priv;
-+      u32 atc;
-+      int reg;
-+
-+      if (is63xx(dev))
-+              reg = B53_AGING_TIME_CONTROL_63XX;
-+      else
-+              reg = B53_AGING_TIME_CONTROL;
-+
-+      atc = DIV_ROUND_CLOSEST(msecs, 1000);
-+
-+      if (!is5325(dev) && !is5365(dev))
-+              atc |= AGE_CHANGE;
-+
-+      b53_write32(dev, B53_MGMT_PAGE, reg, atc);
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(b53_set_ageing_time);
-+
- static const struct phylink_mac_ops b53_phylink_mac_ops = {
-       .mac_select_pcs = b53_phylink_mac_select_pcs,
-       .mac_config     = b53_phylink_mac_config,
-@@ -2436,6 +2463,7 @@ static const struct dsa_switch_ops b53_s
-       .support_eee            = b53_support_eee,
-       .get_mac_eee            = b53_get_mac_eee,
-       .set_mac_eee            = b53_set_mac_eee,
-+      .set_ageing_time        = b53_set_ageing_time,
-       .port_bridge_join       = b53_br_join,
-       .port_bridge_leave      = b53_br_leave,
-       .port_pre_bridge_flags  = b53_br_flags_pre,
---- a/drivers/net/dsa/b53/b53_priv.h
-+++ b/drivers/net/dsa/b53/b53_priv.h
-@@ -343,6 +343,7 @@ void b53_get_strings(struct dsa_switch *
- void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
- int b53_get_sset_count(struct dsa_switch *ds, int port, int sset);
- void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data);
-+int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs);
- int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
-               bool *tx_fwd_offload, struct netlink_ext_ack *extack);
- void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge);
---- a/drivers/net/dsa/b53/b53_regs.h
-+++ b/drivers/net/dsa/b53/b53_regs.h
-@@ -220,6 +220,13 @@
- #define   BRCM_HDR_P5_EN              BIT(1) /* Enable tagging on port 5 */
- #define   BRCM_HDR_P7_EN              BIT(2) /* Enable tagging on port 7 */
-+/* Aging Time control register (32 bit) */
-+#define B53_AGING_TIME_CONTROL                0x06
-+#define B53_AGING_TIME_CONTROL_63XX   0x08
-+#define  AGE_CHANGE                   BIT(20)
-+#define  AGE_TIME_MASK                        0x7ffff
-+#define  AGE_TIME_MAX                 1048575
-+
- /* Mirror capture control register (16 bit) */
- #define B53_MIR_CAP_CTL                       0x10
- #define  CAP_PORT_MASK                        0xf
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 (file)
index 9a53b70..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-From 1237c2d4a8db79dfd4369bff6930b0e385ed7d5c Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <[email protected]>
-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 <[email protected]>
-Tested-by: Álvaro Fernández Rojas <[email protected]>
-Signed-off-by: Jonas Gorski <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Paolo Abeni <[email protected]>
----
- 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 (file)
index 6f15ea3..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-From 4af523551d876ab8b8057d1e5303a860fd736fcb Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <[email protected]>
-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 <[email protected]>
-Reviewed-by: Florian Fainelli <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Paolo Abeni <[email protected]>
----
- 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 (file)
index 739e1b7..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-From 75f4f7b2b13008803f84768ff90396f9d7553221 Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <[email protected]>
-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 <[email protected]>
-Reviewed-by: Florian Fainelli <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Paolo Abeni <[email protected]>
----
- drivers/net/dsa/b53/b53_common.c | 22 ++++++++--------------
- 1 file changed, 8 insertions(+), 14 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -22,6 +22,7 @@
- #include <linux/gpio.h>
- #include <linux/kernel.h>
- #include <linux/math.h>
-+#include <linux/minmax.h>
- #include <linux/module.h>
- #include <linux/platform_data/b53.h>
- #include <linux/phy.h>
-@@ -1322,24 +1323,17 @@ static void b53_adjust_63xx_rgmii(struct
-                                 phy_interface_t interface)
- {
-       struct b53_device *dev = ds->priv;
--      u8 rgmii_ctrl = 0, off;
-+      u8 rgmii_ctrl = 0;
--      if (port == dev->imp_port)
--              off = B53_RGMII_CTRL_IMP;
--      else
--              off = B53_RGMII_CTRL_P(port);
--
--      b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
-+      b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl);
-       rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
--      if (port != dev->imp_port) {
--              if (is63268(dev))
--                      rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
-+      if (is63268(dev))
-+              rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
--              rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
--      }
-+      rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
--      b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl);
-+      b53_write8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), rgmii_ctrl);
-       dev_dbg(ds->dev, "Configured port %d for %s\n", port,
-               phy_modes(interface));
-@@ -1484,7 +1478,7 @@ static void b53_phylink_mac_config(struc
-       struct b53_device *dev = ds->priv;
-       int port = dp->index;
--      if (is63xx(dev) && port >= B53_63XX_RGMII0)
-+      if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4))
-               b53_adjust_63xx_rgmii(ds, port, interface);
-       if (mode == MLO_AN_FIXED) {
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 (file)
index 9b74dd1..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From 5ea0d42c1980e6d10e5cb56a78021db5bfcebaaf Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <[email protected]>
-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 <[email protected]>
-Signed-off-by: Jonas Gorski <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Paolo Abeni <[email protected]>
----
- 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 (file)
index 9f2143d..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-From bc1a65eb81a21e2aa3c3dca058ee8adf687b6ef5 Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <[email protected]>
-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 <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Paolo Abeni <[email protected]>
----
- 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 (file)
index 0000000..e231bc8
--- /dev/null
@@ -0,0 +1,32 @@
+From 8cae5a0d91fea01d90ce7c1827e26934a22ca2fa Mon Sep 17 00:00:00 2001
+From: Rui Salvaterra <[email protected]>
+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 <[email protected]>
+---
+ 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 (file)
index 9fa88d2..0000000
+++ /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?= <[email protected]>
-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 <[email protected]>
-Reviewed-by: Florian Fainelli <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 0000000..25bd96f
--- /dev/null
@@ -0,0 +1,88 @@
+From 277f96c1f3f71d6e1d3bcf650d7cd84c1442210f Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <[email protected]>
+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 <[email protected]>
+Reviewed-by: Simon Horman <[email protected]>
+Signed-off-by: Andrew Lunn <[email protected]>
+---
+ 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 (file)
index 0000000..fbf3a99
--- /dev/null
@@ -0,0 +1,271 @@
+From c0dc1b412f9d840c51c5ee8927bf066e15a59550 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <[email protected]>
+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 <[email protected]>
+Reviewed-by: Simon Horman <[email protected]>
+Signed-off-by: Andrew Lunn <[email protected]>
+---
+ 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 (file)
index 0000000..1f6f5f5
--- /dev/null
@@ -0,0 +1,40 @@
+From bcbbfb4f62c4ba35783cc617997a2e92d91e3940 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <[email protected]>
+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 <[email protected]>
+Reviewed-by: Simon Horman <[email protected]>
+Signed-off-by: Andrew Lunn <[email protected]>
+---
+ 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 (file)
index 0000000..7161ffe
--- /dev/null
@@ -0,0 +1,3565 @@
+From e062f073dc0df4fcd338043cb0b69b6bcd31e4af Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <[email protected]>
+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 <[email protected]>
+Signed-off-by: SkyLake.Huang <[email protected]>
+Signed-off-by: David S. Miller <[email protected]>
+---
+ 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 <[email protected]>
+ M:    SkyLake Huang <[email protected]>
+ L:    [email protected]
+ S:    Maintained
+-F:    drivers/net/phy/mediatek-ge-soc.c
+-F:    drivers/net/phy/mediatek-ge.c
++F:    drivers/net/phy/mediatek/mtk-ge-soc.c
++F:    drivers/net/phy/mediatek/mtk-ge.c
+ F:    drivers/phy/mediatek/phy-mtk-xfi-tphy.c
+ MEDIATEK I2C CONTROLLER DRIVER
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -266,22 +266,7 @@ config MAXLINEAR_GPHY
+         Support for the Maxlinear GPY115, GPY211, GPY212, GPY215,
+         GPY241, GPY245 PHYs.
+-config MEDIATEK_GE_PHY
+-      tristate "MediaTek Gigabit Ethernet PHYs"
+-      help
+-        Supports the MediaTek Gigabit Ethernet PHYs.
+-
+-config MEDIATEK_GE_SOC_PHY
+-      tristate "MediaTek SoC Ethernet PHYs"
+-      depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
+-      depends on NVMEM_MTK_EFUSE
+-      help
+-        Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+-
+-        Include support for built-in Ethernet PHYs which are present in
+-        the MT7981 and MT7988 SoCs. These PHYs need calibration data
+-        present in the SoCs efuse and will dynamically calibrate VCM
+-        (common-mode voltage) during startup.
++source "drivers/net/phy/mediatek/Kconfig"
+ config MICREL_PHY
+       tristate "Micrel PHYs"
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -74,8 +74,7 @@ obj-$(CONFIG_MARVELL_PHY)    += marvell.o
+ obj-$(CONFIG_MARVELL_88Q2XXX_PHY)     += marvell-88q2xxx.o
+ obj-$(CONFIG_MARVELL_88X2222_PHY)     += marvell-88x2222.o
+ obj-$(CONFIG_MAXLINEAR_GPHY)  += mxl-gpy.o
+-obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
+-obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)     += mediatek-ge-soc.o
++obj-y                         += mediatek/
+ obj-$(CONFIG_MESON_GXL_PHY)   += meson-gxl.o
+ obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
+ obj-$(CONFIG_MICREL_PHY)      += micrel.o
+--- /dev/null
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -0,0 +1,22 @@
++# SPDX-License-Identifier: GPL-2.0-only
++config MEDIATEK_GE_PHY
++      tristate "MediaTek Gigabit Ethernet PHYs"
++      help
++        Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
++
++        Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531.
++        You may find mt7530 inside mt7621. This driver shares some
++        common operations with MediaTek SoC built-in Gigabit
++        Ethernet PHYs.
++
++config MEDIATEK_GE_SOC_PHY
++      tristate "MediaTek SoC Ethernet PHYs"
++      depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
++      depends on NVMEM_MTK_EFUSE
++      help
++        Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
++
++        Include support for built-in Ethernet PHYs which are present in
++        the MT7981 and MT7988 SoCs. These PHYs need calibration data
++        present in the SoCs efuse and will dynamically calibrate VCM
++        (common-mode voltage) during startup.
+--- /dev/null
++++ b/drivers/net/phy/mediatek/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_MEDIATEK_GE_PHY)         += mtk-ge.o
++obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)     += mtk-ge-soc.o
+--- a/drivers/net/phy/mediatek-ge-soc.c
++++ /dev/null
+@@ -1,1610 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0+
+-#include <linux/bitfield.h>
+-#include <linux/bitmap.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/module.h>
+-#include <linux/nvmem-consumer.h>
+-#include <linux/pinctrl/consumer.h>
+-#include <linux/phy.h>
+-#include <linux/regmap.h>
+-
+-#define MTK_GPHY_ID_MT7981                    0x03a29461
+-#define MTK_GPHY_ID_MT7988                    0x03a29481
+-
+-#define MTK_EXT_PAGE_ACCESS                   0x1f
+-#define MTK_PHY_PAGE_STANDARD                 0x0000
+-#define MTK_PHY_PAGE_EXTENDED_3                       0x0003
+-
+-#define MTK_PHY_LPI_REG_14                    0x14
+-#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK      GENMASK(8, 0)
+-
+-#define MTK_PHY_LPI_REG_1c                    0x1c
+-#define MTK_PHY_SMI_DET_ON_THRESH_MASK                GENMASK(13, 8)
+-
+-#define MTK_PHY_PAGE_EXTENDED_2A30            0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5            0x52b5
+-
+-#define ANALOG_INTERNAL_OPERATION_MAX_US      20
+-#define TXRESERVE_MIN                         0
+-#define TXRESERVE_MAX                         7
+-
+-#define MTK_PHY_ANARG_RG                      0x10
+-#define   MTK_PHY_TCLKOFFSET_MASK             GENMASK(12, 8)
+-
+-/* Registers on MDIO_MMD_VEND1 */
+-#define MTK_PHY_TXVLD_DA_RG                   0x12
+-#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK      GENMASK(15, 10)
+-#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK      GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_A2         0x16
+-#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK      GENMASK(15, 10)
+-#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK      GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_B1         0x17
+-#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK      GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK      GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_B2         0x18
+-#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK      GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK      GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_C1         0x19
+-#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK      GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK      GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_C2         0x20
+-#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK      GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK      GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_D1         0x21
+-#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK      GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK      GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_D2         0x22
+-#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK      GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK      GENMASK(5, 0)
+-
+-#define MTK_PHY_RXADC_CTRL_RG7                        0xc6
+-#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK      GENMASK(9, 8)
+-
+-#define MTK_PHY_RXADC_CTRL_RG9                        0xc8
+-#define   MTK_PHY_DA_RX_PSBN_TBT_MASK         GENMASK(14, 12)
+-#define   MTK_PHY_DA_RX_PSBN_HBT_MASK         GENMASK(10, 8)
+-#define   MTK_PHY_DA_RX_PSBN_GBE_MASK         GENMASK(6, 4)
+-#define   MTK_PHY_DA_RX_PSBN_LP_MASK          GENMASK(2, 0)
+-
+-#define MTK_PHY_LDO_OUTPUT_V                  0xd7
+-
+-#define MTK_PHY_RG_ANA_CAL_RG0                        0xdb
+-#define   MTK_PHY_RG_CAL_CKINV                        BIT(12)
+-#define   MTK_PHY_RG_ANA_CALEN                        BIT(8)
+-#define   MTK_PHY_RG_ZCALEN_A                 BIT(0)
+-
+-#define MTK_PHY_RG_ANA_CAL_RG1                        0xdc
+-#define   MTK_PHY_RG_ZCALEN_B                 BIT(12)
+-#define   MTK_PHY_RG_ZCALEN_C                 BIT(8)
+-#define   MTK_PHY_RG_ZCALEN_D                 BIT(4)
+-#define   MTK_PHY_RG_TXVOS_CALEN              BIT(0)
+-
+-#define MTK_PHY_RG_ANA_CAL_RG5                        0xe0
+-#define   MTK_PHY_RG_REXT_TRIM_MASK           GENMASK(13, 8)
+-
+-#define MTK_PHY_RG_TX_FILTER                  0xfe
+-
+-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120    0x120
+-#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK       GENMASK(12, 8)
+-#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK       GENMASK(4, 0)
+-
+-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122    0x122
+-#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK     GENMASK(7, 0)
+-
+-#define MTK_PHY_RG_TESTMUX_ADC_CTRL           0x144
+-#define   MTK_PHY_RG_TXEN_DIG_MASK            GENMASK(5, 5)
+-
+-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B               0x172
+-#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK     GENMASK(13, 8)
+-#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK     GENMASK(6, 0)
+-
+-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D               0x173
+-#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK     GENMASK(13, 8)
+-#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK     GENMASK(6, 0)
+-
+-#define MTK_PHY_RG_AD_CAL_COMP                        0x17a
+-#define   MTK_PHY_AD_CAL_COMP_OUT_MASK                GENMASK(8, 8)
+-
+-#define MTK_PHY_RG_AD_CAL_CLK                 0x17b
+-#define   MTK_PHY_DA_CAL_CLK                  BIT(0)
+-
+-#define MTK_PHY_RG_AD_CALIN                   0x17c
+-#define   MTK_PHY_DA_CALIN_FLAG                       BIT(0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_A             0x17d
+-#define   MTK_PHY_DASN_DAC_IN0_A_MASK         GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_B             0x17e
+-#define   MTK_PHY_DASN_DAC_IN0_B_MASK         GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_C             0x17f
+-#define   MTK_PHY_DASN_DAC_IN0_C_MASK         GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_D             0x180
+-#define   MTK_PHY_DASN_DAC_IN0_D_MASK         GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_A             0x181
+-#define   MTK_PHY_DASN_DAC_IN1_A_MASK         GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_B             0x182
+-#define   MTK_PHY_DASN_DAC_IN1_B_MASK         GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_C             0x183
+-#define   MTK_PHY_DASN_DAC_IN1_C_MASK         GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_D             0x184
+-#define   MTK_PHY_DASN_DAC_IN1_D_MASK         GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DEV1E_REG19b                       0x19b
+-#define   MTK_PHY_BYPASS_DSP_LPI_READY                BIT(8)
+-
+-#define MTK_PHY_RG_LP_IIR2_K1_L                       0x22a
+-#define MTK_PHY_RG_LP_IIR2_K1_U                       0x22b
+-#define MTK_PHY_RG_LP_IIR2_K2_L                       0x22c
+-#define MTK_PHY_RG_LP_IIR2_K2_U                       0x22d
+-#define MTK_PHY_RG_LP_IIR2_K3_L                       0x22e
+-#define MTK_PHY_RG_LP_IIR2_K3_U                       0x22f
+-#define MTK_PHY_RG_LP_IIR2_K4_L                       0x230
+-#define MTK_PHY_RG_LP_IIR2_K4_U                       0x231
+-#define MTK_PHY_RG_LP_IIR2_K5_L                       0x232
+-#define MTK_PHY_RG_LP_IIR2_K5_U                       0x233
+-
+-#define MTK_PHY_RG_DEV1E_REG234                       0x234
+-#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK                GENMASK(0, 0)
+-#define   MTK_PHY_LPF_X_AVERAGE_MASK          GENMASK(7, 4)
+-#define   MTK_PHY_TR_LP_IIR_EEE_EN            BIT(12)
+-
+-#define MTK_PHY_RG_LPF_CNT_VAL                        0x235
+-
+-#define MTK_PHY_RG_DEV1E_REG238                       0x238
+-#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK  GENMASK(8, 0)
+-#define   MTK_PHY_LPI_SLV_SEND_TX_EN          BIT(12)
+-
+-#define MTK_PHY_RG_DEV1E_REG239                       0x239
+-#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK     GENMASK(8, 0)
+-#define   MTK_PHY_LPI_TXPCS_LOC_RCV           BIT(12)
+-
+-#define MTK_PHY_RG_DEV1E_REG27C                       0x27c
+-#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK   GENMASK(12, 8)
+-#define MTK_PHY_RG_DEV1E_REG27D                       0x27d
+-#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK   GENMASK(4, 0)
+-
+-#define MTK_PHY_RG_DEV1E_REG2C7                       0x2c7
+-#define   MTK_PHY_MAX_GAIN_MASK                       GENMASK(4, 0)
+-#define   MTK_PHY_MIN_GAIN_MASK                       GENMASK(12, 8)
+-
+-#define MTK_PHY_RG_DEV1E_REG2D1                       0x2d1
+-#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK        GENMASK(7, 0)
+-#define   MTK_PHY_LPI_SKIP_SD_SLV_TR          BIT(8)
+-#define   MTK_PHY_LPI_TR_READY                        BIT(9)
+-#define   MTK_PHY_LPI_VCO_EEE_STG0_EN         BIT(10)
+-
+-#define MTK_PHY_RG_DEV1E_REG323                       0x323
+-#define   MTK_PHY_EEE_WAKE_MAS_INT_DC         BIT(0)
+-#define   MTK_PHY_EEE_WAKE_SLV_INT_DC         BIT(4)
+-
+-#define MTK_PHY_RG_DEV1E_REG324                       0x324
+-#define   MTK_PHY_SMI_DETCNT_MAX_MASK         GENMASK(5, 0)
+-#define   MTK_PHY_SMI_DET_MAX_EN              BIT(8)
+-
+-#define MTK_PHY_RG_DEV1E_REG326                       0x326
+-#define   MTK_PHY_LPI_MODE_SD_ON              BIT(0)
+-#define   MTK_PHY_RESET_RANDUPD_CNT           BIT(1)
+-#define   MTK_PHY_TREC_UPDATE_ENAB_CLR                BIT(2)
+-#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF       BIT(4)
+-#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP    BIT(5)
+-
+-#define MTK_PHY_LDO_PUMP_EN_PAIRAB            0x502
+-#define MTK_PHY_LDO_PUMP_EN_PAIRCD            0x503
+-
+-#define MTK_PHY_DA_TX_R50_PAIR_A              0x53d
+-#define MTK_PHY_DA_TX_R50_PAIR_B              0x53e
+-#define MTK_PHY_DA_TX_R50_PAIR_C              0x53f
+-#define MTK_PHY_DA_TX_R50_PAIR_D              0x540
+-
+-/* Registers on MDIO_MMD_VEND2 */
+-#define MTK_PHY_LED0_ON_CTRL                  0x24
+-#define MTK_PHY_LED1_ON_CTRL                  0x26
+-#define   MTK_PHY_LED_ON_MASK                 GENMASK(6, 0)
+-#define   MTK_PHY_LED_ON_LINK1000             BIT(0)
+-#define   MTK_PHY_LED_ON_LINK100              BIT(1)
+-#define   MTK_PHY_LED_ON_LINK10                       BIT(2)
+-#define   MTK_PHY_LED_ON_LINK                 (MTK_PHY_LED_ON_LINK10 |\
+-                                               MTK_PHY_LED_ON_LINK100 |\
+-                                               MTK_PHY_LED_ON_LINK1000)
+-#define   MTK_PHY_LED_ON_LINKDOWN             BIT(3)
+-#define   MTK_PHY_LED_ON_FDX                  BIT(4) /* Full duplex */
+-#define   MTK_PHY_LED_ON_HDX                  BIT(5) /* Half duplex */
+-#define   MTK_PHY_LED_ON_FORCE_ON             BIT(6)
+-#define   MTK_PHY_LED_ON_POLARITY             BIT(14)
+-#define   MTK_PHY_LED_ON_ENABLE                       BIT(15)
+-
+-#define MTK_PHY_LED0_BLINK_CTRL                       0x25
+-#define MTK_PHY_LED1_BLINK_CTRL                       0x27
+-#define   MTK_PHY_LED_BLINK_1000TX            BIT(0)
+-#define   MTK_PHY_LED_BLINK_1000RX            BIT(1)
+-#define   MTK_PHY_LED_BLINK_100TX             BIT(2)
+-#define   MTK_PHY_LED_BLINK_100RX             BIT(3)
+-#define   MTK_PHY_LED_BLINK_10TX              BIT(4)
+-#define   MTK_PHY_LED_BLINK_10RX              BIT(5)
+-#define   MTK_PHY_LED_BLINK_RX                        (MTK_PHY_LED_BLINK_10RX |\
+-                                               MTK_PHY_LED_BLINK_100RX |\
+-                                               MTK_PHY_LED_BLINK_1000RX)
+-#define   MTK_PHY_LED_BLINK_TX                        (MTK_PHY_LED_BLINK_10TX |\
+-                                               MTK_PHY_LED_BLINK_100TX |\
+-                                               MTK_PHY_LED_BLINK_1000TX)
+-#define   MTK_PHY_LED_BLINK_COLLISION         BIT(6)
+-#define   MTK_PHY_LED_BLINK_RX_CRC_ERR                BIT(7)
+-#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR               BIT(8)
+-#define   MTK_PHY_LED_BLINK_FORCE_BLINK               BIT(9)
+-
+-#define MTK_PHY_LED1_DEFAULT_POLARITIES               BIT(1)
+-
+-#define MTK_PHY_RG_BG_RASEL                   0x115
+-#define   MTK_PHY_RG_BG_RASEL_MASK            GENMASK(2, 0)
+-
+-/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
+-#define RG_GPIO_MISC_TPBANK0                  0x6f0
+-#define   RG_GPIO_MISC_TPBANK0_BOOTMODE               GENMASK(11, 8)
+-
+-/* These macro privides efuse parsing for internal phy. */
+-#define EFS_DA_TX_I2MPB_A(x)                  (((x) >> 0) & GENMASK(5, 0))
+-#define EFS_DA_TX_I2MPB_B(x)                  (((x) >> 6) & GENMASK(5, 0))
+-#define EFS_DA_TX_I2MPB_C(x)                  (((x) >> 12) & GENMASK(5, 0))
+-#define EFS_DA_TX_I2MPB_D(x)                  (((x) >> 18) & GENMASK(5, 0))
+-#define EFS_DA_TX_AMP_OFFSET_A(x)             (((x) >> 24) & GENMASK(5, 0))
+-
+-#define EFS_DA_TX_AMP_OFFSET_B(x)             (((x) >> 0) & GENMASK(5, 0))
+-#define EFS_DA_TX_AMP_OFFSET_C(x)             (((x) >> 6) & GENMASK(5, 0))
+-#define EFS_DA_TX_AMP_OFFSET_D(x)             (((x) >> 12) & GENMASK(5, 0))
+-#define EFS_DA_TX_R50_A(x)                    (((x) >> 18) & GENMASK(5, 0))
+-#define EFS_DA_TX_R50_B(x)                    (((x) >> 24) & GENMASK(5, 0))
+-
+-#define EFS_DA_TX_R50_C(x)                    (((x) >> 0) & GENMASK(5, 0))
+-#define EFS_DA_TX_R50_D(x)                    (((x) >> 6) & GENMASK(5, 0))
+-
+-#define EFS_RG_BG_RASEL(x)                    (((x) >> 4) & GENMASK(2, 0))
+-#define EFS_RG_REXT_TRIM(x)                   (((x) >> 7) & GENMASK(5, 0))
+-
+-enum {
+-      NO_PAIR,
+-      PAIR_A,
+-      PAIR_B,
+-      PAIR_C,
+-      PAIR_D,
+-};
+-
+-enum calibration_mode {
+-      EFUSE_K,
+-      SW_K
+-};
+-
+-enum CAL_ITEM {
+-      REXT,
+-      TX_OFFSET,
+-      TX_AMP,
+-      TX_R50,
+-      TX_VCM
+-};
+-
+-enum CAL_MODE {
+-      EFUSE_M,
+-      SW_M
+-};
+-
+-#define MTK_PHY_LED_STATE_FORCE_ON    0
+-#define MTK_PHY_LED_STATE_FORCE_BLINK 1
+-#define MTK_PHY_LED_STATE_NETDEV      2
+-
+-struct mtk_socphy_priv {
+-      unsigned long           led_state;
+-};
+-
+-struct mtk_socphy_shared {
+-      u32                     boottrap;
+-      struct mtk_socphy_priv  priv[4];
+-};
+-
+-static int mtk_socphy_read_page(struct phy_device *phydev)
+-{
+-      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_socphy_write_page(struct phy_device *phydev, int page)
+-{
+-      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+-/* One calibration cycle consists of:
+- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
+- *   until AD_CAL_COMP is ready to output calibration result.
+- * 2.Wait until DA_CAL_CLK is available.
+- * 3.Fetch AD_CAL_COMP_OUT.
+- */
+-static int cal_cycle(struct phy_device *phydev, int devad,
+-                   u32 regnum, u16 mask, u16 cal_val)
+-{
+-      int reg_val;
+-      int ret;
+-
+-      phy_modify_mmd(phydev, devad, regnum,
+-                     mask, cal_val);
+-      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+-                       MTK_PHY_DA_CALIN_FLAG);
+-
+-      ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
+-                                      MTK_PHY_RG_AD_CAL_CLK, reg_val,
+-                                      reg_val & MTK_PHY_DA_CAL_CLK, 500,
+-                                      ANALOG_INTERNAL_OPERATION_MAX_US,
+-                                      false);
+-      if (ret) {
+-              phydev_err(phydev, "Calibration cycle timeout\n");
+-              return ret;
+-      }
+-
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+-                         MTK_PHY_DA_CALIN_FLAG);
+-      ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
+-      if (ret < 0)
+-              return ret;
+-      ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
+-      phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
+-
+-      return ret;
+-}
+-
+-static int rext_fill_result(struct phy_device *phydev, u16 *buf)
+-{
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+-                     MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
+-                     MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
+-
+-      return 0;
+-}
+-
+-static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
+-{
+-      u16 rext_cal_val[2];
+-
+-      rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
+-      rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
+-      rext_fill_result(phydev, rext_cal_val);
+-
+-      return 0;
+-}
+-
+-static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
+-{
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
+-                     MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
+-                     MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
+-                     MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
+-                     MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
+-
+-      return 0;
+-}
+-
+-static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
+-{
+-      u16 tx_offset_cal_val[4];
+-
+-      tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
+-      tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
+-      tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
+-      tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
+-
+-      tx_offset_fill_result(phydev, tx_offset_cal_val);
+-
+-      return 0;
+-}
+-
+-static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
+-{
+-      const int vals_9481[16] = { 10, 6, 6, 10,
+-                                  10, 6, 6, 10,
+-                                  10, 6, 6, 10,
+-                                  10, 6, 6, 10 };
+-      const int vals_9461[16] = { 7, 1, 4, 7,
+-                                  7, 1, 4, 7,
+-                                  7, 1, 4, 7,
+-                                  7, 1, 4, 7 };
+-      int bias[16] = {};
+-      int i;
+-
+-      switch (phydev->drv->phy_id) {
+-      case MTK_GPHY_ID_MT7981:
+-              /* We add some calibration to efuse values
+-               * due to board level influence.
+-               * GBE: +7, TBT: +1, HBT: +4, TST: +7
+-               */
+-              memcpy(bias, (const void *)vals_9461, sizeof(bias));
+-              break;
+-      case MTK_GPHY_ID_MT7988:
+-              memcpy(bias, (const void *)vals_9481, sizeof(bias));
+-              break;
+-      }
+-
+-      /* Prevent overflow */
+-      for (i = 0; i < 12; i++) {
+-              if (buf[i >> 2] + bias[i] > 63) {
+-                      buf[i >> 2] = 63;
+-                      bias[i] = 0;
+-              }
+-      }
+-
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+-                     MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
+-                                buf[0] + bias[0]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+-                     MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
+-                                buf[0] + bias[1]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+-                     MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
+-                                buf[0] + bias[2]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+-                     MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
+-                                buf[0] + bias[3]));
+-
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+-                     MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
+-                                buf[1] + bias[4]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+-                     MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
+-                                buf[1] + bias[5]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+-                     MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
+-                                buf[1] + bias[6]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+-                     MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
+-                                buf[1] + bias[7]));
+-
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+-                     MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
+-                                buf[2] + bias[8]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+-                     MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
+-                                buf[2] + bias[9]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+-                     MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
+-                                buf[2] + bias[10]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+-                     MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
+-                                buf[2] + bias[11]));
+-
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+-                     MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
+-                                buf[3] + bias[12]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+-                     MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
+-                                buf[3] + bias[13]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+-                     MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
+-                                buf[3] + bias[14]));
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+-                     MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
+-                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
+-                                buf[3] + bias[15]));
+-
+-      return 0;
+-}
+-
+-static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
+-{
+-      u16 tx_amp_cal_val[4];
+-
+-      tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
+-      tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
+-      tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
+-      tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
+-      tx_amp_fill_result(phydev, tx_amp_cal_val);
+-
+-      return 0;
+-}
+-
+-static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
+-                            u8 txg_calen_x)
+-{
+-      int bias = 0;
+-      u16 reg, val;
+-
+-      if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
+-              bias = -1;
+-
+-      val = clamp_val(bias + tx_r50_cal_val, 0, 63);
+-
+-      switch (txg_calen_x) {
+-      case PAIR_A:
+-              reg = MTK_PHY_DA_TX_R50_PAIR_A;
+-              break;
+-      case PAIR_B:
+-              reg = MTK_PHY_DA_TX_R50_PAIR_B;
+-              break;
+-      case PAIR_C:
+-              reg = MTK_PHY_DA_TX_R50_PAIR_C;
+-              break;
+-      case PAIR_D:
+-              reg = MTK_PHY_DA_TX_R50_PAIR_D;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
+-
+-      return 0;
+-}
+-
+-static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
+-                          u8 txg_calen_x)
+-{
+-      u16 tx_r50_cal_val;
+-
+-      switch (txg_calen_x) {
+-      case PAIR_A:
+-              tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
+-              break;
+-      case PAIR_B:
+-              tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
+-              break;
+-      case PAIR_C:
+-              tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
+-              break;
+-      case PAIR_D:
+-              tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-      tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
+-
+-      return 0;
+-}
+-
+-static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
+-{
+-      u8 lower_idx, upper_idx, txreserve_val;
+-      u8 lower_ret, upper_ret;
+-      int ret;
+-
+-      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+-                       MTK_PHY_RG_ANA_CALEN);
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+-                         MTK_PHY_RG_CAL_CKINV);
+-      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+-                       MTK_PHY_RG_TXVOS_CALEN);
+-
+-      switch (rg_txreserve_x) {
+-      case PAIR_A:
+-              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                                 MTK_PHY_RG_DASN_DAC_IN0_A,
+-                                 MTK_PHY_DASN_DAC_IN0_A_MASK);
+-              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                                 MTK_PHY_RG_DASN_DAC_IN1_A,
+-                                 MTK_PHY_DASN_DAC_IN1_A_MASK);
+-              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                               MTK_PHY_RG_ANA_CAL_RG0,
+-                               MTK_PHY_RG_ZCALEN_A);
+-              break;
+-      case PAIR_B:
+-              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                                 MTK_PHY_RG_DASN_DAC_IN0_B,
+-                                 MTK_PHY_DASN_DAC_IN0_B_MASK);
+-              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                                 MTK_PHY_RG_DASN_DAC_IN1_B,
+-                                 MTK_PHY_DASN_DAC_IN1_B_MASK);
+-              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                               MTK_PHY_RG_ANA_CAL_RG1,
+-                               MTK_PHY_RG_ZCALEN_B);
+-              break;
+-      case PAIR_C:
+-              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                                 MTK_PHY_RG_DASN_DAC_IN0_C,
+-                                 MTK_PHY_DASN_DAC_IN0_C_MASK);
+-              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                                 MTK_PHY_RG_DASN_DAC_IN1_C,
+-                                 MTK_PHY_DASN_DAC_IN1_C_MASK);
+-              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                               MTK_PHY_RG_ANA_CAL_RG1,
+-                               MTK_PHY_RG_ZCALEN_C);
+-              break;
+-      case PAIR_D:
+-              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                                 MTK_PHY_RG_DASN_DAC_IN0_D,
+-                                 MTK_PHY_DASN_DAC_IN0_D_MASK);
+-              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                                 MTK_PHY_RG_DASN_DAC_IN1_D,
+-                                 MTK_PHY_DASN_DAC_IN1_D_MASK);
+-              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                               MTK_PHY_RG_ANA_CAL_RG1,
+-                               MTK_PHY_RG_ZCALEN_D);
+-              break;
+-      default:
+-              ret = -EINVAL;
+-              goto restore;
+-      }
+-
+-      lower_idx = TXRESERVE_MIN;
+-      upper_idx = TXRESERVE_MAX;
+-
+-      phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
+-      while ((upper_idx - lower_idx) > 1) {
+-              txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
+-              ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+-                              MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-                              MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-                              MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-                              MTK_PHY_DA_RX_PSBN_LP_MASK,
+-                              txreserve_val << 12 | txreserve_val << 8 |
+-                              txreserve_val << 4 | txreserve_val);
+-              if (ret == 1) {
+-                      upper_idx = txreserve_val;
+-                      upper_ret = ret;
+-              } else if (ret == 0) {
+-                      lower_idx = txreserve_val;
+-                      lower_ret = ret;
+-              } else {
+-                      goto restore;
+-              }
+-      }
+-
+-      if (lower_idx == TXRESERVE_MIN) {
+-              lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
+-                                    MTK_PHY_RXADC_CTRL_RG9,
+-                                    MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-                                    MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-                                    MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-                                    MTK_PHY_DA_RX_PSBN_LP_MASK,
+-                                    lower_idx << 12 | lower_idx << 8 |
+-                                    lower_idx << 4 | lower_idx);
+-              ret = lower_ret;
+-      } else if (upper_idx == TXRESERVE_MAX) {
+-              upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
+-                                    MTK_PHY_RXADC_CTRL_RG9,
+-                                    MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-                                    MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-                                    MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-                                    MTK_PHY_DA_RX_PSBN_LP_MASK,
+-                                    upper_idx << 12 | upper_idx << 8 |
+-                                    upper_idx << 4 | upper_idx);
+-              ret = upper_ret;
+-      }
+-      if (ret < 0)
+-              goto restore;
+-
+-      /* We calibrate TX-VCM in different logic. Check upper index and then
+-       * lower index. If this calibration is valid, apply lower index's
+-       * result.
+-       */
+-      ret = upper_ret - lower_ret;
+-      if (ret == 1) {
+-              ret = 0;
+-              /* Make sure we use upper_idx in our calibration system */
+-              cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+-                        MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-                        MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-                        MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-                        MTK_PHY_DA_RX_PSBN_LP_MASK,
+-                        upper_idx << 12 | upper_idx << 8 |
+-                        upper_idx << 4 | upper_idx);
+-              phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
+-      } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
+-                 lower_ret == 1) {
+-              ret = 0;
+-              cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+-                        MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-                        MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-                        MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-                        MTK_PHY_DA_RX_PSBN_LP_MASK,
+-                        lower_idx << 12 | lower_idx << 8 |
+-                        lower_idx << 4 | lower_idx);
+-              phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
+-                          lower_idx);
+-      } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
+-                 lower_ret == 0) {
+-              ret = 0;
+-              phydev_warn(phydev,
+-                          "TX-VCM SW cal result at high margin 0x%x\n",
+-                          upper_idx);
+-      } else {
+-              ret = -EINVAL;
+-      }
+-
+-restore:
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+-                         MTK_PHY_RG_ANA_CALEN);
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+-                         MTK_PHY_RG_TXVOS_CALEN);
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+-                         MTK_PHY_RG_ZCALEN_A);
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+-                         MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
+-                         MTK_PHY_RG_ZCALEN_D);
+-
+-      return ret;
+-}
+-
+-static void mt798x_phy_common_finetune(struct phy_device *phydev)
+-{
+-      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-      /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
+-      __phy_write(phydev, 0x11, 0xc71);
+-      __phy_write(phydev, 0x12, 0xc);
+-      __phy_write(phydev, 0x10, 0x8fae);
+-
+-      /* EnabRandUpdTrig = 1 */
+-      __phy_write(phydev, 0x11, 0x2f00);
+-      __phy_write(phydev, 0x12, 0xe);
+-      __phy_write(phydev, 0x10, 0x8fb0);
+-
+-      /* NormMseLoThresh = 85 */
+-      __phy_write(phydev, 0x11, 0x55a0);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x83aa);
+-
+-      /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
+-      __phy_write(phydev, 0x11, 0x240);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x9680);
+-
+-      /* TrFreeze = 0 (mt7988 default) */
+-      __phy_write(phydev, 0x11, 0x0);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x9686);
+-
+-      /* SSTrKp100 = 5 */
+-      /* SSTrKf100 = 6 */
+-      /* SSTrKp1000Mas = 5 */
+-      /* SSTrKf1000Mas = 6 */
+-      /* SSTrKp1000Slv = 5 */
+-      /* SSTrKf1000Slv = 6 */
+-      __phy_write(phydev, 0x11, 0xbaef);
+-      __phy_write(phydev, 0x12, 0x2e);
+-      __phy_write(phydev, 0x10, 0x968c);
+-      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-}
+-
+-static void mt7981_phy_finetune(struct phy_device *phydev)
+-{
+-      u16 val[8] = { 0x01ce, 0x01c1,
+-                     0x020f, 0x0202,
+-                     0x03d0, 0x03c0,
+-                     0x0013, 0x0005 };
+-      int i, k;
+-
+-      /* 100M eye finetune:
+-       * Keep middle level of TX MLT3 shapper as default.
+-       * Only change TX MLT3 overshoot level here.
+-       */
+-      for (k = 0, i = 1; i < 12; i++) {
+-              if (i % 3 == 0)
+-                      continue;
+-              phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
+-      }
+-
+-      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-      /* ResetSyncOffset = 6 */
+-      __phy_write(phydev, 0x11, 0x600);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x8fc0);
+-
+-      /* VgaDecRate = 1 */
+-      __phy_write(phydev, 0x11, 0x4c2a);
+-      __phy_write(phydev, 0x12, 0x3e);
+-      __phy_write(phydev, 0x10, 0x8fa4);
+-
+-      /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
+-       * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
+-       */
+-      __phy_write(phydev, 0x11, 0xd10a);
+-      __phy_write(phydev, 0x12, 0x34);
+-      __phy_write(phydev, 0x10, 0x8f82);
+-
+-      /* VcoSlicerThreshBitsHigh */
+-      __phy_write(phydev, 0x11, 0x5555);
+-      __phy_write(phydev, 0x12, 0x55);
+-      __phy_write(phydev, 0x10, 0x8ec0);
+-      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-      /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+-                     MTK_PHY_TR_OPEN_LOOP_EN_MASK |
+-                     MTK_PHY_LPF_X_AVERAGE_MASK,
+-                     BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
+-
+-      /* rg_tr_lpf_cnt_val = 512 */
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
+-
+-      /* IIR2 related */
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
+-
+-      /* FFE peaking */
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
+-                     MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
+-                     MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
+-
+-      /* Disable LDO pump */
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
+-      /* Adjust LDO output voltage */
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
+-}
+-
+-static void mt7988_phy_finetune(struct phy_device *phydev)
+-{
+-      u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
+-                      0x020d, 0x0206, 0x0384, 0x03d0,
+-                      0x03c6, 0x030a, 0x0011, 0x0005 };
+-      int i;
+-
+-      /* Set default MLT3 shaper first */
+-      for (i = 0; i < 12; i++)
+-              phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
+-
+-      /* TCT finetune */
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
+-
+-      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-      /* ResetSyncOffset = 5 */
+-      __phy_write(phydev, 0x11, 0x500);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x8fc0);
+-
+-      /* VgaDecRate is 1 at default on mt7988 */
+-
+-      /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
+-       * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
+-       */
+-      __phy_write(phydev, 0x11, 0xb90a);
+-      __phy_write(phydev, 0x12, 0x6f);
+-      __phy_write(phydev, 0x10, 0x8f82);
+-
+-      /* RemAckCntLimitCtrl = 1 */
+-      __phy_write(phydev, 0x11, 0xfbba);
+-      __phy_write(phydev, 0x12, 0xc3);
+-      __phy_write(phydev, 0x10, 0x87f8);
+-
+-      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-      /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+-                     MTK_PHY_TR_OPEN_LOOP_EN_MASK |
+-                     MTK_PHY_LPF_X_AVERAGE_MASK,
+-                     BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
+-
+-      /* rg_tr_lpf_cnt_val = 1023 */
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
+-}
+-
+-static void mt798x_phy_eee(struct phy_device *phydev)
+-{
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+-                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
+-                     MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
+-                     MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
+-                     FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
+-                     FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
+-
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+-                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
+-                     MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+-                     FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+-                                0xff));
+-
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                         MTK_PHY_RG_TESTMUX_ADC_CTRL,
+-                         MTK_PHY_RG_TXEN_DIG_MASK);
+-
+-      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                       MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
+-
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-                         MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
+-
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
+-                     MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
+-                     MTK_PHY_LPI_SLV_SEND_TX_EN,
+-                     FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
+-
+-      /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
+-                         MTK_PHY_LPI_TXPCS_LOC_RCV);
+-
+-      /* This also fixes some IoT issues, such as CH340 */
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
+-                     MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
+-                     FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
+-                     FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
+-
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
+-                     MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
+-                     FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
+-                                0x33) |
+-                     MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
+-                     MTK_PHY_LPI_VCO_EEE_STG0_EN);
+-
+-      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
+-                       MTK_PHY_EEE_WAKE_MAS_INT_DC |
+-                       MTK_PHY_EEE_WAKE_SLV_INT_DC);
+-
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
+-                     MTK_PHY_SMI_DETCNT_MAX_MASK,
+-                     FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
+-                     MTK_PHY_SMI_DET_MAX_EN);
+-
+-      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
+-                       MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
+-                       MTK_PHY_TREC_UPDATE_ENAB_CLR |
+-                       MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
+-                       MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
+-
+-      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-      /* Regsigdet_sel_1000 = 0 */
+-      __phy_write(phydev, 0x11, 0xb);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x9690);
+-
+-      /* REG_EEE_st2TrKf1000 = 2 */
+-      __phy_write(phydev, 0x11, 0x114f);
+-      __phy_write(phydev, 0x12, 0x2);
+-      __phy_write(phydev, 0x10, 0x969a);
+-
+-      /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
+-      __phy_write(phydev, 0x11, 0x3028);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x969e);
+-
+-      /* RegEEE_slv_wake_int_timer_tar = 8 */
+-      __phy_write(phydev, 0x11, 0x5010);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x96a0);
+-
+-      /* RegEEE_trfreeze_timer2 = 586 */
+-      __phy_write(phydev, 0x11, 0x24a);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x96a8);
+-
+-      /* RegEEE100Stg1_tar = 16 */
+-      __phy_write(phydev, 0x11, 0x3210);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x96b8);
+-
+-      /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
+-      __phy_write(phydev, 0x11, 0x1463);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x96ca);
+-
+-      /* DfeTailEnableVgaThresh1000 = 27 */
+-      __phy_write(phydev, 0x11, 0x36);
+-      __phy_write(phydev, 0x12, 0x0);
+-      __phy_write(phydev, 0x10, 0x8f80);
+-      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
+-      __phy_modify(phydev, MTK_PHY_LPI_REG_14,
+-                   MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
+-                   FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
+-
+-      __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
+-                   FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
+-      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+-                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
+-                     MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+-                     FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+-                                0xff));
+-}
+-
+-static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
+-                u8 start_pair, u8 end_pair)
+-{
+-      u8 pair_n;
+-      int ret;
+-
+-      for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
+-              /* TX_OFFSET & TX_AMP have no SW calibration. */
+-              switch (cal_item) {
+-              case TX_VCM:
+-                      ret = tx_vcm_cal_sw(phydev, pair_n);
+-                      break;
+-              default:
+-                      return -EINVAL;
+-              }
+-              if (ret)
+-                      return ret;
+-      }
+-      return 0;
+-}
+-
+-static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
+-                   u8 start_pair, u8 end_pair, u32 *buf)
+-{
+-      u8 pair_n;
+-      int ret;
+-
+-      for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
+-              /* TX_VCM has no efuse calibration. */
+-              switch (cal_item) {
+-              case REXT:
+-                      ret = rext_cal_efuse(phydev, buf);
+-                      break;
+-              case TX_OFFSET:
+-                      ret = tx_offset_cal_efuse(phydev, buf);
+-                      break;
+-              case TX_AMP:
+-                      ret = tx_amp_cal_efuse(phydev, buf);
+-                      break;
+-              case TX_R50:
+-                      ret = tx_r50_cal_efuse(phydev, buf, pair_n);
+-                      break;
+-              default:
+-                      return -EINVAL;
+-              }
+-              if (ret)
+-                      return ret;
+-      }
+-
+-      return 0;
+-}
+-
+-static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
+-                   enum CAL_MODE cal_mode, u8 start_pair,
+-                   u8 end_pair, u32 *buf)
+-{
+-      int ret;
+-
+-      switch (cal_mode) {
+-      case EFUSE_M:
+-              ret = cal_efuse(phydev, cal_item, start_pair,
+-                              end_pair, buf);
+-              break;
+-      case SW_M:
+-              ret = cal_sw(phydev, cal_item, start_pair, end_pair);
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      if (ret) {
+-              phydev_err(phydev, "cal %d failed\n", cal_item);
+-              return -EIO;
+-      }
+-
+-      return 0;
+-}
+-
+-static int mt798x_phy_calibration(struct phy_device *phydev)
+-{
+-      struct nvmem_cell *cell;
+-      int ret = 0;
+-      size_t len;
+-      u32 *buf;
+-
+-      cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
+-      if (IS_ERR(cell)) {
+-              if (PTR_ERR(cell) == -EPROBE_DEFER)
+-                      return PTR_ERR(cell);
+-              return 0;
+-      }
+-
+-      buf = (u32 *)nvmem_cell_read(cell, &len);
+-      if (IS_ERR(buf))
+-              return PTR_ERR(buf);
+-      nvmem_cell_put(cell);
+-
+-      if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
+-              phydev_err(phydev, "invalid efuse data\n");
+-              ret = -EINVAL;
+-              goto out;
+-      }
+-
+-      ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
+-      if (ret)
+-              goto out;
+-      ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
+-      if (ret)
+-              goto out;
+-      ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
+-      if (ret)
+-              goto out;
+-      ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
+-      if (ret)
+-              goto out;
+-      ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
+-      if (ret)
+-              goto out;
+-
+-out:
+-      kfree(buf);
+-      return ret;
+-}
+-
+-static int mt798x_phy_config_init(struct phy_device *phydev)
+-{
+-      switch (phydev->drv->phy_id) {
+-      case MTK_GPHY_ID_MT7981:
+-              mt7981_phy_finetune(phydev);
+-              break;
+-      case MTK_GPHY_ID_MT7988:
+-              mt7988_phy_finetune(phydev);
+-              break;
+-      }
+-
+-      mt798x_phy_common_finetune(phydev);
+-      mt798x_phy_eee(phydev);
+-
+-      return mt798x_phy_calibration(phydev);
+-}
+-
+-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+-                                  bool on)
+-{
+-      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+-      struct mtk_socphy_priv *priv = phydev->priv;
+-      bool changed;
+-
+-      if (on)
+-              changed = !test_and_set_bit(bit_on, &priv->led_state);
+-      else
+-              changed = !!test_and_clear_bit(bit_on, &priv->led_state);
+-
+-      changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
+-                                      (index ? 16 : 0), &priv->led_state);
+-      if (changed)
+-              return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-                                    MTK_PHY_LED1_ON_CTRL :
+-                                    MTK_PHY_LED0_ON_CTRL,
+-                                    MTK_PHY_LED_ON_MASK,
+-                                    on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+-      else
+-              return 0;
+-}
+-
+-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+-                                     bool blinking)
+-{
+-      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+-                               (index ? 16 : 0);
+-      struct mtk_socphy_priv *priv = phydev->priv;
+-      bool changed;
+-
+-      if (blinking)
+-              changed = !test_and_set_bit(bit_blink, &priv->led_state);
+-      else
+-              changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
+-
+-      changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
+-                            (index ? 16 : 0), &priv->led_state);
+-      if (changed)
+-              return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+-                                   MTK_PHY_LED1_BLINK_CTRL :
+-                                   MTK_PHY_LED0_BLINK_CTRL,
+-                                   blinking ?
+-                                   MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+-      else
+-              return 0;
+-}
+-
+-static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
+-                                  unsigned long *delay_on,
+-                                  unsigned long *delay_off)
+-{
+-      bool blinking = false;
+-      int err = 0;
+-
+-      if (index > 1)
+-              return -EINVAL;
+-
+-      if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+-              blinking = true;
+-              *delay_on = 50;
+-              *delay_off = 50;
+-      }
+-
+-      err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
+-      if (err)
+-              return err;
+-
+-      return mt798x_phy_hw_led_on_set(phydev, index, false);
+-}
+-
+-static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
+-                                       u8 index, enum led_brightness value)
+-{
+-      int err;
+-
+-      err = mt798x_phy_hw_led_blink_set(phydev, index, false);
+-      if (err)
+-              return err;
+-
+-      return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
+-}
+-
+-static const unsigned long supported_triggers =
+-      BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+-      BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+-      BIT(TRIGGER_NETDEV_LINK)        |
+-      BIT(TRIGGER_NETDEV_LINK_10)     |
+-      BIT(TRIGGER_NETDEV_LINK_100)    |
+-      BIT(TRIGGER_NETDEV_LINK_1000)   |
+-      BIT(TRIGGER_NETDEV_RX)          |
+-      BIT(TRIGGER_NETDEV_TX);
+-
+-static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+-                                        unsigned long rules)
+-{
+-      if (index > 1)
+-              return -EINVAL;
+-
+-      /* All combinations of the supported triggers are allowed */
+-      if (rules & ~supported_triggers)
+-              return -EOPNOTSUPP;
+-
+-      return 0;
+-};
+-
+-static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+-                                       unsigned long *rules)
+-{
+-      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+-                               (index ? 16 : 0);
+-      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+-      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+-      struct mtk_socphy_priv *priv = phydev->priv;
+-      int on, blink;
+-
+-      if (index > 1)
+-              return -EINVAL;
+-
+-      on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+-                        index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
+-
+-      if (on < 0)
+-              return -EIO;
+-
+-      blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+-                           index ? MTK_PHY_LED1_BLINK_CTRL :
+-                                   MTK_PHY_LED0_BLINK_CTRL);
+-      if (blink < 0)
+-              return -EIO;
+-
+-      if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
+-                 MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
+-          (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
+-              set_bit(bit_netdev, &priv->led_state);
+-      else
+-              clear_bit(bit_netdev, &priv->led_state);
+-
+-      if (on & MTK_PHY_LED_ON_FORCE_ON)
+-              set_bit(bit_on, &priv->led_state);
+-      else
+-              clear_bit(bit_on, &priv->led_state);
+-
+-      if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
+-              set_bit(bit_blink, &priv->led_state);
+-      else
+-              clear_bit(bit_blink, &priv->led_state);
+-
+-      if (!rules)
+-              return 0;
+-
+-      if (on & MTK_PHY_LED_ON_LINK)
+-              *rules |= BIT(TRIGGER_NETDEV_LINK);
+-
+-      if (on & MTK_PHY_LED_ON_LINK10)
+-              *rules |= BIT(TRIGGER_NETDEV_LINK_10);
+-
+-      if (on & MTK_PHY_LED_ON_LINK100)
+-              *rules |= BIT(TRIGGER_NETDEV_LINK_100);
+-
+-      if (on & MTK_PHY_LED_ON_LINK1000)
+-              *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+-
+-      if (on & MTK_PHY_LED_ON_FDX)
+-              *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+-
+-      if (on & MTK_PHY_LED_ON_HDX)
+-              *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
+-
+-      if (blink & MTK_PHY_LED_BLINK_RX)
+-              *rules |= BIT(TRIGGER_NETDEV_RX);
+-
+-      if (blink & MTK_PHY_LED_BLINK_TX)
+-              *rules |= BIT(TRIGGER_NETDEV_TX);
+-
+-      return 0;
+-};
+-
+-static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
+-                                       unsigned long rules)
+-{
+-      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+-      struct mtk_socphy_priv *priv = phydev->priv;
+-      u16 on = 0, blink = 0;
+-      int ret;
+-
+-      if (index > 1)
+-              return -EINVAL;
+-
+-      if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+-              on |= MTK_PHY_LED_ON_FDX;
+-
+-      if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
+-              on |= MTK_PHY_LED_ON_HDX;
+-
+-      if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
+-              on |= MTK_PHY_LED_ON_LINK10;
+-
+-      if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+-              on |= MTK_PHY_LED_ON_LINK100;
+-
+-      if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+-              on |= MTK_PHY_LED_ON_LINK1000;
+-
+-      if (rules & BIT(TRIGGER_NETDEV_RX)) {
+-              blink |= (on & MTK_PHY_LED_ON_LINK) ?
+-                        (((on & MTK_PHY_LED_ON_LINK10) ?
+-                          MTK_PHY_LED_BLINK_10RX : 0) |
+-                         ((on & MTK_PHY_LED_ON_LINK100) ?
+-                          MTK_PHY_LED_BLINK_100RX : 0) |
+-                         ((on & MTK_PHY_LED_ON_LINK1000) ?
+-                          MTK_PHY_LED_BLINK_1000RX : 0)) :
+-                        MTK_PHY_LED_BLINK_RX;
+-      }
+-
+-      if (rules & BIT(TRIGGER_NETDEV_TX)) {
+-              blink |= (on & MTK_PHY_LED_ON_LINK) ?
+-                        (((on & MTK_PHY_LED_ON_LINK10) ?
+-                          MTK_PHY_LED_BLINK_10TX : 0) |
+-                         ((on & MTK_PHY_LED_ON_LINK100) ?
+-                          MTK_PHY_LED_BLINK_100TX : 0) |
+-                         ((on & MTK_PHY_LED_ON_LINK1000) ?
+-                          MTK_PHY_LED_BLINK_1000TX : 0)) :
+-                        MTK_PHY_LED_BLINK_TX;
+-      }
+-
+-      if (blink || on)
+-              set_bit(bit_netdev, &priv->led_state);
+-      else
+-              clear_bit(bit_netdev, &priv->led_state);
+-
+-      ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-                              MTK_PHY_LED1_ON_CTRL :
+-                              MTK_PHY_LED0_ON_CTRL,
+-                           MTK_PHY_LED_ON_FDX     |
+-                           MTK_PHY_LED_ON_HDX     |
+-                           MTK_PHY_LED_ON_LINK,
+-                           on);
+-
+-      if (ret)
+-              return ret;
+-
+-      return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+-                              MTK_PHY_LED1_BLINK_CTRL :
+-                              MTK_PHY_LED0_BLINK_CTRL, blink);
+-};
+-
+-static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
+-{
+-      struct mtk_socphy_shared *priv = phydev->shared->priv;
+-      u32 polarities;
+-
+-      if (led_num == 0)
+-              polarities = ~(priv->boottrap);
+-      else
+-              polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
+-
+-      if (polarities & BIT(phydev->mdio.addr))
+-              return true;
+-
+-      return false;
+-}
+-
+-static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
+-{
+-      struct pinctrl *pinctrl;
+-      int index;
+-
+-      /* Setup LED polarity according to bootstrap use of LED pins */
+-      for (index = 0; index < 2; ++index)
+-              phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-                              MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+-                             MTK_PHY_LED_ON_POLARITY,
+-                             mt7988_phy_led_get_polarity(phydev, index) ?
+-                              MTK_PHY_LED_ON_POLARITY : 0);
+-
+-      /* Only now setup pinctrl to avoid bogus blinking */
+-      pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
+-      if (IS_ERR(pinctrl))
+-              dev_err(&phydev->mdio.bus->dev,
+-                      "Failed to setup PHY LED pinctrl\n");
+-
+-      return 0;
+-}
+-
+-static int mt7988_phy_probe_shared(struct phy_device *phydev)
+-{
+-      struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
+-      struct mtk_socphy_shared *shared = phydev->shared->priv;
+-      struct regmap *regmap;
+-      u32 reg;
+-      int ret;
+-
+-      /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
+-       * LED_C and LED_D respectively. At the same time those pins are used to
+-       * bootstrap configuration of the reference clock source (LED_A),
+-       * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
+-       * In practice this is done using a LED and a resistor pulling the pin
+-       * either to GND or to VIO.
+-       * The detected value at boot time is accessible at run-time using the
+-       * TPBANK0 register located in the gpio base of the pinctrl, in order
+-       * to read it here it needs to be referenced by a phandle called
+-       * 'mediatek,pio' in the MDIO bus hosting the PHY.
+-       * The 4 bits in TPBANK0 are kept as package shared data and are used to
+-       * set LED polarity for each of the LED0.
+-       */
+-      regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
+-      if (IS_ERR(regmap))
+-              return PTR_ERR(regmap);
+-
+-      ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, &reg);
+-      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 <[email protected]>");
+-MODULE_AUTHOR("SkyLake Huang <[email protected]>");
+-MODULE_LICENSE("GPL");
+-
+-MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
+--- a/drivers/net/phy/mediatek-ge.c
++++ /dev/null
+@@ -1,111 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0+
+-#include <linux/bitfield.h>
+-#include <linux/module.h>
+-#include <linux/phy.h>
+-
+-#define MTK_EXT_PAGE_ACCESS           0x1f
+-#define MTK_PHY_PAGE_STANDARD         0x0000
+-#define MTK_PHY_PAGE_EXTENDED         0x0001
+-#define MTK_PHY_PAGE_EXTENDED_2               0x0002
+-#define MTK_PHY_PAGE_EXTENDED_3               0x0003
+-#define MTK_PHY_PAGE_EXTENDED_2A30    0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5    0x52b5
+-
+-static int mtk_gephy_read_page(struct phy_device *phydev)
+-{
+-      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_gephy_write_page(struct phy_device *phydev, int page)
+-{
+-      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+-static void mtk_gephy_config_init(struct phy_device *phydev)
+-{
+-      /* Enable HW auto downshift */
+-      phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
+-
+-      /* Increase SlvDPSready time */
+-      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-      __phy_write(phydev, 0x10, 0xafae);
+-      __phy_write(phydev, 0x12, 0x2f);
+-      __phy_write(phydev, 0x10, 0x8fae);
+-      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-      /* Adjust 100_mse_threshold */
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
+-
+-      /* Disable mcc */
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
+-}
+-
+-static int mt7530_phy_config_init(struct phy_device *phydev)
+-{
+-      mtk_gephy_config_init(phydev);
+-
+-      /* Increase post_update_timer */
+-      phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
+-
+-      return 0;
+-}
+-
+-static int mt7531_phy_config_init(struct phy_device *phydev)
+-{
+-      mtk_gephy_config_init(phydev);
+-
+-      /* PHY link down power saving enable */
+-      phy_set_bits(phydev, 0x17, BIT(4));
+-      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
+-
+-      /* Set TX Pair delay selection */
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
+-      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
+-
+-      return 0;
+-}
+-
+-static struct phy_driver mtk_gephy_driver[] = {
+-      {
+-              PHY_ID_MATCH_EXACT(0x03a29412),
+-              .name           = "MediaTek MT7530 PHY",
+-              .config_init    = mt7530_phy_config_init,
+-              /* Interrupts are handled by the switch, not the PHY
+-               * itself.
+-               */
+-              .config_intr    = genphy_no_config_intr,
+-              .handle_interrupt = genphy_handle_interrupt_no_ack,
+-              .suspend        = genphy_suspend,
+-              .resume         = genphy_resume,
+-              .read_page      = mtk_gephy_read_page,
+-              .write_page     = mtk_gephy_write_page,
+-      },
+-      {
+-              PHY_ID_MATCH_EXACT(0x03a29441),
+-              .name           = "MediaTek MT7531 PHY",
+-              .config_init    = mt7531_phy_config_init,
+-              /* Interrupts are handled by the switch, not the PHY
+-               * itself.
+-               */
+-              .config_intr    = genphy_no_config_intr,
+-              .handle_interrupt = genphy_handle_interrupt_no_ack,
+-              .suspend        = genphy_suspend,
+-              .resume         = genphy_resume,
+-              .read_page      = mtk_gephy_read_page,
+-              .write_page     = mtk_gephy_write_page,
+-      },
+-};
+-
+-module_phy_driver(mtk_gephy_driver);
+-
+-static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
+-      { PHY_ID_MATCH_EXACT(0x03a29441) },
+-      { PHY_ID_MATCH_EXACT(0x03a29412) },
+-      { }
+-};
+-
+-MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
+-MODULE_AUTHOR("DENG, Qingfang <[email protected]>");
+-MODULE_LICENSE("GPL");
+-
+-MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -0,0 +1,1610 @@
++// SPDX-License-Identifier: GPL-2.0+
++#include <linux/bitfield.h>
++#include <linux/bitmap.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/phy.h>
++#include <linux/regmap.h>
++
++#define MTK_GPHY_ID_MT7981                    0x03a29461
++#define MTK_GPHY_ID_MT7988                    0x03a29481
++
++#define MTK_EXT_PAGE_ACCESS                   0x1f
++#define MTK_PHY_PAGE_STANDARD                 0x0000
++#define MTK_PHY_PAGE_EXTENDED_3                       0x0003
++
++#define MTK_PHY_LPI_REG_14                    0x14
++#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK      GENMASK(8, 0)
++
++#define MTK_PHY_LPI_REG_1c                    0x1c
++#define MTK_PHY_SMI_DET_ON_THRESH_MASK                GENMASK(13, 8)
++
++#define MTK_PHY_PAGE_EXTENDED_2A30            0x2a30
++#define MTK_PHY_PAGE_EXTENDED_52B5            0x52b5
++
++#define ANALOG_INTERNAL_OPERATION_MAX_US      20
++#define TXRESERVE_MIN                         0
++#define TXRESERVE_MAX                         7
++
++#define MTK_PHY_ANARG_RG                      0x10
++#define   MTK_PHY_TCLKOFFSET_MASK             GENMASK(12, 8)
++
++/* Registers on MDIO_MMD_VEND1 */
++#define MTK_PHY_TXVLD_DA_RG                   0x12
++#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK      GENMASK(15, 10)
++#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK      GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_A2         0x16
++#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK      GENMASK(15, 10)
++#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK      GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_B1         0x17
++#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK      GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK      GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_B2         0x18
++#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK      GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK      GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_C1         0x19
++#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK      GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK      GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_C2         0x20
++#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK      GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK      GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_D1         0x21
++#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK      GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK      GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_D2         0x22
++#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK      GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK      GENMASK(5, 0)
++
++#define MTK_PHY_RXADC_CTRL_RG7                        0xc6
++#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK      GENMASK(9, 8)
++
++#define MTK_PHY_RXADC_CTRL_RG9                        0xc8
++#define   MTK_PHY_DA_RX_PSBN_TBT_MASK         GENMASK(14, 12)
++#define   MTK_PHY_DA_RX_PSBN_HBT_MASK         GENMASK(10, 8)
++#define   MTK_PHY_DA_RX_PSBN_GBE_MASK         GENMASK(6, 4)
++#define   MTK_PHY_DA_RX_PSBN_LP_MASK          GENMASK(2, 0)
++
++#define MTK_PHY_LDO_OUTPUT_V                  0xd7
++
++#define MTK_PHY_RG_ANA_CAL_RG0                        0xdb
++#define   MTK_PHY_RG_CAL_CKINV                        BIT(12)
++#define   MTK_PHY_RG_ANA_CALEN                        BIT(8)
++#define   MTK_PHY_RG_ZCALEN_A                 BIT(0)
++
++#define MTK_PHY_RG_ANA_CAL_RG1                        0xdc
++#define   MTK_PHY_RG_ZCALEN_B                 BIT(12)
++#define   MTK_PHY_RG_ZCALEN_C                 BIT(8)
++#define   MTK_PHY_RG_ZCALEN_D                 BIT(4)
++#define   MTK_PHY_RG_TXVOS_CALEN              BIT(0)
++
++#define MTK_PHY_RG_ANA_CAL_RG5                        0xe0
++#define   MTK_PHY_RG_REXT_TRIM_MASK           GENMASK(13, 8)
++
++#define MTK_PHY_RG_TX_FILTER                  0xfe
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120    0x120
++#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK       GENMASK(12, 8)
++#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK       GENMASK(4, 0)
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122    0x122
++#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK     GENMASK(7, 0)
++
++#define MTK_PHY_RG_TESTMUX_ADC_CTRL           0x144
++#define   MTK_PHY_RG_TXEN_DIG_MASK            GENMASK(5, 5)
++
++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B               0x172
++#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK     GENMASK(13, 8)
++#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK     GENMASK(6, 0)
++
++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D               0x173
++#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK     GENMASK(13, 8)
++#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK     GENMASK(6, 0)
++
++#define MTK_PHY_RG_AD_CAL_COMP                        0x17a
++#define   MTK_PHY_AD_CAL_COMP_OUT_MASK                GENMASK(8, 8)
++
++#define MTK_PHY_RG_AD_CAL_CLK                 0x17b
++#define   MTK_PHY_DA_CAL_CLK                  BIT(0)
++
++#define MTK_PHY_RG_AD_CALIN                   0x17c
++#define   MTK_PHY_DA_CALIN_FLAG                       BIT(0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_A             0x17d
++#define   MTK_PHY_DASN_DAC_IN0_A_MASK         GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_B             0x17e
++#define   MTK_PHY_DASN_DAC_IN0_B_MASK         GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_C             0x17f
++#define   MTK_PHY_DASN_DAC_IN0_C_MASK         GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_D             0x180
++#define   MTK_PHY_DASN_DAC_IN0_D_MASK         GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_A             0x181
++#define   MTK_PHY_DASN_DAC_IN1_A_MASK         GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_B             0x182
++#define   MTK_PHY_DASN_DAC_IN1_B_MASK         GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_C             0x183
++#define   MTK_PHY_DASN_DAC_IN1_C_MASK         GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_D             0x184
++#define   MTK_PHY_DASN_DAC_IN1_D_MASK         GENMASK(9, 0)
++
++#define MTK_PHY_RG_DEV1E_REG19b                       0x19b
++#define   MTK_PHY_BYPASS_DSP_LPI_READY                BIT(8)
++
++#define MTK_PHY_RG_LP_IIR2_K1_L                       0x22a
++#define MTK_PHY_RG_LP_IIR2_K1_U                       0x22b
++#define MTK_PHY_RG_LP_IIR2_K2_L                       0x22c
++#define MTK_PHY_RG_LP_IIR2_K2_U                       0x22d
++#define MTK_PHY_RG_LP_IIR2_K3_L                       0x22e
++#define MTK_PHY_RG_LP_IIR2_K3_U                       0x22f
++#define MTK_PHY_RG_LP_IIR2_K4_L                       0x230
++#define MTK_PHY_RG_LP_IIR2_K4_U                       0x231
++#define MTK_PHY_RG_LP_IIR2_K5_L                       0x232
++#define MTK_PHY_RG_LP_IIR2_K5_U                       0x233
++
++#define MTK_PHY_RG_DEV1E_REG234                       0x234
++#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK                GENMASK(0, 0)
++#define   MTK_PHY_LPF_X_AVERAGE_MASK          GENMASK(7, 4)
++#define   MTK_PHY_TR_LP_IIR_EEE_EN            BIT(12)
++
++#define MTK_PHY_RG_LPF_CNT_VAL                        0x235
++
++#define MTK_PHY_RG_DEV1E_REG238                       0x238
++#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK  GENMASK(8, 0)
++#define   MTK_PHY_LPI_SLV_SEND_TX_EN          BIT(12)
++
++#define MTK_PHY_RG_DEV1E_REG239                       0x239
++#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK     GENMASK(8, 0)
++#define   MTK_PHY_LPI_TXPCS_LOC_RCV           BIT(12)
++
++#define MTK_PHY_RG_DEV1E_REG27C                       0x27c
++#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK   GENMASK(12, 8)
++#define MTK_PHY_RG_DEV1E_REG27D                       0x27d
++#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK   GENMASK(4, 0)
++
++#define MTK_PHY_RG_DEV1E_REG2C7                       0x2c7
++#define   MTK_PHY_MAX_GAIN_MASK                       GENMASK(4, 0)
++#define   MTK_PHY_MIN_GAIN_MASK                       GENMASK(12, 8)
++
++#define MTK_PHY_RG_DEV1E_REG2D1                       0x2d1
++#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK        GENMASK(7, 0)
++#define   MTK_PHY_LPI_SKIP_SD_SLV_TR          BIT(8)
++#define   MTK_PHY_LPI_TR_READY                        BIT(9)
++#define   MTK_PHY_LPI_VCO_EEE_STG0_EN         BIT(10)
++
++#define MTK_PHY_RG_DEV1E_REG323                       0x323
++#define   MTK_PHY_EEE_WAKE_MAS_INT_DC         BIT(0)
++#define   MTK_PHY_EEE_WAKE_SLV_INT_DC         BIT(4)
++
++#define MTK_PHY_RG_DEV1E_REG324                       0x324
++#define   MTK_PHY_SMI_DETCNT_MAX_MASK         GENMASK(5, 0)
++#define   MTK_PHY_SMI_DET_MAX_EN              BIT(8)
++
++#define MTK_PHY_RG_DEV1E_REG326                       0x326
++#define   MTK_PHY_LPI_MODE_SD_ON              BIT(0)
++#define   MTK_PHY_RESET_RANDUPD_CNT           BIT(1)
++#define   MTK_PHY_TREC_UPDATE_ENAB_CLR                BIT(2)
++#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF       BIT(4)
++#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP    BIT(5)
++
++#define MTK_PHY_LDO_PUMP_EN_PAIRAB            0x502
++#define MTK_PHY_LDO_PUMP_EN_PAIRCD            0x503
++
++#define MTK_PHY_DA_TX_R50_PAIR_A              0x53d
++#define MTK_PHY_DA_TX_R50_PAIR_B              0x53e
++#define MTK_PHY_DA_TX_R50_PAIR_C              0x53f
++#define MTK_PHY_DA_TX_R50_PAIR_D              0x540
++
++/* Registers on MDIO_MMD_VEND2 */
++#define MTK_PHY_LED0_ON_CTRL                  0x24
++#define MTK_PHY_LED1_ON_CTRL                  0x26
++#define   MTK_PHY_LED_ON_MASK                 GENMASK(6, 0)
++#define   MTK_PHY_LED_ON_LINK1000             BIT(0)
++#define   MTK_PHY_LED_ON_LINK100              BIT(1)
++#define   MTK_PHY_LED_ON_LINK10                       BIT(2)
++#define   MTK_PHY_LED_ON_LINK                 (MTK_PHY_LED_ON_LINK10 |\
++                                               MTK_PHY_LED_ON_LINK100 |\
++                                               MTK_PHY_LED_ON_LINK1000)
++#define   MTK_PHY_LED_ON_LINKDOWN             BIT(3)
++#define   MTK_PHY_LED_ON_FDX                  BIT(4) /* Full duplex */
++#define   MTK_PHY_LED_ON_HDX                  BIT(5) /* Half duplex */
++#define   MTK_PHY_LED_ON_FORCE_ON             BIT(6)
++#define   MTK_PHY_LED_ON_POLARITY             BIT(14)
++#define   MTK_PHY_LED_ON_ENABLE                       BIT(15)
++
++#define MTK_PHY_LED0_BLINK_CTRL                       0x25
++#define MTK_PHY_LED1_BLINK_CTRL                       0x27
++#define   MTK_PHY_LED_BLINK_1000TX            BIT(0)
++#define   MTK_PHY_LED_BLINK_1000RX            BIT(1)
++#define   MTK_PHY_LED_BLINK_100TX             BIT(2)
++#define   MTK_PHY_LED_BLINK_100RX             BIT(3)
++#define   MTK_PHY_LED_BLINK_10TX              BIT(4)
++#define   MTK_PHY_LED_BLINK_10RX              BIT(5)
++#define   MTK_PHY_LED_BLINK_RX                        (MTK_PHY_LED_BLINK_10RX |\
++                                               MTK_PHY_LED_BLINK_100RX |\
++                                               MTK_PHY_LED_BLINK_1000RX)
++#define   MTK_PHY_LED_BLINK_TX                        (MTK_PHY_LED_BLINK_10TX |\
++                                               MTK_PHY_LED_BLINK_100TX |\
++                                               MTK_PHY_LED_BLINK_1000TX)
++#define   MTK_PHY_LED_BLINK_COLLISION         BIT(6)
++#define   MTK_PHY_LED_BLINK_RX_CRC_ERR                BIT(7)
++#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR               BIT(8)
++#define   MTK_PHY_LED_BLINK_FORCE_BLINK               BIT(9)
++
++#define MTK_PHY_LED1_DEFAULT_POLARITIES               BIT(1)
++
++#define MTK_PHY_RG_BG_RASEL                   0x115
++#define   MTK_PHY_RG_BG_RASEL_MASK            GENMASK(2, 0)
++
++/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
++#define RG_GPIO_MISC_TPBANK0                  0x6f0
++#define   RG_GPIO_MISC_TPBANK0_BOOTMODE               GENMASK(11, 8)
++
++/* These macro privides efuse parsing for internal phy. */
++#define EFS_DA_TX_I2MPB_A(x)                  (((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_B(x)                  (((x) >> 6) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_C(x)                  (((x) >> 12) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_D(x)                  (((x) >> 18) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_A(x)             (((x) >> 24) & GENMASK(5, 0))
++
++#define EFS_DA_TX_AMP_OFFSET_B(x)             (((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_C(x)             (((x) >> 6) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_D(x)             (((x) >> 12) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_A(x)                    (((x) >> 18) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_B(x)                    (((x) >> 24) & GENMASK(5, 0))
++
++#define EFS_DA_TX_R50_C(x)                    (((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_D(x)                    (((x) >> 6) & GENMASK(5, 0))
++
++#define EFS_RG_BG_RASEL(x)                    (((x) >> 4) & GENMASK(2, 0))
++#define EFS_RG_REXT_TRIM(x)                   (((x) >> 7) & GENMASK(5, 0))
++
++enum {
++      NO_PAIR,
++      PAIR_A,
++      PAIR_B,
++      PAIR_C,
++      PAIR_D,
++};
++
++enum calibration_mode {
++      EFUSE_K,
++      SW_K
++};
++
++enum CAL_ITEM {
++      REXT,
++      TX_OFFSET,
++      TX_AMP,
++      TX_R50,
++      TX_VCM
++};
++
++enum CAL_MODE {
++      EFUSE_M,
++      SW_M
++};
++
++#define MTK_PHY_LED_STATE_FORCE_ON    0
++#define MTK_PHY_LED_STATE_FORCE_BLINK 1
++#define MTK_PHY_LED_STATE_NETDEV      2
++
++struct mtk_socphy_priv {
++      unsigned long           led_state;
++};
++
++struct mtk_socphy_shared {
++      u32                     boottrap;
++      struct mtk_socphy_priv  priv[4];
++};
++
++static int mtk_socphy_read_page(struct phy_device *phydev)
++{
++      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++
++static int mtk_socphy_write_page(struct phy_device *phydev, int page)
++{
++      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++
++/* One calibration cycle consists of:
++ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
++ *   until AD_CAL_COMP is ready to output calibration result.
++ * 2.Wait until DA_CAL_CLK is available.
++ * 3.Fetch AD_CAL_COMP_OUT.
++ */
++static int cal_cycle(struct phy_device *phydev, int devad,
++                   u32 regnum, u16 mask, u16 cal_val)
++{
++      int reg_val;
++      int ret;
++
++      phy_modify_mmd(phydev, devad, regnum,
++                     mask, cal_val);
++      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
++                       MTK_PHY_DA_CALIN_FLAG);
++
++      ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
++                                      MTK_PHY_RG_AD_CAL_CLK, reg_val,
++                                      reg_val & MTK_PHY_DA_CAL_CLK, 500,
++                                      ANALOG_INTERNAL_OPERATION_MAX_US,
++                                      false);
++      if (ret) {
++              phydev_err(phydev, "Calibration cycle timeout\n");
++              return ret;
++      }
++
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
++                         MTK_PHY_DA_CALIN_FLAG);
++      ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
++      if (ret < 0)
++              return ret;
++      ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
++      phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
++
++      return ret;
++}
++
++static int rext_fill_result(struct phy_device *phydev, u16 *buf)
++{
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
++                     MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
++      phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
++                     MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
++
++      return 0;
++}
++
++static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++      u16 rext_cal_val[2];
++
++      rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
++      rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
++      rext_fill_result(phydev, rext_cal_val);
++
++      return 0;
++}
++
++static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
++{
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
++                     MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
++                     MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
++                     MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
++                     MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
++
++      return 0;
++}
++
++static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++      u16 tx_offset_cal_val[4];
++
++      tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
++      tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
++      tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
++      tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
++
++      tx_offset_fill_result(phydev, tx_offset_cal_val);
++
++      return 0;
++}
++
++static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
++{
++      const int vals_9481[16] = { 10, 6, 6, 10,
++                                  10, 6, 6, 10,
++                                  10, 6, 6, 10,
++                                  10, 6, 6, 10 };
++      const int vals_9461[16] = { 7, 1, 4, 7,
++                                  7, 1, 4, 7,
++                                  7, 1, 4, 7,
++                                  7, 1, 4, 7 };
++      int bias[16] = {};
++      int i;
++
++      switch (phydev->drv->phy_id) {
++      case MTK_GPHY_ID_MT7981:
++              /* We add some calibration to efuse values
++               * due to board level influence.
++               * GBE: +7, TBT: +1, HBT: +4, TST: +7
++               */
++              memcpy(bias, (const void *)vals_9461, sizeof(bias));
++              break;
++      case MTK_GPHY_ID_MT7988:
++              memcpy(bias, (const void *)vals_9481, sizeof(bias));
++              break;
++      }
++
++      /* Prevent overflow */
++      for (i = 0; i < 12; i++) {
++              if (buf[i >> 2] + bias[i] > 63) {
++                      buf[i >> 2] = 63;
++                      bias[i] = 0;
++              }
++      }
++
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
++                     MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
++                                buf[0] + bias[0]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
++                     MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
++                                buf[0] + bias[1]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
++                     MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
++                                buf[0] + bias[2]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
++                     MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
++                                buf[0] + bias[3]));
++
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
++                     MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
++                                buf[1] + bias[4]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
++                     MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
++                                buf[1] + bias[5]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
++                     MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
++                                buf[1] + bias[6]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
++                     MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
++                                buf[1] + bias[7]));
++
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
++                     MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
++                                buf[2] + bias[8]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
++                     MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
++                                buf[2] + bias[9]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
++                     MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
++                                buf[2] + bias[10]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
++                     MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
++                                buf[2] + bias[11]));
++
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
++                     MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
++                                buf[3] + bias[12]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
++                     MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
++                                buf[3] + bias[13]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
++                     MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
++                                buf[3] + bias[14]));
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
++                     MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
++                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
++                                buf[3] + bias[15]));
++
++      return 0;
++}
++
++static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++      u16 tx_amp_cal_val[4];
++
++      tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
++      tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
++      tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
++      tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
++      tx_amp_fill_result(phydev, tx_amp_cal_val);
++
++      return 0;
++}
++
++static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
++                            u8 txg_calen_x)
++{
++      int bias = 0;
++      u16 reg, val;
++
++      if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
++              bias = -1;
++
++      val = clamp_val(bias + tx_r50_cal_val, 0, 63);
++
++      switch (txg_calen_x) {
++      case PAIR_A:
++              reg = MTK_PHY_DA_TX_R50_PAIR_A;
++              break;
++      case PAIR_B:
++              reg = MTK_PHY_DA_TX_R50_PAIR_B;
++              break;
++      case PAIR_C:
++              reg = MTK_PHY_DA_TX_R50_PAIR_C;
++              break;
++      case PAIR_D:
++              reg = MTK_PHY_DA_TX_R50_PAIR_D;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
++
++      return 0;
++}
++
++static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
++                          u8 txg_calen_x)
++{
++      u16 tx_r50_cal_val;
++
++      switch (txg_calen_x) {
++      case PAIR_A:
++              tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
++              break;
++      case PAIR_B:
++              tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
++              break;
++      case PAIR_C:
++              tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
++              break;
++      case PAIR_D:
++              tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
++              break;
++      default:
++              return -EINVAL;
++      }
++      tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
++
++      return 0;
++}
++
++static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
++{
++      u8 lower_idx, upper_idx, txreserve_val;
++      u8 lower_ret, upper_ret;
++      int ret;
++
++      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++                       MTK_PHY_RG_ANA_CALEN);
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++                         MTK_PHY_RG_CAL_CKINV);
++      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++                       MTK_PHY_RG_TXVOS_CALEN);
++
++      switch (rg_txreserve_x) {
++      case PAIR_A:
++              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                                 MTK_PHY_RG_DASN_DAC_IN0_A,
++                                 MTK_PHY_DASN_DAC_IN0_A_MASK);
++              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                                 MTK_PHY_RG_DASN_DAC_IN1_A,
++                                 MTK_PHY_DASN_DAC_IN1_A_MASK);
++              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++                               MTK_PHY_RG_ANA_CAL_RG0,
++                               MTK_PHY_RG_ZCALEN_A);
++              break;
++      case PAIR_B:
++              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                                 MTK_PHY_RG_DASN_DAC_IN0_B,
++                                 MTK_PHY_DASN_DAC_IN0_B_MASK);
++              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                                 MTK_PHY_RG_DASN_DAC_IN1_B,
++                                 MTK_PHY_DASN_DAC_IN1_B_MASK);
++              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++                               MTK_PHY_RG_ANA_CAL_RG1,
++                               MTK_PHY_RG_ZCALEN_B);
++              break;
++      case PAIR_C:
++              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                                 MTK_PHY_RG_DASN_DAC_IN0_C,
++                                 MTK_PHY_DASN_DAC_IN0_C_MASK);
++              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                                 MTK_PHY_RG_DASN_DAC_IN1_C,
++                                 MTK_PHY_DASN_DAC_IN1_C_MASK);
++              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++                               MTK_PHY_RG_ANA_CAL_RG1,
++                               MTK_PHY_RG_ZCALEN_C);
++              break;
++      case PAIR_D:
++              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                                 MTK_PHY_RG_DASN_DAC_IN0_D,
++                                 MTK_PHY_DASN_DAC_IN0_D_MASK);
++              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                                 MTK_PHY_RG_DASN_DAC_IN1_D,
++                                 MTK_PHY_DASN_DAC_IN1_D_MASK);
++              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++                               MTK_PHY_RG_ANA_CAL_RG1,
++                               MTK_PHY_RG_ZCALEN_D);
++              break;
++      default:
++              ret = -EINVAL;
++              goto restore;
++      }
++
++      lower_idx = TXRESERVE_MIN;
++      upper_idx = TXRESERVE_MAX;
++
++      phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
++      while ((upper_idx - lower_idx) > 1) {
++              txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
++              ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++                              MTK_PHY_DA_RX_PSBN_TBT_MASK |
++                              MTK_PHY_DA_RX_PSBN_HBT_MASK |
++                              MTK_PHY_DA_RX_PSBN_GBE_MASK |
++                              MTK_PHY_DA_RX_PSBN_LP_MASK,
++                              txreserve_val << 12 | txreserve_val << 8 |
++                              txreserve_val << 4 | txreserve_val);
++              if (ret == 1) {
++                      upper_idx = txreserve_val;
++                      upper_ret = ret;
++              } else if (ret == 0) {
++                      lower_idx = txreserve_val;
++                      lower_ret = ret;
++              } else {
++                      goto restore;
++              }
++      }
++
++      if (lower_idx == TXRESERVE_MIN) {
++              lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
++                                    MTK_PHY_RXADC_CTRL_RG9,
++                                    MTK_PHY_DA_RX_PSBN_TBT_MASK |
++                                    MTK_PHY_DA_RX_PSBN_HBT_MASK |
++                                    MTK_PHY_DA_RX_PSBN_GBE_MASK |
++                                    MTK_PHY_DA_RX_PSBN_LP_MASK,
++                                    lower_idx << 12 | lower_idx << 8 |
++                                    lower_idx << 4 | lower_idx);
++              ret = lower_ret;
++      } else if (upper_idx == TXRESERVE_MAX) {
++              upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
++                                    MTK_PHY_RXADC_CTRL_RG9,
++                                    MTK_PHY_DA_RX_PSBN_TBT_MASK |
++                                    MTK_PHY_DA_RX_PSBN_HBT_MASK |
++                                    MTK_PHY_DA_RX_PSBN_GBE_MASK |
++                                    MTK_PHY_DA_RX_PSBN_LP_MASK,
++                                    upper_idx << 12 | upper_idx << 8 |
++                                    upper_idx << 4 | upper_idx);
++              ret = upper_ret;
++      }
++      if (ret < 0)
++              goto restore;
++
++      /* We calibrate TX-VCM in different logic. Check upper index and then
++       * lower index. If this calibration is valid, apply lower index's
++       * result.
++       */
++      ret = upper_ret - lower_ret;
++      if (ret == 1) {
++              ret = 0;
++              /* Make sure we use upper_idx in our calibration system */
++              cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++                        MTK_PHY_DA_RX_PSBN_TBT_MASK |
++                        MTK_PHY_DA_RX_PSBN_HBT_MASK |
++                        MTK_PHY_DA_RX_PSBN_GBE_MASK |
++                        MTK_PHY_DA_RX_PSBN_LP_MASK,
++                        upper_idx << 12 | upper_idx << 8 |
++                        upper_idx << 4 | upper_idx);
++              phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
++      } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
++                 lower_ret == 1) {
++              ret = 0;
++              cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++                        MTK_PHY_DA_RX_PSBN_TBT_MASK |
++                        MTK_PHY_DA_RX_PSBN_HBT_MASK |
++                        MTK_PHY_DA_RX_PSBN_GBE_MASK |
++                        MTK_PHY_DA_RX_PSBN_LP_MASK,
++                        lower_idx << 12 | lower_idx << 8 |
++                        lower_idx << 4 | lower_idx);
++              phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
++                          lower_idx);
++      } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
++                 lower_ret == 0) {
++              ret = 0;
++              phydev_warn(phydev,
++                          "TX-VCM SW cal result at high margin 0x%x\n",
++                          upper_idx);
++      } else {
++              ret = -EINVAL;
++      }
++
++restore:
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++                         MTK_PHY_RG_ANA_CALEN);
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++                         MTK_PHY_RG_TXVOS_CALEN);
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++                         MTK_PHY_RG_ZCALEN_A);
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++                         MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
++                         MTK_PHY_RG_ZCALEN_D);
++
++      return ret;
++}
++
++static void mt798x_phy_common_finetune(struct phy_device *phydev)
++{
++      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++      /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
++      __phy_write(phydev, 0x11, 0xc71);
++      __phy_write(phydev, 0x12, 0xc);
++      __phy_write(phydev, 0x10, 0x8fae);
++
++      /* EnabRandUpdTrig = 1 */
++      __phy_write(phydev, 0x11, 0x2f00);
++      __phy_write(phydev, 0x12, 0xe);
++      __phy_write(phydev, 0x10, 0x8fb0);
++
++      /* NormMseLoThresh = 85 */
++      __phy_write(phydev, 0x11, 0x55a0);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x83aa);
++
++      /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
++      __phy_write(phydev, 0x11, 0x240);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x9680);
++
++      /* TrFreeze = 0 (mt7988 default) */
++      __phy_write(phydev, 0x11, 0x0);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x9686);
++
++      /* SSTrKp100 = 5 */
++      /* SSTrKf100 = 6 */
++      /* SSTrKp1000Mas = 5 */
++      /* SSTrKf1000Mas = 6 */
++      /* SSTrKp1000Slv = 5 */
++      /* SSTrKf1000Slv = 6 */
++      __phy_write(phydev, 0x11, 0xbaef);
++      __phy_write(phydev, 0x12, 0x2e);
++      __phy_write(phydev, 0x10, 0x968c);
++      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++}
++
++static void mt7981_phy_finetune(struct phy_device *phydev)
++{
++      u16 val[8] = { 0x01ce, 0x01c1,
++                     0x020f, 0x0202,
++                     0x03d0, 0x03c0,
++                     0x0013, 0x0005 };
++      int i, k;
++
++      /* 100M eye finetune:
++       * Keep middle level of TX MLT3 shapper as default.
++       * Only change TX MLT3 overshoot level here.
++       */
++      for (k = 0, i = 1; i < 12; i++) {
++              if (i % 3 == 0)
++                      continue;
++              phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
++      }
++
++      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++      /* ResetSyncOffset = 6 */
++      __phy_write(phydev, 0x11, 0x600);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x8fc0);
++
++      /* VgaDecRate = 1 */
++      __phy_write(phydev, 0x11, 0x4c2a);
++      __phy_write(phydev, 0x12, 0x3e);
++      __phy_write(phydev, 0x10, 0x8fa4);
++
++      /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
++       * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
++       */
++      __phy_write(phydev, 0x11, 0xd10a);
++      __phy_write(phydev, 0x12, 0x34);
++      __phy_write(phydev, 0x10, 0x8f82);
++
++      /* VcoSlicerThreshBitsHigh */
++      __phy_write(phydev, 0x11, 0x5555);
++      __phy_write(phydev, 0x12, 0x55);
++      __phy_write(phydev, 0x10, 0x8ec0);
++      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++      /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
++                     MTK_PHY_TR_OPEN_LOOP_EN_MASK |
++                     MTK_PHY_LPF_X_AVERAGE_MASK,
++                     BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
++
++      /* rg_tr_lpf_cnt_val = 512 */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
++
++      /* IIR2 related */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
++
++      /* FFE peaking */
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
++                     MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
++                     MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
++
++      /* Disable LDO pump */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
++      /* Adjust LDO output voltage */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
++}
++
++static void mt7988_phy_finetune(struct phy_device *phydev)
++{
++      u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
++                      0x020d, 0x0206, 0x0384, 0x03d0,
++                      0x03c6, 0x030a, 0x0011, 0x0005 };
++      int i;
++
++      /* Set default MLT3 shaper first */
++      for (i = 0; i < 12; i++)
++              phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
++
++      /* TCT finetune */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
++
++      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++      /* ResetSyncOffset = 5 */
++      __phy_write(phydev, 0x11, 0x500);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x8fc0);
++
++      /* VgaDecRate is 1 at default on mt7988 */
++
++      /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
++       * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
++       */
++      __phy_write(phydev, 0x11, 0xb90a);
++      __phy_write(phydev, 0x12, 0x6f);
++      __phy_write(phydev, 0x10, 0x8f82);
++
++      /* RemAckCntLimitCtrl = 1 */
++      __phy_write(phydev, 0x11, 0xfbba);
++      __phy_write(phydev, 0x12, 0xc3);
++      __phy_write(phydev, 0x10, 0x87f8);
++
++      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++      /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
++                     MTK_PHY_TR_OPEN_LOOP_EN_MASK |
++                     MTK_PHY_LPF_X_AVERAGE_MASK,
++                     BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
++
++      /* rg_tr_lpf_cnt_val = 1023 */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
++}
++
++static void mt798x_phy_eee(struct phy_device *phydev)
++{
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
++                     MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
++                     MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
++                     FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
++                     FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
++
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
++                     MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++                     FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++                                0xff));
++
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                         MTK_PHY_RG_TESTMUX_ADC_CTRL,
++                         MTK_PHY_RG_TXEN_DIG_MASK);
++
++      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++                       MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
++
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++                         MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
++
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
++                     MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
++                     MTK_PHY_LPI_SLV_SEND_TX_EN,
++                     FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
++
++      /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
++                         MTK_PHY_LPI_TXPCS_LOC_RCV);
++
++      /* This also fixes some IoT issues, such as CH340 */
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
++                     MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
++                     FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
++                     FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
++
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
++                     MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
++                     FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
++                                0x33) |
++                     MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
++                     MTK_PHY_LPI_VCO_EEE_STG0_EN);
++
++      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
++                       MTK_PHY_EEE_WAKE_MAS_INT_DC |
++                       MTK_PHY_EEE_WAKE_SLV_INT_DC);
++
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
++                     MTK_PHY_SMI_DETCNT_MAX_MASK,
++                     FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
++                     MTK_PHY_SMI_DET_MAX_EN);
++
++      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
++                       MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
++                       MTK_PHY_TREC_UPDATE_ENAB_CLR |
++                       MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
++                       MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
++
++      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++      /* Regsigdet_sel_1000 = 0 */
++      __phy_write(phydev, 0x11, 0xb);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x9690);
++
++      /* REG_EEE_st2TrKf1000 = 2 */
++      __phy_write(phydev, 0x11, 0x114f);
++      __phy_write(phydev, 0x12, 0x2);
++      __phy_write(phydev, 0x10, 0x969a);
++
++      /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
++      __phy_write(phydev, 0x11, 0x3028);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x969e);
++
++      /* RegEEE_slv_wake_int_timer_tar = 8 */
++      __phy_write(phydev, 0x11, 0x5010);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x96a0);
++
++      /* RegEEE_trfreeze_timer2 = 586 */
++      __phy_write(phydev, 0x11, 0x24a);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x96a8);
++
++      /* RegEEE100Stg1_tar = 16 */
++      __phy_write(phydev, 0x11, 0x3210);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x96b8);
++
++      /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
++      __phy_write(phydev, 0x11, 0x1463);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x96ca);
++
++      /* DfeTailEnableVgaThresh1000 = 27 */
++      __phy_write(phydev, 0x11, 0x36);
++      __phy_write(phydev, 0x12, 0x0);
++      __phy_write(phydev, 0x10, 0x8f80);
++      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
++      __phy_modify(phydev, MTK_PHY_LPI_REG_14,
++                   MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
++                   FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
++
++      __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
++                   FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
++      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
++                     MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++                     FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++                                0xff));
++}
++
++static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
++                u8 start_pair, u8 end_pair)
++{
++      u8 pair_n;
++      int ret;
++
++      for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
++              /* TX_OFFSET & TX_AMP have no SW calibration. */
++              switch (cal_item) {
++              case TX_VCM:
++                      ret = tx_vcm_cal_sw(phydev, pair_n);
++                      break;
++              default:
++                      return -EINVAL;
++              }
++              if (ret)
++                      return ret;
++      }
++      return 0;
++}
++
++static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
++                   u8 start_pair, u8 end_pair, u32 *buf)
++{
++      u8 pair_n;
++      int ret;
++
++      for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
++              /* TX_VCM has no efuse calibration. */
++              switch (cal_item) {
++              case REXT:
++                      ret = rext_cal_efuse(phydev, buf);
++                      break;
++              case TX_OFFSET:
++                      ret = tx_offset_cal_efuse(phydev, buf);
++                      break;
++              case TX_AMP:
++                      ret = tx_amp_cal_efuse(phydev, buf);
++                      break;
++              case TX_R50:
++                      ret = tx_r50_cal_efuse(phydev, buf, pair_n);
++                      break;
++              default:
++                      return -EINVAL;
++              }
++              if (ret)
++                      return ret;
++      }
++
++      return 0;
++}
++
++static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
++                   enum CAL_MODE cal_mode, u8 start_pair,
++                   u8 end_pair, u32 *buf)
++{
++      int ret;
++
++      switch (cal_mode) {
++      case EFUSE_M:
++              ret = cal_efuse(phydev, cal_item, start_pair,
++                              end_pair, buf);
++              break;
++      case SW_M:
++              ret = cal_sw(phydev, cal_item, start_pair, end_pair);
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      if (ret) {
++              phydev_err(phydev, "cal %d failed\n", cal_item);
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static int mt798x_phy_calibration(struct phy_device *phydev)
++{
++      struct nvmem_cell *cell;
++      int ret = 0;
++      size_t len;
++      u32 *buf;
++
++      cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
++      if (IS_ERR(cell)) {
++              if (PTR_ERR(cell) == -EPROBE_DEFER)
++                      return PTR_ERR(cell);
++              return 0;
++      }
++
++      buf = (u32 *)nvmem_cell_read(cell, &len);
++      if (IS_ERR(buf))
++              return PTR_ERR(buf);
++      nvmem_cell_put(cell);
++
++      if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
++              phydev_err(phydev, "invalid efuse data\n");
++              ret = -EINVAL;
++              goto out;
++      }
++
++      ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++      if (ret)
++              goto out;
++      ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++      if (ret)
++              goto out;
++      ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++      if (ret)
++              goto out;
++      ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
++      if (ret)
++              goto out;
++      ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
++      if (ret)
++              goto out;
++
++out:
++      kfree(buf);
++      return ret;
++}
++
++static int mt798x_phy_config_init(struct phy_device *phydev)
++{
++      switch (phydev->drv->phy_id) {
++      case MTK_GPHY_ID_MT7981:
++              mt7981_phy_finetune(phydev);
++              break;
++      case MTK_GPHY_ID_MT7988:
++              mt7988_phy_finetune(phydev);
++              break;
++      }
++
++      mt798x_phy_common_finetune(phydev);
++      mt798x_phy_eee(phydev);
++
++      return mt798x_phy_calibration(phydev);
++}
++
++static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
++                                  bool on)
++{
++      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++      struct mtk_socphy_priv *priv = phydev->priv;
++      bool changed;
++
++      if (on)
++              changed = !test_and_set_bit(bit_on, &priv->led_state);
++      else
++              changed = !!test_and_clear_bit(bit_on, &priv->led_state);
++
++      changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
++                                      (index ? 16 : 0), &priv->led_state);
++      if (changed)
++              return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++                                    MTK_PHY_LED1_ON_CTRL :
++                                    MTK_PHY_LED0_ON_CTRL,
++                                    MTK_PHY_LED_ON_MASK,
++                                    on ? MTK_PHY_LED_ON_FORCE_ON : 0);
++      else
++              return 0;
++}
++
++static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
++                                     bool blinking)
++{
++      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++                               (index ? 16 : 0);
++      struct mtk_socphy_priv *priv = phydev->priv;
++      bool changed;
++
++      if (blinking)
++              changed = !test_and_set_bit(bit_blink, &priv->led_state);
++      else
++              changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
++
++      changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
++                            (index ? 16 : 0), &priv->led_state);
++      if (changed)
++              return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++                                   MTK_PHY_LED1_BLINK_CTRL :
++                                   MTK_PHY_LED0_BLINK_CTRL,
++                                   blinking ?
++                                   MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
++      else
++              return 0;
++}
++
++static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
++                                  unsigned long *delay_on,
++                                  unsigned long *delay_off)
++{
++      bool blinking = false;
++      int err = 0;
++
++      if (index > 1)
++              return -EINVAL;
++
++      if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
++              blinking = true;
++              *delay_on = 50;
++              *delay_off = 50;
++      }
++
++      err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
++      if (err)
++              return err;
++
++      return mt798x_phy_hw_led_on_set(phydev, index, false);
++}
++
++static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
++                                       u8 index, enum led_brightness value)
++{
++      int err;
++
++      err = mt798x_phy_hw_led_blink_set(phydev, index, false);
++      if (err)
++              return err;
++
++      return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
++}
++
++static const unsigned long supported_triggers =
++      BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++      BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
++      BIT(TRIGGER_NETDEV_LINK)        |
++      BIT(TRIGGER_NETDEV_LINK_10)     |
++      BIT(TRIGGER_NETDEV_LINK_100)    |
++      BIT(TRIGGER_NETDEV_LINK_1000)   |
++      BIT(TRIGGER_NETDEV_RX)          |
++      BIT(TRIGGER_NETDEV_TX);
++
++static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++                                        unsigned long rules)
++{
++      if (index > 1)
++              return -EINVAL;
++
++      /* All combinations of the supported triggers are allowed */
++      if (rules & ~supported_triggers)
++              return -EOPNOTSUPP;
++
++      return 0;
++};
++
++static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
++                                       unsigned long *rules)
++{
++      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++                               (index ? 16 : 0);
++      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++      struct mtk_socphy_priv *priv = phydev->priv;
++      int on, blink;
++
++      if (index > 1)
++              return -EINVAL;
++
++      on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++                        index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
++
++      if (on < 0)
++              return -EIO;
++
++      blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++                           index ? MTK_PHY_LED1_BLINK_CTRL :
++                                   MTK_PHY_LED0_BLINK_CTRL);
++      if (blink < 0)
++              return -EIO;
++
++      if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
++                 MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
++          (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
++              set_bit(bit_netdev, &priv->led_state);
++      else
++              clear_bit(bit_netdev, &priv->led_state);
++
++      if (on & MTK_PHY_LED_ON_FORCE_ON)
++              set_bit(bit_on, &priv->led_state);
++      else
++              clear_bit(bit_on, &priv->led_state);
++
++      if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
++              set_bit(bit_blink, &priv->led_state);
++      else
++              clear_bit(bit_blink, &priv->led_state);
++
++      if (!rules)
++              return 0;
++
++      if (on & MTK_PHY_LED_ON_LINK)
++              *rules |= BIT(TRIGGER_NETDEV_LINK);
++
++      if (on & MTK_PHY_LED_ON_LINK10)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_10);
++
++      if (on & MTK_PHY_LED_ON_LINK100)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++      if (on & MTK_PHY_LED_ON_LINK1000)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++      if (on & MTK_PHY_LED_ON_FDX)
++              *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
++
++      if (on & MTK_PHY_LED_ON_HDX)
++              *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
++
++      if (blink & MTK_PHY_LED_BLINK_RX)
++              *rules |= BIT(TRIGGER_NETDEV_RX);
++
++      if (blink & MTK_PHY_LED_BLINK_TX)
++              *rules |= BIT(TRIGGER_NETDEV_TX);
++
++      return 0;
++};
++
++static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
++                                       unsigned long rules)
++{
++      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++      struct mtk_socphy_priv *priv = phydev->priv;
++      u16 on = 0, blink = 0;
++      int ret;
++
++      if (index > 1)
++              return -EINVAL;
++
++      if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
++              on |= MTK_PHY_LED_ON_FDX;
++
++      if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
++              on |= MTK_PHY_LED_ON_HDX;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
++              on |= MTK_PHY_LED_ON_LINK10;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
++              on |= MTK_PHY_LED_ON_LINK100;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
++              on |= MTK_PHY_LED_ON_LINK1000;
++
++      if (rules & BIT(TRIGGER_NETDEV_RX)) {
++              blink |= (on & MTK_PHY_LED_ON_LINK) ?
++                        (((on & MTK_PHY_LED_ON_LINK10) ?
++                          MTK_PHY_LED_BLINK_10RX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK100) ?
++                          MTK_PHY_LED_BLINK_100RX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK1000) ?
++                          MTK_PHY_LED_BLINK_1000RX : 0)) :
++                        MTK_PHY_LED_BLINK_RX;
++      }
++
++      if (rules & BIT(TRIGGER_NETDEV_TX)) {
++              blink |= (on & MTK_PHY_LED_ON_LINK) ?
++                        (((on & MTK_PHY_LED_ON_LINK10) ?
++                          MTK_PHY_LED_BLINK_10TX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK100) ?
++                          MTK_PHY_LED_BLINK_100TX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK1000) ?
++                          MTK_PHY_LED_BLINK_1000TX : 0)) :
++                        MTK_PHY_LED_BLINK_TX;
++      }
++
++      if (blink || on)
++              set_bit(bit_netdev, &priv->led_state);
++      else
++              clear_bit(bit_netdev, &priv->led_state);
++
++      ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++                              MTK_PHY_LED1_ON_CTRL :
++                              MTK_PHY_LED0_ON_CTRL,
++                           MTK_PHY_LED_ON_FDX     |
++                           MTK_PHY_LED_ON_HDX     |
++                           MTK_PHY_LED_ON_LINK,
++                           on);
++
++      if (ret)
++              return ret;
++
++      return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++                              MTK_PHY_LED1_BLINK_CTRL :
++                              MTK_PHY_LED0_BLINK_CTRL, blink);
++};
++
++static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
++{
++      struct mtk_socphy_shared *priv = phydev->shared->priv;
++      u32 polarities;
++
++      if (led_num == 0)
++              polarities = ~(priv->boottrap);
++      else
++              polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
++
++      if (polarities & BIT(phydev->mdio.addr))
++              return true;
++
++      return false;
++}
++
++static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
++{
++      struct pinctrl *pinctrl;
++      int index;
++
++      /* Setup LED polarity according to bootstrap use of LED pins */
++      for (index = 0; index < 2; ++index)
++              phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++                              MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++                             MTK_PHY_LED_ON_POLARITY,
++                             mt7988_phy_led_get_polarity(phydev, index) ?
++                              MTK_PHY_LED_ON_POLARITY : 0);
++
++      /* Only now setup pinctrl to avoid bogus blinking */
++      pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
++      if (IS_ERR(pinctrl))
++              dev_err(&phydev->mdio.bus->dev,
++                      "Failed to setup PHY LED pinctrl\n");
++
++      return 0;
++}
++
++static int mt7988_phy_probe_shared(struct phy_device *phydev)
++{
++      struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
++      struct mtk_socphy_shared *shared = phydev->shared->priv;
++      struct regmap *regmap;
++      u32 reg;
++      int ret;
++
++      /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
++       * LED_C and LED_D respectively. At the same time those pins are used to
++       * bootstrap configuration of the reference clock source (LED_A),
++       * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
++       * In practice this is done using a LED and a resistor pulling the pin
++       * either to GND or to VIO.
++       * The detected value at boot time is accessible at run-time using the
++       * TPBANK0 register located in the gpio base of the pinctrl, in order
++       * to read it here it needs to be referenced by a phandle called
++       * 'mediatek,pio' in the MDIO bus hosting the PHY.
++       * The 4 bits in TPBANK0 are kept as package shared data and are used to
++       * set LED polarity for each of the LED0.
++       */
++      regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
++      if (IS_ERR(regmap))
++              return PTR_ERR(regmap);
++
++      ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, &reg);
++      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 <[email protected]>");
++MODULE_AUTHOR("SkyLake Huang <[email protected]>");
++MODULE_LICENSE("GPL");
++
++MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -0,0 +1,111 @@
++// SPDX-License-Identifier: GPL-2.0+
++#include <linux/bitfield.h>
++#include <linux/module.h>
++#include <linux/phy.h>
++
++#define MTK_EXT_PAGE_ACCESS           0x1f
++#define MTK_PHY_PAGE_STANDARD         0x0000
++#define MTK_PHY_PAGE_EXTENDED         0x0001
++#define MTK_PHY_PAGE_EXTENDED_2               0x0002
++#define MTK_PHY_PAGE_EXTENDED_3               0x0003
++#define MTK_PHY_PAGE_EXTENDED_2A30    0x2a30
++#define MTK_PHY_PAGE_EXTENDED_52B5    0x52b5
++
++static int mtk_gephy_read_page(struct phy_device *phydev)
++{
++      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++
++static int mtk_gephy_write_page(struct phy_device *phydev, int page)
++{
++      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++
++static void mtk_gephy_config_init(struct phy_device *phydev)
++{
++      /* Enable HW auto downshift */
++      phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
++
++      /* Increase SlvDPSready time */
++      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++      __phy_write(phydev, 0x10, 0xafae);
++      __phy_write(phydev, 0x12, 0x2f);
++      __phy_write(phydev, 0x10, 0x8fae);
++      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++      /* Adjust 100_mse_threshold */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
++
++      /* Disable mcc */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
++}
++
++static int mt7530_phy_config_init(struct phy_device *phydev)
++{
++      mtk_gephy_config_init(phydev);
++
++      /* Increase post_update_timer */
++      phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
++
++      return 0;
++}
++
++static int mt7531_phy_config_init(struct phy_device *phydev)
++{
++      mtk_gephy_config_init(phydev);
++
++      /* PHY link down power saving enable */
++      phy_set_bits(phydev, 0x17, BIT(4));
++      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
++
++      /* Set TX Pair delay selection */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
++
++      return 0;
++}
++
++static struct phy_driver mtk_gephy_driver[] = {
++      {
++              PHY_ID_MATCH_EXACT(0x03a29412),
++              .name           = "MediaTek MT7530 PHY",
++              .config_init    = mt7530_phy_config_init,
++              /* Interrupts are handled by the switch, not the PHY
++               * itself.
++               */
++              .config_intr    = genphy_no_config_intr,
++              .handle_interrupt = genphy_handle_interrupt_no_ack,
++              .suspend        = genphy_suspend,
++              .resume         = genphy_resume,
++              .read_page      = mtk_gephy_read_page,
++              .write_page     = mtk_gephy_write_page,
++      },
++      {
++              PHY_ID_MATCH_EXACT(0x03a29441),
++              .name           = "MediaTek MT7531 PHY",
++              .config_init    = mt7531_phy_config_init,
++              /* Interrupts are handled by the switch, not the PHY
++               * itself.
++               */
++              .config_intr    = genphy_no_config_intr,
++              .handle_interrupt = genphy_handle_interrupt_no_ack,
++              .suspend        = genphy_suspend,
++              .resume         = genphy_resume,
++              .read_page      = mtk_gephy_read_page,
++              .write_page     = mtk_gephy_write_page,
++      },
++};
++
++module_phy_driver(mtk_gephy_driver);
++
++static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
++      { PHY_ID_MATCH_EXACT(0x03a29441) },
++      { PHY_ID_MATCH_EXACT(0x03a29412) },
++      { }
++};
++
++MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
++MODULE_AUTHOR("DENG, Qingfang <[email protected]>");
++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 (file)
index 0000000..63407ac
--- /dev/null
@@ -0,0 +1,774 @@
+From 71d88c7409b91c853d7f9c933f5e27933d656e5e Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <[email protected]>
+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 <[email protected]>
+Signed-off-by: SkyLake.Huang <[email protected]>
+Signed-off-by: David S. Miller <[email protected]>
+---
+ MAINTAINERS                            |   2 +
+ drivers/net/phy/mediatek/Kconfig       |   4 +
+ drivers/net/phy/mediatek/Makefile      |   1 +
+ drivers/net/phy/mediatek/mtk-ge-soc.c  | 280 +++----------------------
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 254 ++++++++++++++++++++++
+ drivers/net/phy/mediatek/mtk.h         |  86 ++++++++
+ 6 files changed, 372 insertions(+), 255 deletions(-)
+ create mode 100644 drivers/net/phy/mediatek/mtk-phy-lib.c
+ create mode 100644 drivers/net/phy/mediatek/mtk.h
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -14428,7 +14428,9 @@ M:     SkyLake Huang <SkyLake.Huang@mediatek
+ L:    [email protected]
+ S:    Maintained
+ F:    drivers/net/phy/mediatek/mtk-ge-soc.c
++F:    drivers/net/phy/mediatek/mtk-phy-lib.c
+ F:    drivers/net/phy/mediatek/mtk-ge.c
++F:    drivers/net/phy/mediatek/mtk.h
+ F:    drivers/phy/mediatek/phy-mtk-xfi-tphy.c
+ MEDIATEK I2C CONTROLLER DRIVER
+--- a/drivers/net/phy/mediatek/Kconfig
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -1,4 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0-only
++config MTK_NET_PHYLIB
++      tristate
++
+ config MEDIATEK_GE_PHY
+       tristate "MediaTek Gigabit Ethernet PHYs"
+       help
+@@ -13,6 +16,7 @@ config MEDIATEK_GE_SOC_PHY
+       tristate "MediaTek SoC Ethernet PHYs"
+       depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
+       depends on NVMEM_MTK_EFUSE
++      select MTK_NET_PHYLIB
+       help
+         Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+--- a/drivers/net/phy/mediatek/Makefile
++++ b/drivers/net/phy/mediatek/Makefile
+@@ -1,3 +1,4 @@
+ # SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_MTK_NET_PHYLIB)          += mtk-phy-lib.o
+ obj-$(CONFIG_MEDIATEK_GE_PHY)         += mtk-ge.o
+ obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)     += mtk-ge-soc.o
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -8,6 +8,8 @@
+ #include <linux/phy.h>
+ #include <linux/regmap.h>
++#include "mtk.h"
++
+ #define MTK_GPHY_ID_MT7981                    0x03a29461
+ #define MTK_GPHY_ID_MT7988                    0x03a29481
+@@ -210,41 +212,6 @@
+ #define MTK_PHY_DA_TX_R50_PAIR_D              0x540
+ /* Registers on MDIO_MMD_VEND2 */
+-#define MTK_PHY_LED0_ON_CTRL                  0x24
+-#define MTK_PHY_LED1_ON_CTRL                  0x26
+-#define   MTK_PHY_LED_ON_MASK                 GENMASK(6, 0)
+-#define   MTK_PHY_LED_ON_LINK1000             BIT(0)
+-#define   MTK_PHY_LED_ON_LINK100              BIT(1)
+-#define   MTK_PHY_LED_ON_LINK10                       BIT(2)
+-#define   MTK_PHY_LED_ON_LINK                 (MTK_PHY_LED_ON_LINK10 |\
+-                                               MTK_PHY_LED_ON_LINK100 |\
+-                                               MTK_PHY_LED_ON_LINK1000)
+-#define   MTK_PHY_LED_ON_LINKDOWN             BIT(3)
+-#define   MTK_PHY_LED_ON_FDX                  BIT(4) /* Full duplex */
+-#define   MTK_PHY_LED_ON_HDX                  BIT(5) /* Half duplex */
+-#define   MTK_PHY_LED_ON_FORCE_ON             BIT(6)
+-#define   MTK_PHY_LED_ON_POLARITY             BIT(14)
+-#define   MTK_PHY_LED_ON_ENABLE                       BIT(15)
+-
+-#define MTK_PHY_LED0_BLINK_CTRL                       0x25
+-#define MTK_PHY_LED1_BLINK_CTRL                       0x27
+-#define   MTK_PHY_LED_BLINK_1000TX            BIT(0)
+-#define   MTK_PHY_LED_BLINK_1000RX            BIT(1)
+-#define   MTK_PHY_LED_BLINK_100TX             BIT(2)
+-#define   MTK_PHY_LED_BLINK_100RX             BIT(3)
+-#define   MTK_PHY_LED_BLINK_10TX              BIT(4)
+-#define   MTK_PHY_LED_BLINK_10RX              BIT(5)
+-#define   MTK_PHY_LED_BLINK_RX                        (MTK_PHY_LED_BLINK_10RX |\
+-                                               MTK_PHY_LED_BLINK_100RX |\
+-                                               MTK_PHY_LED_BLINK_1000RX)
+-#define   MTK_PHY_LED_BLINK_TX                        (MTK_PHY_LED_BLINK_10TX |\
+-                                               MTK_PHY_LED_BLINK_100TX |\
+-                                               MTK_PHY_LED_BLINK_1000TX)
+-#define   MTK_PHY_LED_BLINK_COLLISION         BIT(6)
+-#define   MTK_PHY_LED_BLINK_RX_CRC_ERR                BIT(7)
+-#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR               BIT(8)
+-#define   MTK_PHY_LED_BLINK_FORCE_BLINK               BIT(9)
+-
+ #define MTK_PHY_LED1_DEFAULT_POLARITIES               BIT(1)
+ #define MTK_PHY_RG_BG_RASEL                   0x115
+@@ -299,14 +266,6 @@ enum CAL_MODE {
+       SW_M
+ };
+-#define MTK_PHY_LED_STATE_FORCE_ON    0
+-#define MTK_PHY_LED_STATE_FORCE_BLINK 1
+-#define MTK_PHY_LED_STATE_NETDEV      2
+-
+-struct mtk_socphy_priv {
+-      unsigned long           led_state;
+-};
+-
+ struct mtk_socphy_shared {
+       u32                     boottrap;
+       struct mtk_socphy_priv  priv[4];
+@@ -1172,76 +1131,23 @@ static int mt798x_phy_config_init(struct
+       return mt798x_phy_calibration(phydev);
+ }
+-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+-                                  bool on)
+-{
+-      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+-      struct mtk_socphy_priv *priv = phydev->priv;
+-      bool changed;
+-
+-      if (on)
+-              changed = !test_and_set_bit(bit_on, &priv->led_state);
+-      else
+-              changed = !!test_and_clear_bit(bit_on, &priv->led_state);
+-
+-      changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
+-                                      (index ? 16 : 0), &priv->led_state);
+-      if (changed)
+-              return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-                                    MTK_PHY_LED1_ON_CTRL :
+-                                    MTK_PHY_LED0_ON_CTRL,
+-                                    MTK_PHY_LED_ON_MASK,
+-                                    on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+-      else
+-              return 0;
+-}
+-
+-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+-                                     bool blinking)
+-{
+-      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+-                               (index ? 16 : 0);
+-      struct mtk_socphy_priv *priv = phydev->priv;
+-      bool changed;
+-
+-      if (blinking)
+-              changed = !test_and_set_bit(bit_blink, &priv->led_state);
+-      else
+-              changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
+-
+-      changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
+-                            (index ? 16 : 0), &priv->led_state);
+-      if (changed)
+-              return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+-                                   MTK_PHY_LED1_BLINK_CTRL :
+-                                   MTK_PHY_LED0_BLINK_CTRL,
+-                                   blinking ?
+-                                   MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+-      else
+-              return 0;
+-}
+-
+ static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
+                                   unsigned long *delay_on,
+                                   unsigned long *delay_off)
+ {
+       bool blinking = false;
+-      int err = 0;
+-
+-      if (index > 1)
+-              return -EINVAL;
++      int err;
+-      if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+-              blinking = true;
+-              *delay_on = 50;
+-              *delay_off = 50;
+-      }
++      err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
++      if (err < 0)
++              return err;
+-      err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
++      err = mtk_phy_hw_led_blink_set(phydev, index, blinking);
+       if (err)
+               return err;
+-      return mt798x_phy_hw_led_on_set(phydev, index, false);
++      return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
++                                   false);
+ }
+ static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
+@@ -1249,11 +1155,12 @@ static int mt798x_phy_led_brightness_set
+ {
+       int err;
+-      err = mt798x_phy_hw_led_blink_set(phydev, index, false);
++      err = mtk_phy_hw_led_blink_set(phydev, index, false);
+       if (err)
+               return err;
+-      return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
++      return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
++                                   (value != LED_OFF));
+ }
+ static const unsigned long supported_triggers =
+@@ -1269,155 +1176,26 @@ static const unsigned long supported_tri
+ static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+                                         unsigned long rules)
+ {
+-      if (index > 1)
+-              return -EINVAL;
+-
+-      /* All combinations of the supported triggers are allowed */
+-      if (rules & ~supported_triggers)
+-              return -EOPNOTSUPP;
+-
+-      return 0;
+-};
++      return mtk_phy_led_hw_is_supported(phydev, index, rules,
++                                         supported_triggers);
++}
+ static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+                                        unsigned long *rules)
+ {
+-      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+-                               (index ? 16 : 0);
+-      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+-      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+-      struct mtk_socphy_priv *priv = phydev->priv;
+-      int on, blink;
+-
+-      if (index > 1)
+-              return -EINVAL;
+-
+-      on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+-                        index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
+-
+-      if (on < 0)
+-              return -EIO;
+-
+-      blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+-                           index ? MTK_PHY_LED1_BLINK_CTRL :
+-                                   MTK_PHY_LED0_BLINK_CTRL);
+-      if (blink < 0)
+-              return -EIO;
+-
+-      if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
+-                 MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
+-          (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
+-              set_bit(bit_netdev, &priv->led_state);
+-      else
+-              clear_bit(bit_netdev, &priv->led_state);
+-
+-      if (on & MTK_PHY_LED_ON_FORCE_ON)
+-              set_bit(bit_on, &priv->led_state);
+-      else
+-              clear_bit(bit_on, &priv->led_state);
+-
+-      if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
+-              set_bit(bit_blink, &priv->led_state);
+-      else
+-              clear_bit(bit_blink, &priv->led_state);
+-
+-      if (!rules)
+-              return 0;
+-
+-      if (on & MTK_PHY_LED_ON_LINK)
+-              *rules |= BIT(TRIGGER_NETDEV_LINK);
+-
+-      if (on & MTK_PHY_LED_ON_LINK10)
+-              *rules |= BIT(TRIGGER_NETDEV_LINK_10);
+-
+-      if (on & MTK_PHY_LED_ON_LINK100)
+-              *rules |= BIT(TRIGGER_NETDEV_LINK_100);
+-
+-      if (on & MTK_PHY_LED_ON_LINK1000)
+-              *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+-
+-      if (on & MTK_PHY_LED_ON_FDX)
+-              *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+-
+-      if (on & MTK_PHY_LED_ON_HDX)
+-              *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
+-
+-      if (blink & MTK_PHY_LED_BLINK_RX)
+-              *rules |= BIT(TRIGGER_NETDEV_RX);
+-
+-      if (blink & MTK_PHY_LED_BLINK_TX)
+-              *rules |= BIT(TRIGGER_NETDEV_TX);
+-
+-      return 0;
++      return mtk_phy_led_hw_ctrl_get(phydev, index, rules,
++                                     MTK_GPHY_LED_ON_SET,
++                                     MTK_GPHY_LED_RX_BLINK_SET,
++                                     MTK_GPHY_LED_TX_BLINK_SET);
+ };
+ static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
+                                        unsigned long rules)
+ {
+-      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+-      struct mtk_socphy_priv *priv = phydev->priv;
+-      u16 on = 0, blink = 0;
+-      int ret;
+-
+-      if (index > 1)
+-              return -EINVAL;
+-
+-      if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+-              on |= MTK_PHY_LED_ON_FDX;
+-
+-      if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
+-              on |= MTK_PHY_LED_ON_HDX;
+-
+-      if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
+-              on |= MTK_PHY_LED_ON_LINK10;
+-
+-      if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+-              on |= MTK_PHY_LED_ON_LINK100;
+-
+-      if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+-              on |= MTK_PHY_LED_ON_LINK1000;
+-
+-      if (rules & BIT(TRIGGER_NETDEV_RX)) {
+-              blink |= (on & MTK_PHY_LED_ON_LINK) ?
+-                        (((on & MTK_PHY_LED_ON_LINK10) ?
+-                          MTK_PHY_LED_BLINK_10RX : 0) |
+-                         ((on & MTK_PHY_LED_ON_LINK100) ?
+-                          MTK_PHY_LED_BLINK_100RX : 0) |
+-                         ((on & MTK_PHY_LED_ON_LINK1000) ?
+-                          MTK_PHY_LED_BLINK_1000RX : 0)) :
+-                        MTK_PHY_LED_BLINK_RX;
+-      }
+-
+-      if (rules & BIT(TRIGGER_NETDEV_TX)) {
+-              blink |= (on & MTK_PHY_LED_ON_LINK) ?
+-                        (((on & MTK_PHY_LED_ON_LINK10) ?
+-                          MTK_PHY_LED_BLINK_10TX : 0) |
+-                         ((on & MTK_PHY_LED_ON_LINK100) ?
+-                          MTK_PHY_LED_BLINK_100TX : 0) |
+-                         ((on & MTK_PHY_LED_ON_LINK1000) ?
+-                          MTK_PHY_LED_BLINK_1000TX : 0)) :
+-                        MTK_PHY_LED_BLINK_TX;
+-      }
+-
+-      if (blink || on)
+-              set_bit(bit_netdev, &priv->led_state);
+-      else
+-              clear_bit(bit_netdev, &priv->led_state);
+-
+-      ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-                              MTK_PHY_LED1_ON_CTRL :
+-                              MTK_PHY_LED0_ON_CTRL,
+-                           MTK_PHY_LED_ON_FDX     |
+-                           MTK_PHY_LED_ON_HDX     |
+-                           MTK_PHY_LED_ON_LINK,
+-                           on);
+-
+-      if (ret)
+-              return ret;
+-
+-      return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+-                              MTK_PHY_LED1_BLINK_CTRL :
+-                              MTK_PHY_LED0_BLINK_CTRL, blink);
++      return mtk_phy_led_hw_ctrl_set(phydev, index, rules,
++                                     MTK_GPHY_LED_ON_SET,
++                                     MTK_GPHY_LED_RX_BLINK_SET,
++                                     MTK_GPHY_LED_TX_BLINK_SET);
+ };
+ static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
+@@ -1492,14 +1270,6 @@ static int mt7988_phy_probe_shared(struc
+       return 0;
+ }
+-static void mt798x_phy_leds_state_init(struct phy_device *phydev)
+-{
+-      int i;
+-
+-      for (i = 0; i < 2; ++i)
+-              mt798x_phy_led_hw_control_get(phydev, i, NULL);
+-}
+-
+ static int mt7988_phy_probe(struct phy_device *phydev)
+ {
+       struct mtk_socphy_shared *shared;
+@@ -1525,7 +1295,7 @@ static int mt7988_phy_probe(struct phy_d
+       phydev->priv = priv;
+-      mt798x_phy_leds_state_init(phydev);
++      mtk_phy_leds_state_init(phydev);
+       err = mt7988_phy_fix_leds_polarities(phydev);
+       if (err)
+@@ -1552,7 +1322,7 @@ static int mt7981_phy_probe(struct phy_d
+       phydev->priv = priv;
+-      mt798x_phy_leds_state_init(phydev);
++      mtk_phy_leds_state_init(phydev);
+       return mt798x_phy_calibration(phydev);
+ }
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -0,0 +1,254 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <linux/phy.h>
++#include <linux/module.h>
++
++#include <linux/netdevice.h>
++
++#include "mtk.h"
++
++int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++                              unsigned long rules,
++                              unsigned long supported_triggers)
++{
++      if (index > 1)
++              return -EINVAL;
++
++      /* All combinations of the supported triggers are allowed */
++      if (rules & ~supported_triggers)
++              return -EOPNOTSUPP;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
++
++int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
++                          unsigned long *rules, u16 on_set,
++                          u16 rx_blink_set, u16 tx_blink_set)
++{
++      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++                               (index ? 16 : 0);
++      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++      struct mtk_socphy_priv *priv = phydev->priv;
++      int on, blink;
++
++      if (index > 1)
++              return -EINVAL;
++
++      on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++                        index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
++
++      if (on < 0)
++              return -EIO;
++
++      blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++                           index ? MTK_PHY_LED1_BLINK_CTRL :
++                                   MTK_PHY_LED0_BLINK_CTRL);
++      if (blink < 0)
++              return -EIO;
++
++      if ((on & (on_set | MTK_PHY_LED_ON_FDX |
++                 MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
++          (blink & (rx_blink_set | tx_blink_set)))
++              set_bit(bit_netdev, &priv->led_state);
++      else
++              clear_bit(bit_netdev, &priv->led_state);
++
++      if (on & MTK_PHY_LED_ON_FORCE_ON)
++              set_bit(bit_on, &priv->led_state);
++      else
++              clear_bit(bit_on, &priv->led_state);
++
++      if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
++              set_bit(bit_blink, &priv->led_state);
++      else
++              clear_bit(bit_blink, &priv->led_state);
++
++      if (!rules)
++              return 0;
++
++      if (on & on_set)
++              *rules |= BIT(TRIGGER_NETDEV_LINK);
++
++      if (on & MTK_PHY_LED_ON_LINK10)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_10);
++
++      if (on & MTK_PHY_LED_ON_LINK100)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++      if (on & MTK_PHY_LED_ON_LINK1000)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++      if (on & MTK_PHY_LED_ON_LINK2500)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
++
++      if (on & MTK_PHY_LED_ON_FDX)
++              *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
++
++      if (on & MTK_PHY_LED_ON_HDX)
++              *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
++
++      if (blink & rx_blink_set)
++              *rules |= BIT(TRIGGER_NETDEV_RX);
++
++      if (blink & tx_blink_set)
++              *rules |= BIT(TRIGGER_NETDEV_TX);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
++
++int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
++                          unsigned long rules, u16 on_set,
++                          u16 rx_blink_set, u16 tx_blink_set)
++{
++      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++      struct mtk_socphy_priv *priv = phydev->priv;
++      u16 on = 0, blink = 0;
++      int ret;
++
++      if (index > 1)
++              return -EINVAL;
++
++      if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
++              on |= MTK_PHY_LED_ON_FDX;
++
++      if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
++              on |= MTK_PHY_LED_ON_HDX;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
++              on |= MTK_PHY_LED_ON_LINK10;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
++              on |= MTK_PHY_LED_ON_LINK100;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
++              on |= MTK_PHY_LED_ON_LINK1000;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
++              on |= MTK_PHY_LED_ON_LINK2500;
++
++      if (rules & BIT(TRIGGER_NETDEV_RX)) {
++              blink |= (on & on_set) ?
++                        (((on & MTK_PHY_LED_ON_LINK10) ?
++                          MTK_PHY_LED_BLINK_10RX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK100) ?
++                          MTK_PHY_LED_BLINK_100RX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK1000) ?
++                          MTK_PHY_LED_BLINK_1000RX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK2500) ?
++                          MTK_PHY_LED_BLINK_2500RX : 0)) :
++                        rx_blink_set;
++      }
++
++      if (rules & BIT(TRIGGER_NETDEV_TX)) {
++              blink |= (on & on_set) ?
++                        (((on & MTK_PHY_LED_ON_LINK10) ?
++                          MTK_PHY_LED_BLINK_10TX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK100) ?
++                          MTK_PHY_LED_BLINK_100TX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK1000) ?
++                          MTK_PHY_LED_BLINK_1000TX : 0) |
++                         ((on & MTK_PHY_LED_ON_LINK2500) ?
++                          MTK_PHY_LED_BLINK_2500TX : 0)) :
++                        tx_blink_set;
++      }
++
++      if (blink || on)
++              set_bit(bit_netdev, &priv->led_state);
++      else
++              clear_bit(bit_netdev, &priv->led_state);
++
++      ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++                           MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++                           MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
++                           on);
++
++      if (ret)
++              return ret;
++
++      return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++                           MTK_PHY_LED1_BLINK_CTRL :
++                           MTK_PHY_LED0_BLINK_CTRL, blink);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
++
++int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
++                          unsigned long *delay_off, bool *blinking)
++{
++      if (index > 1)
++              return -EINVAL;
++
++      if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
++              *blinking = true;
++              *delay_on = 50;
++              *delay_off = 50;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
++
++int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
++                        u16 led_on_mask, bool on)
++{
++      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++      struct mtk_socphy_priv *priv = phydev->priv;
++      bool changed;
++
++      if (on)
++              changed = !test_and_set_bit(bit_on, &priv->led_state);
++      else
++              changed = !!test_and_clear_bit(bit_on, &priv->led_state);
++
++      changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
++                                      (index ? 16 : 0), &priv->led_state);
++      if (changed)
++              return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++                                    MTK_PHY_LED1_ON_CTRL :
++                                    MTK_PHY_LED0_ON_CTRL,
++                                    led_on_mask,
++                                    on ? MTK_PHY_LED_ON_FORCE_ON : 0);
++      else
++              return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
++
++int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking)
++{
++      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++                               (index ? 16 : 0);
++      struct mtk_socphy_priv *priv = phydev->priv;
++      bool changed;
++
++      if (blinking)
++              changed = !test_and_set_bit(bit_blink, &priv->led_state);
++      else
++              changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
++
++      changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
++                            (index ? 16 : 0), &priv->led_state);
++      if (changed)
++              return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++                                   MTK_PHY_LED1_BLINK_CTRL :
++                                   MTK_PHY_LED0_BLINK_CTRL,
++                                   blinking ?
++                                   MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
++      else
++              return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
++
++void mtk_phy_leds_state_init(struct phy_device *phydev)
++{
++      int i;
++
++      for (i = 0; i < 2; ++i)
++              phydev->drv->led_hw_control_get(phydev, i, NULL);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
++
++MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
++MODULE_AUTHOR("Sky Huang <[email protected]>");
++MODULE_AUTHOR("Daniel Golle <[email protected]>");
++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 <[email protected]>
++ * 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 (file)
index 0000000..19f3a84
--- /dev/null
@@ -0,0 +1,72 @@
+From 3efd0595fc7aaae300f5d9f4f0ae86f432c8d2c7 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <[email protected]>
+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 <[email protected]>
+Signed-off-by: SkyLake.Huang <[email protected]>
+Signed-off-by: David S. Miller <[email protected]>
+---
+ 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 (file)
index 0000000..a5828bc
--- /dev/null
@@ -0,0 +1,153 @@
+From 50a97d716105a5f35aaecca0bdfe8e23cba0e87f Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <[email protected]>
+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 <[email protected]>
+Signed-off-by: David S. Miller <[email protected]>
+---
+ drivers/net/phy/mediatek/Kconfig       |  1 +
+ drivers/net/phy/mediatek/mtk-ge-soc.c  | 18 ++++--------------
+ drivers/net/phy/mediatek/mtk-ge.c      | 20 ++++++--------------
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 12 ++++++++++++
+ drivers/net/phy/mediatek/mtk.h         |  3 +++
+ 5 files changed, 26 insertions(+), 28 deletions(-)
+
+--- a/drivers/net/phy/mediatek/Kconfig
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -4,6 +4,7 @@ config MTK_NET_PHYLIB
+ config MEDIATEK_GE_PHY
+       tristate "MediaTek Gigabit Ethernet PHYs"
++      select MTK_NET_PHYLIB
+       help
+         Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -271,16 +271,6 @@ struct mtk_socphy_shared {
+       struct mtk_socphy_priv  priv[4];
+ };
+-static int mtk_socphy_read_page(struct phy_device *phydev)
+-{
+-      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_socphy_write_page(struct phy_device *phydev, int page)
+-{
+-      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+ /* One calibration cycle consists of:
+  * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
+  *   until AD_CAL_COMP is ready to output calibration result.
+@@ -1337,8 +1327,8 @@ static struct phy_driver mtk_socphy_driv
+               .probe          = mt7981_phy_probe,
+               .suspend        = genphy_suspend,
+               .resume         = genphy_resume,
+-              .read_page      = mtk_socphy_read_page,
+-              .write_page     = mtk_socphy_write_page,
++              .read_page      = mtk_phy_read_page,
++              .write_page     = mtk_phy_write_page,
+               .led_blink_set  = mt798x_phy_led_blink_set,
+               .led_brightness_set = mt798x_phy_led_brightness_set,
+               .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+@@ -1354,8 +1344,8 @@ static struct phy_driver mtk_socphy_driv
+               .probe          = mt7988_phy_probe,
+               .suspend        = genphy_suspend,
+               .resume         = genphy_resume,
+-              .read_page      = mtk_socphy_read_page,
+-              .write_page     = mtk_socphy_write_page,
++              .read_page      = mtk_phy_read_page,
++              .write_page     = mtk_phy_write_page,
+               .led_blink_set  = mt798x_phy_led_blink_set,
+               .led_brightness_set = mt798x_phy_led_brightness_set,
+               .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -3,6 +3,8 @@
+ #include <linux/module.h>
+ #include <linux/phy.h>
++#include "mtk.h"
++
+ #define MTK_EXT_PAGE_ACCESS           0x1f
+ #define MTK_PHY_PAGE_STANDARD         0x0000
+ #define MTK_PHY_PAGE_EXTENDED         0x0001
+@@ -11,16 +13,6 @@
+ #define MTK_PHY_PAGE_EXTENDED_2A30    0x2a30
+ #define MTK_PHY_PAGE_EXTENDED_52B5    0x52b5
+-static int mtk_gephy_read_page(struct phy_device *phydev)
+-{
+-      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_gephy_write_page(struct phy_device *phydev, int page)
+-{
+-      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+ static void mtk_gephy_config_init(struct phy_device *phydev)
+ {
+       /* Enable HW auto downshift */
+@@ -77,8 +69,8 @@ static struct phy_driver mtk_gephy_drive
+               .handle_interrupt = genphy_handle_interrupt_no_ack,
+               .suspend        = genphy_suspend,
+               .resume         = genphy_resume,
+-              .read_page      = mtk_gephy_read_page,
+-              .write_page     = mtk_gephy_write_page,
++              .read_page      = mtk_phy_read_page,
++              .write_page     = mtk_phy_write_page,
+       },
+       {
+               PHY_ID_MATCH_EXACT(0x03a29441),
+@@ -91,8 +83,8 @@ static struct phy_driver mtk_gephy_drive
+               .handle_interrupt = genphy_handle_interrupt_no_ack,
+               .suspend        = genphy_suspend,
+               .resume         = genphy_resume,
+-              .read_page      = mtk_gephy_read_page,
+-              .write_page     = mtk_gephy_write_page,
++              .read_page      = mtk_phy_read_page,
++              .write_page     = mtk_phy_write_page,
+       },
+ };
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -6,6 +6,18 @@
+ #include "mtk.h"
++int mtk_phy_read_page(struct phy_device *phydev)
++{
++      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_read_page);
++
++int mtk_phy_write_page(struct phy_device *phydev, int page)
++{
++      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_write_page);
++
+ int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+                               unsigned long rules,
+                               unsigned long supported_triggers)
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -66,6 +66,9 @@ struct mtk_socphy_priv {
+       unsigned long           led_state;
+ };
++int mtk_phy_read_page(struct phy_device *phydev);
++int mtk_phy_write_page(struct phy_device *phydev, int page);
++
+ int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+                               unsigned long rules,
+                               unsigned long supported_triggers);
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 (file)
index 0000000..1c87384
--- /dev/null
@@ -0,0 +1,56 @@
+From e6579df175d5b1baa605c82f8e759542262637cf Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <[email protected]>
+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 <[email protected]>
+Signed-off-by: SkyLake.Huang <[email protected]>
+Signed-off-by: David S. Miller <[email protected]>
+---
+ 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 (file)
index 0000000..669b58d
--- /dev/null
@@ -0,0 +1,700 @@
+From e127f7380aaf2cd1614961d826a4af7ab297d37f Mon Sep 17 00:00:00 2001
+From: Christophe JAILLET <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/403c381b7d9156b67ad68ffc44b8eee70c5e86a9.1736691226.git.christophe.jaillet@wanadoo.fr
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..545e929
--- /dev/null
@@ -0,0 +1,146 @@
+From 7e06c3dbfa5f1e39eba92eb79d854fab2a7ad5fe Mon Sep 17 00:00:00 2001
+From: Sky Huang <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..40ce29f
--- /dev/null
@@ -0,0 +1,448 @@
+From 6e7370079669b0d55c9464bb7c3fb8fb7368b912 Mon Sep 17 00:00:00 2001
+From: Sky Huang <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..972a9c0
--- /dev/null
@@ -0,0 +1,73 @@
+From c7e2fb3421ef5ebbb4c91f44bd735ab10edd755a Mon Sep 17 00:00:00 2001
+From: Sky Huang <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..47d891e
--- /dev/null
@@ -0,0 +1,122 @@
+From 7851c73a416b15aff6f9ada9c88affc5f48ff011 Mon Sep 17 00:00:00 2001
+From: Sky Huang <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..858de09
--- /dev/null
@@ -0,0 +1,45 @@
+From bae8c61522c4d5a5250a24dcb57d120ea593fab1 Mon Sep 17 00:00:00 2001
+From: Sky Huang <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..9778ea1
--- /dev/null
@@ -0,0 +1,37 @@
+From e5566162af8b9690e096d2e6089e4ed955a0d13d Mon Sep 17 00:00:00 2001
+From: Christian Marangi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Signed-off-by: Christian Marangi <[email protected]>
+Acked-by: Arnd Bergmann <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..5498ecb
--- /dev/null
@@ -0,0 +1,129 @@
+From 4590c8bc10951feee3e439bf7fff1b458c2e6fad Mon Sep 17 00:00:00 2001
+From: Christian Marangi <[email protected]>
+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 <[email protected]>
+Signed-off-by: Christian Marangi <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..1b1dda2
--- /dev/null
@@ -0,0 +1,40 @@
+From 34501d047ac0a6cbb13285ba9d15f75c1deb7da7 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <[email protected]>
+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 <[email protected]>
+Fixes: 6a325aed130b ("net: phy: mediatek: add Airoha PHY ID to SoC driver")
+Signed-off-by: Christian Marangi <[email protected]>
+Link: https://patch.msgid.link/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 25bd96f..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-From 277f96c1f3f71d6e1d3bcf650d7cd84c1442210f Mon Sep 17 00:00:00 2001
-From: "SkyLake.Huang" <[email protected]>
-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 <[email protected]>
-Reviewed-by: Simon Horman <[email protected]>
-Signed-off-by: Andrew Lunn <[email protected]>
----
- 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 (file)
index 0000000..2ca3f2e
--- /dev/null
@@ -0,0 +1,157 @@
+From 952d7325362ffbefa6ce5619fb4e53c2159ec7a7 Mon Sep 17 00:00:00 2001
+From: Qingfang Deng <[email protected]>
+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 <[email protected]>
+---
+ 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 (file)
index fbf3a99..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-From c0dc1b412f9d840c51c5ee8927bf066e15a59550 Mon Sep 17 00:00:00 2001
-From: "SkyLake.Huang" <[email protected]>
-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 <[email protected]>
-Reviewed-by: Simon Horman <[email protected]>
-Signed-off-by: Andrew Lunn <[email protected]>
----
- 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 (file)
index 1f6f5f5..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-From bcbbfb4f62c4ba35783cc617997a2e92d91e3940 Mon Sep 17 00:00:00 2001
-From: "SkyLake.Huang" <[email protected]>
-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 <[email protected]>
-Reviewed-by: Simon Horman <[email protected]>
-Signed-off-by: Andrew Lunn <[email protected]>
----
- 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 (file)
index 7161ffe..0000000
+++ /dev/null
@@ -1,3565 +0,0 @@
-From e062f073dc0df4fcd338043cb0b69b6bcd31e4af Mon Sep 17 00:00:00 2001
-From: "SkyLake.Huang" <[email protected]>
-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 <[email protected]>
-Signed-off-by: SkyLake.Huang <[email protected]>
-Signed-off-by: David S. Miller <[email protected]>
----
- 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 <[email protected]>
- M:    SkyLake Huang <[email protected]>
- L:    [email protected]
- S:    Maintained
--F:    drivers/net/phy/mediatek-ge-soc.c
--F:    drivers/net/phy/mediatek-ge.c
-+F:    drivers/net/phy/mediatek/mtk-ge-soc.c
-+F:    drivers/net/phy/mediatek/mtk-ge.c
- F:    drivers/phy/mediatek/phy-mtk-xfi-tphy.c
- MEDIATEK I2C CONTROLLER DRIVER
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -266,22 +266,7 @@ config MAXLINEAR_GPHY
-         Support for the Maxlinear GPY115, GPY211, GPY212, GPY215,
-         GPY241, GPY245 PHYs.
--config MEDIATEK_GE_PHY
--      tristate "MediaTek Gigabit Ethernet PHYs"
--      help
--        Supports the MediaTek Gigabit Ethernet PHYs.
--
--config MEDIATEK_GE_SOC_PHY
--      tristate "MediaTek SoC Ethernet PHYs"
--      depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
--      depends on NVMEM_MTK_EFUSE
--      help
--        Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
--
--        Include support for built-in Ethernet PHYs which are present in
--        the MT7981 and MT7988 SoCs. These PHYs need calibration data
--        present in the SoCs efuse and will dynamically calibrate VCM
--        (common-mode voltage) during startup.
-+source "drivers/net/phy/mediatek/Kconfig"
- config MICREL_PHY
-       tristate "Micrel PHYs"
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -74,8 +74,7 @@ obj-$(CONFIG_MARVELL_PHY)    += marvell.o
- obj-$(CONFIG_MARVELL_88Q2XXX_PHY)     += marvell-88q2xxx.o
- obj-$(CONFIG_MARVELL_88X2222_PHY)     += marvell-88x2222.o
- obj-$(CONFIG_MAXLINEAR_GPHY)  += mxl-gpy.o
--obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
--obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)     += mediatek-ge-soc.o
-+obj-y                         += mediatek/
- obj-$(CONFIG_MESON_GXL_PHY)   += meson-gxl.o
- obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
- obj-$(CONFIG_MICREL_PHY)      += micrel.o
---- /dev/null
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -0,0 +1,22 @@
-+# SPDX-License-Identifier: GPL-2.0-only
-+config MEDIATEK_GE_PHY
-+      tristate "MediaTek Gigabit Ethernet PHYs"
-+      help
-+        Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
-+
-+        Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531.
-+        You may find mt7530 inside mt7621. This driver shares some
-+        common operations with MediaTek SoC built-in Gigabit
-+        Ethernet PHYs.
-+
-+config MEDIATEK_GE_SOC_PHY
-+      tristate "MediaTek SoC Ethernet PHYs"
-+      depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
-+      depends on NVMEM_MTK_EFUSE
-+      help
-+        Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
-+
-+        Include support for built-in Ethernet PHYs which are present in
-+        the MT7981 and MT7988 SoCs. These PHYs need calibration data
-+        present in the SoCs efuse and will dynamically calibrate VCM
-+        (common-mode voltage) during startup.
---- /dev/null
-+++ b/drivers/net/phy/mediatek/Makefile
-@@ -0,0 +1,3 @@
-+# SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_MEDIATEK_GE_PHY)         += mtk-ge.o
-+obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)     += mtk-ge-soc.o
---- a/drivers/net/phy/mediatek-ge-soc.c
-+++ /dev/null
-@@ -1,1610 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--#include <linux/bitfield.h>
--#include <linux/bitmap.h>
--#include <linux/mfd/syscon.h>
--#include <linux/module.h>
--#include <linux/nvmem-consumer.h>
--#include <linux/pinctrl/consumer.h>
--#include <linux/phy.h>
--#include <linux/regmap.h>
--
--#define MTK_GPHY_ID_MT7981                    0x03a29461
--#define MTK_GPHY_ID_MT7988                    0x03a29481
--
--#define MTK_EXT_PAGE_ACCESS                   0x1f
--#define MTK_PHY_PAGE_STANDARD                 0x0000
--#define MTK_PHY_PAGE_EXTENDED_3                       0x0003
--
--#define MTK_PHY_LPI_REG_14                    0x14
--#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK      GENMASK(8, 0)
--
--#define MTK_PHY_LPI_REG_1c                    0x1c
--#define MTK_PHY_SMI_DET_ON_THRESH_MASK                GENMASK(13, 8)
--
--#define MTK_PHY_PAGE_EXTENDED_2A30            0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5            0x52b5
--
--#define ANALOG_INTERNAL_OPERATION_MAX_US      20
--#define TXRESERVE_MIN                         0
--#define TXRESERVE_MAX                         7
--
--#define MTK_PHY_ANARG_RG                      0x10
--#define   MTK_PHY_TCLKOFFSET_MASK             GENMASK(12, 8)
--
--/* Registers on MDIO_MMD_VEND1 */
--#define MTK_PHY_TXVLD_DA_RG                   0x12
--#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK      GENMASK(15, 10)
--#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK      GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_A2         0x16
--#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK      GENMASK(15, 10)
--#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK      GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_B1         0x17
--#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK      GENMASK(13, 8)
--#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK      GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_B2         0x18
--#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK      GENMASK(13, 8)
--#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK      GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_C1         0x19
--#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK      GENMASK(13, 8)
--#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK      GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_C2         0x20
--#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK      GENMASK(13, 8)
--#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK      GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_D1         0x21
--#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK      GENMASK(13, 8)
--#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK      GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_D2         0x22
--#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK      GENMASK(13, 8)
--#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK      GENMASK(5, 0)
--
--#define MTK_PHY_RXADC_CTRL_RG7                        0xc6
--#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK      GENMASK(9, 8)
--
--#define MTK_PHY_RXADC_CTRL_RG9                        0xc8
--#define   MTK_PHY_DA_RX_PSBN_TBT_MASK         GENMASK(14, 12)
--#define   MTK_PHY_DA_RX_PSBN_HBT_MASK         GENMASK(10, 8)
--#define   MTK_PHY_DA_RX_PSBN_GBE_MASK         GENMASK(6, 4)
--#define   MTK_PHY_DA_RX_PSBN_LP_MASK          GENMASK(2, 0)
--
--#define MTK_PHY_LDO_OUTPUT_V                  0xd7
--
--#define MTK_PHY_RG_ANA_CAL_RG0                        0xdb
--#define   MTK_PHY_RG_CAL_CKINV                        BIT(12)
--#define   MTK_PHY_RG_ANA_CALEN                        BIT(8)
--#define   MTK_PHY_RG_ZCALEN_A                 BIT(0)
--
--#define MTK_PHY_RG_ANA_CAL_RG1                        0xdc
--#define   MTK_PHY_RG_ZCALEN_B                 BIT(12)
--#define   MTK_PHY_RG_ZCALEN_C                 BIT(8)
--#define   MTK_PHY_RG_ZCALEN_D                 BIT(4)
--#define   MTK_PHY_RG_TXVOS_CALEN              BIT(0)
--
--#define MTK_PHY_RG_ANA_CAL_RG5                        0xe0
--#define   MTK_PHY_RG_REXT_TRIM_MASK           GENMASK(13, 8)
--
--#define MTK_PHY_RG_TX_FILTER                  0xfe
--
--#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120    0x120
--#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK       GENMASK(12, 8)
--#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK       GENMASK(4, 0)
--
--#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122    0x122
--#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK     GENMASK(7, 0)
--
--#define MTK_PHY_RG_TESTMUX_ADC_CTRL           0x144
--#define   MTK_PHY_RG_TXEN_DIG_MASK            GENMASK(5, 5)
--
--#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B               0x172
--#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK     GENMASK(13, 8)
--#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK     GENMASK(6, 0)
--
--#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D               0x173
--#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK     GENMASK(13, 8)
--#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK     GENMASK(6, 0)
--
--#define MTK_PHY_RG_AD_CAL_COMP                        0x17a
--#define   MTK_PHY_AD_CAL_COMP_OUT_MASK                GENMASK(8, 8)
--
--#define MTK_PHY_RG_AD_CAL_CLK                 0x17b
--#define   MTK_PHY_DA_CAL_CLK                  BIT(0)
--
--#define MTK_PHY_RG_AD_CALIN                   0x17c
--#define   MTK_PHY_DA_CALIN_FLAG                       BIT(0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_A             0x17d
--#define   MTK_PHY_DASN_DAC_IN0_A_MASK         GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_B             0x17e
--#define   MTK_PHY_DASN_DAC_IN0_B_MASK         GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_C             0x17f
--#define   MTK_PHY_DASN_DAC_IN0_C_MASK         GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_D             0x180
--#define   MTK_PHY_DASN_DAC_IN0_D_MASK         GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_A             0x181
--#define   MTK_PHY_DASN_DAC_IN1_A_MASK         GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_B             0x182
--#define   MTK_PHY_DASN_DAC_IN1_B_MASK         GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_C             0x183
--#define   MTK_PHY_DASN_DAC_IN1_C_MASK         GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_D             0x184
--#define   MTK_PHY_DASN_DAC_IN1_D_MASK         GENMASK(9, 0)
--
--#define MTK_PHY_RG_DEV1E_REG19b                       0x19b
--#define   MTK_PHY_BYPASS_DSP_LPI_READY                BIT(8)
--
--#define MTK_PHY_RG_LP_IIR2_K1_L                       0x22a
--#define MTK_PHY_RG_LP_IIR2_K1_U                       0x22b
--#define MTK_PHY_RG_LP_IIR2_K2_L                       0x22c
--#define MTK_PHY_RG_LP_IIR2_K2_U                       0x22d
--#define MTK_PHY_RG_LP_IIR2_K3_L                       0x22e
--#define MTK_PHY_RG_LP_IIR2_K3_U                       0x22f
--#define MTK_PHY_RG_LP_IIR2_K4_L                       0x230
--#define MTK_PHY_RG_LP_IIR2_K4_U                       0x231
--#define MTK_PHY_RG_LP_IIR2_K5_L                       0x232
--#define MTK_PHY_RG_LP_IIR2_K5_U                       0x233
--
--#define MTK_PHY_RG_DEV1E_REG234                       0x234
--#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK                GENMASK(0, 0)
--#define   MTK_PHY_LPF_X_AVERAGE_MASK          GENMASK(7, 4)
--#define   MTK_PHY_TR_LP_IIR_EEE_EN            BIT(12)
--
--#define MTK_PHY_RG_LPF_CNT_VAL                        0x235
--
--#define MTK_PHY_RG_DEV1E_REG238                       0x238
--#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK  GENMASK(8, 0)
--#define   MTK_PHY_LPI_SLV_SEND_TX_EN          BIT(12)
--
--#define MTK_PHY_RG_DEV1E_REG239                       0x239
--#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK     GENMASK(8, 0)
--#define   MTK_PHY_LPI_TXPCS_LOC_RCV           BIT(12)
--
--#define MTK_PHY_RG_DEV1E_REG27C                       0x27c
--#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK   GENMASK(12, 8)
--#define MTK_PHY_RG_DEV1E_REG27D                       0x27d
--#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK   GENMASK(4, 0)
--
--#define MTK_PHY_RG_DEV1E_REG2C7                       0x2c7
--#define   MTK_PHY_MAX_GAIN_MASK                       GENMASK(4, 0)
--#define   MTK_PHY_MIN_GAIN_MASK                       GENMASK(12, 8)
--
--#define MTK_PHY_RG_DEV1E_REG2D1                       0x2d1
--#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK        GENMASK(7, 0)
--#define   MTK_PHY_LPI_SKIP_SD_SLV_TR          BIT(8)
--#define   MTK_PHY_LPI_TR_READY                        BIT(9)
--#define   MTK_PHY_LPI_VCO_EEE_STG0_EN         BIT(10)
--
--#define MTK_PHY_RG_DEV1E_REG323                       0x323
--#define   MTK_PHY_EEE_WAKE_MAS_INT_DC         BIT(0)
--#define   MTK_PHY_EEE_WAKE_SLV_INT_DC         BIT(4)
--
--#define MTK_PHY_RG_DEV1E_REG324                       0x324
--#define   MTK_PHY_SMI_DETCNT_MAX_MASK         GENMASK(5, 0)
--#define   MTK_PHY_SMI_DET_MAX_EN              BIT(8)
--
--#define MTK_PHY_RG_DEV1E_REG326                       0x326
--#define   MTK_PHY_LPI_MODE_SD_ON              BIT(0)
--#define   MTK_PHY_RESET_RANDUPD_CNT           BIT(1)
--#define   MTK_PHY_TREC_UPDATE_ENAB_CLR                BIT(2)
--#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF       BIT(4)
--#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP    BIT(5)
--
--#define MTK_PHY_LDO_PUMP_EN_PAIRAB            0x502
--#define MTK_PHY_LDO_PUMP_EN_PAIRCD            0x503
--
--#define MTK_PHY_DA_TX_R50_PAIR_A              0x53d
--#define MTK_PHY_DA_TX_R50_PAIR_B              0x53e
--#define MTK_PHY_DA_TX_R50_PAIR_C              0x53f
--#define MTK_PHY_DA_TX_R50_PAIR_D              0x540
--
--/* Registers on MDIO_MMD_VEND2 */
--#define MTK_PHY_LED0_ON_CTRL                  0x24
--#define MTK_PHY_LED1_ON_CTRL                  0x26
--#define   MTK_PHY_LED_ON_MASK                 GENMASK(6, 0)
--#define   MTK_PHY_LED_ON_LINK1000             BIT(0)
--#define   MTK_PHY_LED_ON_LINK100              BIT(1)
--#define   MTK_PHY_LED_ON_LINK10                       BIT(2)
--#define   MTK_PHY_LED_ON_LINK                 (MTK_PHY_LED_ON_LINK10 |\
--                                               MTK_PHY_LED_ON_LINK100 |\
--                                               MTK_PHY_LED_ON_LINK1000)
--#define   MTK_PHY_LED_ON_LINKDOWN             BIT(3)
--#define   MTK_PHY_LED_ON_FDX                  BIT(4) /* Full duplex */
--#define   MTK_PHY_LED_ON_HDX                  BIT(5) /* Half duplex */
--#define   MTK_PHY_LED_ON_FORCE_ON             BIT(6)
--#define   MTK_PHY_LED_ON_POLARITY             BIT(14)
--#define   MTK_PHY_LED_ON_ENABLE                       BIT(15)
--
--#define MTK_PHY_LED0_BLINK_CTRL                       0x25
--#define MTK_PHY_LED1_BLINK_CTRL                       0x27
--#define   MTK_PHY_LED_BLINK_1000TX            BIT(0)
--#define   MTK_PHY_LED_BLINK_1000RX            BIT(1)
--#define   MTK_PHY_LED_BLINK_100TX             BIT(2)
--#define   MTK_PHY_LED_BLINK_100RX             BIT(3)
--#define   MTK_PHY_LED_BLINK_10TX              BIT(4)
--#define   MTK_PHY_LED_BLINK_10RX              BIT(5)
--#define   MTK_PHY_LED_BLINK_RX                        (MTK_PHY_LED_BLINK_10RX |\
--                                               MTK_PHY_LED_BLINK_100RX |\
--                                               MTK_PHY_LED_BLINK_1000RX)
--#define   MTK_PHY_LED_BLINK_TX                        (MTK_PHY_LED_BLINK_10TX |\
--                                               MTK_PHY_LED_BLINK_100TX |\
--                                               MTK_PHY_LED_BLINK_1000TX)
--#define   MTK_PHY_LED_BLINK_COLLISION         BIT(6)
--#define   MTK_PHY_LED_BLINK_RX_CRC_ERR                BIT(7)
--#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR               BIT(8)
--#define   MTK_PHY_LED_BLINK_FORCE_BLINK               BIT(9)
--
--#define MTK_PHY_LED1_DEFAULT_POLARITIES               BIT(1)
--
--#define MTK_PHY_RG_BG_RASEL                   0x115
--#define   MTK_PHY_RG_BG_RASEL_MASK            GENMASK(2, 0)
--
--/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
--#define RG_GPIO_MISC_TPBANK0                  0x6f0
--#define   RG_GPIO_MISC_TPBANK0_BOOTMODE               GENMASK(11, 8)
--
--/* These macro privides efuse parsing for internal phy. */
--#define EFS_DA_TX_I2MPB_A(x)                  (((x) >> 0) & GENMASK(5, 0))
--#define EFS_DA_TX_I2MPB_B(x)                  (((x) >> 6) & GENMASK(5, 0))
--#define EFS_DA_TX_I2MPB_C(x)                  (((x) >> 12) & GENMASK(5, 0))
--#define EFS_DA_TX_I2MPB_D(x)                  (((x) >> 18) & GENMASK(5, 0))
--#define EFS_DA_TX_AMP_OFFSET_A(x)             (((x) >> 24) & GENMASK(5, 0))
--
--#define EFS_DA_TX_AMP_OFFSET_B(x)             (((x) >> 0) & GENMASK(5, 0))
--#define EFS_DA_TX_AMP_OFFSET_C(x)             (((x) >> 6) & GENMASK(5, 0))
--#define EFS_DA_TX_AMP_OFFSET_D(x)             (((x) >> 12) & GENMASK(5, 0))
--#define EFS_DA_TX_R50_A(x)                    (((x) >> 18) & GENMASK(5, 0))
--#define EFS_DA_TX_R50_B(x)                    (((x) >> 24) & GENMASK(5, 0))
--
--#define EFS_DA_TX_R50_C(x)                    (((x) >> 0) & GENMASK(5, 0))
--#define EFS_DA_TX_R50_D(x)                    (((x) >> 6) & GENMASK(5, 0))
--
--#define EFS_RG_BG_RASEL(x)                    (((x) >> 4) & GENMASK(2, 0))
--#define EFS_RG_REXT_TRIM(x)                   (((x) >> 7) & GENMASK(5, 0))
--
--enum {
--      NO_PAIR,
--      PAIR_A,
--      PAIR_B,
--      PAIR_C,
--      PAIR_D,
--};
--
--enum calibration_mode {
--      EFUSE_K,
--      SW_K
--};
--
--enum CAL_ITEM {
--      REXT,
--      TX_OFFSET,
--      TX_AMP,
--      TX_R50,
--      TX_VCM
--};
--
--enum CAL_MODE {
--      EFUSE_M,
--      SW_M
--};
--
--#define MTK_PHY_LED_STATE_FORCE_ON    0
--#define MTK_PHY_LED_STATE_FORCE_BLINK 1
--#define MTK_PHY_LED_STATE_NETDEV      2
--
--struct mtk_socphy_priv {
--      unsigned long           led_state;
--};
--
--struct mtk_socphy_shared {
--      u32                     boottrap;
--      struct mtk_socphy_priv  priv[4];
--};
--
--static int mtk_socphy_read_page(struct phy_device *phydev)
--{
--      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_socphy_write_page(struct phy_device *phydev, int page)
--{
--      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
--/* One calibration cycle consists of:
-- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
-- *   until AD_CAL_COMP is ready to output calibration result.
-- * 2.Wait until DA_CAL_CLK is available.
-- * 3.Fetch AD_CAL_COMP_OUT.
-- */
--static int cal_cycle(struct phy_device *phydev, int devad,
--                   u32 regnum, u16 mask, u16 cal_val)
--{
--      int reg_val;
--      int ret;
--
--      phy_modify_mmd(phydev, devad, regnum,
--                     mask, cal_val);
--      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
--                       MTK_PHY_DA_CALIN_FLAG);
--
--      ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
--                                      MTK_PHY_RG_AD_CAL_CLK, reg_val,
--                                      reg_val & MTK_PHY_DA_CAL_CLK, 500,
--                                      ANALOG_INTERNAL_OPERATION_MAX_US,
--                                      false);
--      if (ret) {
--              phydev_err(phydev, "Calibration cycle timeout\n");
--              return ret;
--      }
--
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
--                         MTK_PHY_DA_CALIN_FLAG);
--      ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
--      if (ret < 0)
--              return ret;
--      ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
--      phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
--
--      return ret;
--}
--
--static int rext_fill_result(struct phy_device *phydev, u16 *buf)
--{
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
--                     MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
--      phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
--                     MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
--
--      return 0;
--}
--
--static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
--{
--      u16 rext_cal_val[2];
--
--      rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
--      rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
--      rext_fill_result(phydev, rext_cal_val);
--
--      return 0;
--}
--
--static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
--{
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
--                     MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
--                     MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
--                     MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
--                     MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
--
--      return 0;
--}
--
--static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
--{
--      u16 tx_offset_cal_val[4];
--
--      tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
--      tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
--      tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
--      tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
--
--      tx_offset_fill_result(phydev, tx_offset_cal_val);
--
--      return 0;
--}
--
--static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
--{
--      const int vals_9481[16] = { 10, 6, 6, 10,
--                                  10, 6, 6, 10,
--                                  10, 6, 6, 10,
--                                  10, 6, 6, 10 };
--      const int vals_9461[16] = { 7, 1, 4, 7,
--                                  7, 1, 4, 7,
--                                  7, 1, 4, 7,
--                                  7, 1, 4, 7 };
--      int bias[16] = {};
--      int i;
--
--      switch (phydev->drv->phy_id) {
--      case MTK_GPHY_ID_MT7981:
--              /* We add some calibration to efuse values
--               * due to board level influence.
--               * GBE: +7, TBT: +1, HBT: +4, TST: +7
--               */
--              memcpy(bias, (const void *)vals_9461, sizeof(bias));
--              break;
--      case MTK_GPHY_ID_MT7988:
--              memcpy(bias, (const void *)vals_9481, sizeof(bias));
--              break;
--      }
--
--      /* Prevent overflow */
--      for (i = 0; i < 12; i++) {
--              if (buf[i >> 2] + bias[i] > 63) {
--                      buf[i >> 2] = 63;
--                      bias[i] = 0;
--              }
--      }
--
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
--                     MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
--                                buf[0] + bias[0]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
--                     MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
--                                buf[0] + bias[1]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
--                     MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
--                                buf[0] + bias[2]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
--                     MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
--                                buf[0] + bias[3]));
--
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
--                     MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
--                                buf[1] + bias[4]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
--                     MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
--                                buf[1] + bias[5]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
--                     MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
--                                buf[1] + bias[6]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
--                     MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
--                                buf[1] + bias[7]));
--
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
--                     MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
--                                buf[2] + bias[8]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
--                     MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
--                                buf[2] + bias[9]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
--                     MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
--                                buf[2] + bias[10]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
--                     MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
--                                buf[2] + bias[11]));
--
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
--                     MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
--                                buf[3] + bias[12]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
--                     MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
--                                buf[3] + bias[13]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
--                     MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
--                                buf[3] + bias[14]));
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
--                     MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
--                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
--                                buf[3] + bias[15]));
--
--      return 0;
--}
--
--static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
--{
--      u16 tx_amp_cal_val[4];
--
--      tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
--      tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
--      tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
--      tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
--      tx_amp_fill_result(phydev, tx_amp_cal_val);
--
--      return 0;
--}
--
--static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
--                            u8 txg_calen_x)
--{
--      int bias = 0;
--      u16 reg, val;
--
--      if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
--              bias = -1;
--
--      val = clamp_val(bias + tx_r50_cal_val, 0, 63);
--
--      switch (txg_calen_x) {
--      case PAIR_A:
--              reg = MTK_PHY_DA_TX_R50_PAIR_A;
--              break;
--      case PAIR_B:
--              reg = MTK_PHY_DA_TX_R50_PAIR_B;
--              break;
--      case PAIR_C:
--              reg = MTK_PHY_DA_TX_R50_PAIR_C;
--              break;
--      case PAIR_D:
--              reg = MTK_PHY_DA_TX_R50_PAIR_D;
--              break;
--      default:
--              return -EINVAL;
--      }
--
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
--
--      return 0;
--}
--
--static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
--                          u8 txg_calen_x)
--{
--      u16 tx_r50_cal_val;
--
--      switch (txg_calen_x) {
--      case PAIR_A:
--              tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
--              break;
--      case PAIR_B:
--              tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
--              break;
--      case PAIR_C:
--              tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
--              break;
--      case PAIR_D:
--              tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
--              break;
--      default:
--              return -EINVAL;
--      }
--      tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
--
--      return 0;
--}
--
--static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
--{
--      u8 lower_idx, upper_idx, txreserve_val;
--      u8 lower_ret, upper_ret;
--      int ret;
--
--      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
--                       MTK_PHY_RG_ANA_CALEN);
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
--                         MTK_PHY_RG_CAL_CKINV);
--      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
--                       MTK_PHY_RG_TXVOS_CALEN);
--
--      switch (rg_txreserve_x) {
--      case PAIR_A:
--              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                                 MTK_PHY_RG_DASN_DAC_IN0_A,
--                                 MTK_PHY_DASN_DAC_IN0_A_MASK);
--              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                                 MTK_PHY_RG_DASN_DAC_IN1_A,
--                                 MTK_PHY_DASN_DAC_IN1_A_MASK);
--              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
--                               MTK_PHY_RG_ANA_CAL_RG0,
--                               MTK_PHY_RG_ZCALEN_A);
--              break;
--      case PAIR_B:
--              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                                 MTK_PHY_RG_DASN_DAC_IN0_B,
--                                 MTK_PHY_DASN_DAC_IN0_B_MASK);
--              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                                 MTK_PHY_RG_DASN_DAC_IN1_B,
--                                 MTK_PHY_DASN_DAC_IN1_B_MASK);
--              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
--                               MTK_PHY_RG_ANA_CAL_RG1,
--                               MTK_PHY_RG_ZCALEN_B);
--              break;
--      case PAIR_C:
--              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                                 MTK_PHY_RG_DASN_DAC_IN0_C,
--                                 MTK_PHY_DASN_DAC_IN0_C_MASK);
--              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                                 MTK_PHY_RG_DASN_DAC_IN1_C,
--                                 MTK_PHY_DASN_DAC_IN1_C_MASK);
--              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
--                               MTK_PHY_RG_ANA_CAL_RG1,
--                               MTK_PHY_RG_ZCALEN_C);
--              break;
--      case PAIR_D:
--              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                                 MTK_PHY_RG_DASN_DAC_IN0_D,
--                                 MTK_PHY_DASN_DAC_IN0_D_MASK);
--              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                                 MTK_PHY_RG_DASN_DAC_IN1_D,
--                                 MTK_PHY_DASN_DAC_IN1_D_MASK);
--              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
--                               MTK_PHY_RG_ANA_CAL_RG1,
--                               MTK_PHY_RG_ZCALEN_D);
--              break;
--      default:
--              ret = -EINVAL;
--              goto restore;
--      }
--
--      lower_idx = TXRESERVE_MIN;
--      upper_idx = TXRESERVE_MAX;
--
--      phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
--      while ((upper_idx - lower_idx) > 1) {
--              txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
--              ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
--                              MTK_PHY_DA_RX_PSBN_TBT_MASK |
--                              MTK_PHY_DA_RX_PSBN_HBT_MASK |
--                              MTK_PHY_DA_RX_PSBN_GBE_MASK |
--                              MTK_PHY_DA_RX_PSBN_LP_MASK,
--                              txreserve_val << 12 | txreserve_val << 8 |
--                              txreserve_val << 4 | txreserve_val);
--              if (ret == 1) {
--                      upper_idx = txreserve_val;
--                      upper_ret = ret;
--              } else if (ret == 0) {
--                      lower_idx = txreserve_val;
--                      lower_ret = ret;
--              } else {
--                      goto restore;
--              }
--      }
--
--      if (lower_idx == TXRESERVE_MIN) {
--              lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
--                                    MTK_PHY_RXADC_CTRL_RG9,
--                                    MTK_PHY_DA_RX_PSBN_TBT_MASK |
--                                    MTK_PHY_DA_RX_PSBN_HBT_MASK |
--                                    MTK_PHY_DA_RX_PSBN_GBE_MASK |
--                                    MTK_PHY_DA_RX_PSBN_LP_MASK,
--                                    lower_idx << 12 | lower_idx << 8 |
--                                    lower_idx << 4 | lower_idx);
--              ret = lower_ret;
--      } else if (upper_idx == TXRESERVE_MAX) {
--              upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
--                                    MTK_PHY_RXADC_CTRL_RG9,
--                                    MTK_PHY_DA_RX_PSBN_TBT_MASK |
--                                    MTK_PHY_DA_RX_PSBN_HBT_MASK |
--                                    MTK_PHY_DA_RX_PSBN_GBE_MASK |
--                                    MTK_PHY_DA_RX_PSBN_LP_MASK,
--                                    upper_idx << 12 | upper_idx << 8 |
--                                    upper_idx << 4 | upper_idx);
--              ret = upper_ret;
--      }
--      if (ret < 0)
--              goto restore;
--
--      /* We calibrate TX-VCM in different logic. Check upper index and then
--       * lower index. If this calibration is valid, apply lower index's
--       * result.
--       */
--      ret = upper_ret - lower_ret;
--      if (ret == 1) {
--              ret = 0;
--              /* Make sure we use upper_idx in our calibration system */
--              cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
--                        MTK_PHY_DA_RX_PSBN_TBT_MASK |
--                        MTK_PHY_DA_RX_PSBN_HBT_MASK |
--                        MTK_PHY_DA_RX_PSBN_GBE_MASK |
--                        MTK_PHY_DA_RX_PSBN_LP_MASK,
--                        upper_idx << 12 | upper_idx << 8 |
--                        upper_idx << 4 | upper_idx);
--              phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
--      } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
--                 lower_ret == 1) {
--              ret = 0;
--              cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
--                        MTK_PHY_DA_RX_PSBN_TBT_MASK |
--                        MTK_PHY_DA_RX_PSBN_HBT_MASK |
--                        MTK_PHY_DA_RX_PSBN_GBE_MASK |
--                        MTK_PHY_DA_RX_PSBN_LP_MASK,
--                        lower_idx << 12 | lower_idx << 8 |
--                        lower_idx << 4 | lower_idx);
--              phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
--                          lower_idx);
--      } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
--                 lower_ret == 0) {
--              ret = 0;
--              phydev_warn(phydev,
--                          "TX-VCM SW cal result at high margin 0x%x\n",
--                          upper_idx);
--      } else {
--              ret = -EINVAL;
--      }
--
--restore:
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
--                         MTK_PHY_RG_ANA_CALEN);
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
--                         MTK_PHY_RG_TXVOS_CALEN);
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
--                         MTK_PHY_RG_ZCALEN_A);
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
--                         MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
--                         MTK_PHY_RG_ZCALEN_D);
--
--      return ret;
--}
--
--static void mt798x_phy_common_finetune(struct phy_device *phydev)
--{
--      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
--      /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
--      __phy_write(phydev, 0x11, 0xc71);
--      __phy_write(phydev, 0x12, 0xc);
--      __phy_write(phydev, 0x10, 0x8fae);
--
--      /* EnabRandUpdTrig = 1 */
--      __phy_write(phydev, 0x11, 0x2f00);
--      __phy_write(phydev, 0x12, 0xe);
--      __phy_write(phydev, 0x10, 0x8fb0);
--
--      /* NormMseLoThresh = 85 */
--      __phy_write(phydev, 0x11, 0x55a0);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x83aa);
--
--      /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
--      __phy_write(phydev, 0x11, 0x240);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x9680);
--
--      /* TrFreeze = 0 (mt7988 default) */
--      __phy_write(phydev, 0x11, 0x0);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x9686);
--
--      /* SSTrKp100 = 5 */
--      /* SSTrKf100 = 6 */
--      /* SSTrKp1000Mas = 5 */
--      /* SSTrKf1000Mas = 6 */
--      /* SSTrKp1000Slv = 5 */
--      /* SSTrKf1000Slv = 6 */
--      __phy_write(phydev, 0x11, 0xbaef);
--      __phy_write(phydev, 0x12, 0x2e);
--      __phy_write(phydev, 0x10, 0x968c);
--      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--}
--
--static void mt7981_phy_finetune(struct phy_device *phydev)
--{
--      u16 val[8] = { 0x01ce, 0x01c1,
--                     0x020f, 0x0202,
--                     0x03d0, 0x03c0,
--                     0x0013, 0x0005 };
--      int i, k;
--
--      /* 100M eye finetune:
--       * Keep middle level of TX MLT3 shapper as default.
--       * Only change TX MLT3 overshoot level here.
--       */
--      for (k = 0, i = 1; i < 12; i++) {
--              if (i % 3 == 0)
--                      continue;
--              phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
--      }
--
--      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
--      /* ResetSyncOffset = 6 */
--      __phy_write(phydev, 0x11, 0x600);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x8fc0);
--
--      /* VgaDecRate = 1 */
--      __phy_write(phydev, 0x11, 0x4c2a);
--      __phy_write(phydev, 0x12, 0x3e);
--      __phy_write(phydev, 0x10, 0x8fa4);
--
--      /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
--       * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
--       */
--      __phy_write(phydev, 0x11, 0xd10a);
--      __phy_write(phydev, 0x12, 0x34);
--      __phy_write(phydev, 0x10, 0x8f82);
--
--      /* VcoSlicerThreshBitsHigh */
--      __phy_write(phydev, 0x11, 0x5555);
--      __phy_write(phydev, 0x12, 0x55);
--      __phy_write(phydev, 0x10, 0x8ec0);
--      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
--      /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
--                     MTK_PHY_TR_OPEN_LOOP_EN_MASK |
--                     MTK_PHY_LPF_X_AVERAGE_MASK,
--                     BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
--
--      /* rg_tr_lpf_cnt_val = 512 */
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
--
--      /* IIR2 related */
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
--
--      /* FFE peaking */
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
--                     MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
--                     MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
--
--      /* Disable LDO pump */
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
--      /* Adjust LDO output voltage */
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
--}
--
--static void mt7988_phy_finetune(struct phy_device *phydev)
--{
--      u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
--                      0x020d, 0x0206, 0x0384, 0x03d0,
--                      0x03c6, 0x030a, 0x0011, 0x0005 };
--      int i;
--
--      /* Set default MLT3 shaper first */
--      for (i = 0; i < 12; i++)
--              phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
--
--      /* TCT finetune */
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
--
--      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
--      /* ResetSyncOffset = 5 */
--      __phy_write(phydev, 0x11, 0x500);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x8fc0);
--
--      /* VgaDecRate is 1 at default on mt7988 */
--
--      /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
--       * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
--       */
--      __phy_write(phydev, 0x11, 0xb90a);
--      __phy_write(phydev, 0x12, 0x6f);
--      __phy_write(phydev, 0x10, 0x8f82);
--
--      /* RemAckCntLimitCtrl = 1 */
--      __phy_write(phydev, 0x11, 0xfbba);
--      __phy_write(phydev, 0x12, 0xc3);
--      __phy_write(phydev, 0x10, 0x87f8);
--
--      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
--      /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
--                     MTK_PHY_TR_OPEN_LOOP_EN_MASK |
--                     MTK_PHY_LPF_X_AVERAGE_MASK,
--                     BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
--
--      /* rg_tr_lpf_cnt_val = 1023 */
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
--}
--
--static void mt798x_phy_eee(struct phy_device *phydev)
--{
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
--                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
--                     MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
--                     MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
--                     FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
--                     FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
--
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
--                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
--                     MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
--                     FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
--                                0xff));
--
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                         MTK_PHY_RG_TESTMUX_ADC_CTRL,
--                         MTK_PHY_RG_TXEN_DIG_MASK);
--
--      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
--                       MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
--
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
--                         MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
--
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
--                     MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
--                     MTK_PHY_LPI_SLV_SEND_TX_EN,
--                     FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
--
--      /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
--                         MTK_PHY_LPI_TXPCS_LOC_RCV);
--
--      /* This also fixes some IoT issues, such as CH340 */
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
--                     MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
--                     FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
--                     FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
--
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
--                     MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
--                     FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
--                                0x33) |
--                     MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
--                     MTK_PHY_LPI_VCO_EEE_STG0_EN);
--
--      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
--                       MTK_PHY_EEE_WAKE_MAS_INT_DC |
--                       MTK_PHY_EEE_WAKE_SLV_INT_DC);
--
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
--                     MTK_PHY_SMI_DETCNT_MAX_MASK,
--                     FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
--                     MTK_PHY_SMI_DET_MAX_EN);
--
--      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
--                       MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
--                       MTK_PHY_TREC_UPDATE_ENAB_CLR |
--                       MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
--                       MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
--
--      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
--      /* Regsigdet_sel_1000 = 0 */
--      __phy_write(phydev, 0x11, 0xb);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x9690);
--
--      /* REG_EEE_st2TrKf1000 = 2 */
--      __phy_write(phydev, 0x11, 0x114f);
--      __phy_write(phydev, 0x12, 0x2);
--      __phy_write(phydev, 0x10, 0x969a);
--
--      /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
--      __phy_write(phydev, 0x11, 0x3028);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x969e);
--
--      /* RegEEE_slv_wake_int_timer_tar = 8 */
--      __phy_write(phydev, 0x11, 0x5010);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x96a0);
--
--      /* RegEEE_trfreeze_timer2 = 586 */
--      __phy_write(phydev, 0x11, 0x24a);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x96a8);
--
--      /* RegEEE100Stg1_tar = 16 */
--      __phy_write(phydev, 0x11, 0x3210);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x96b8);
--
--      /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
--      __phy_write(phydev, 0x11, 0x1463);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x96ca);
--
--      /* DfeTailEnableVgaThresh1000 = 27 */
--      __phy_write(phydev, 0x11, 0x36);
--      __phy_write(phydev, 0x12, 0x0);
--      __phy_write(phydev, 0x10, 0x8f80);
--      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
--      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
--      __phy_modify(phydev, MTK_PHY_LPI_REG_14,
--                   MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
--                   FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
--
--      __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
--                   FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
--      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
--      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
--                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
--                     MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
--                     FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
--                                0xff));
--}
--
--static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
--                u8 start_pair, u8 end_pair)
--{
--      u8 pair_n;
--      int ret;
--
--      for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
--              /* TX_OFFSET & TX_AMP have no SW calibration. */
--              switch (cal_item) {
--              case TX_VCM:
--                      ret = tx_vcm_cal_sw(phydev, pair_n);
--                      break;
--              default:
--                      return -EINVAL;
--              }
--              if (ret)
--                      return ret;
--      }
--      return 0;
--}
--
--static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
--                   u8 start_pair, u8 end_pair, u32 *buf)
--{
--      u8 pair_n;
--      int ret;
--
--      for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
--              /* TX_VCM has no efuse calibration. */
--              switch (cal_item) {
--              case REXT:
--                      ret = rext_cal_efuse(phydev, buf);
--                      break;
--              case TX_OFFSET:
--                      ret = tx_offset_cal_efuse(phydev, buf);
--                      break;
--              case TX_AMP:
--                      ret = tx_amp_cal_efuse(phydev, buf);
--                      break;
--              case TX_R50:
--                      ret = tx_r50_cal_efuse(phydev, buf, pair_n);
--                      break;
--              default:
--                      return -EINVAL;
--              }
--              if (ret)
--                      return ret;
--      }
--
--      return 0;
--}
--
--static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
--                   enum CAL_MODE cal_mode, u8 start_pair,
--                   u8 end_pair, u32 *buf)
--{
--      int ret;
--
--      switch (cal_mode) {
--      case EFUSE_M:
--              ret = cal_efuse(phydev, cal_item, start_pair,
--                              end_pair, buf);
--              break;
--      case SW_M:
--              ret = cal_sw(phydev, cal_item, start_pair, end_pair);
--              break;
--      default:
--              return -EINVAL;
--      }
--
--      if (ret) {
--              phydev_err(phydev, "cal %d failed\n", cal_item);
--              return -EIO;
--      }
--
--      return 0;
--}
--
--static int mt798x_phy_calibration(struct phy_device *phydev)
--{
--      struct nvmem_cell *cell;
--      int ret = 0;
--      size_t len;
--      u32 *buf;
--
--      cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
--      if (IS_ERR(cell)) {
--              if (PTR_ERR(cell) == -EPROBE_DEFER)
--                      return PTR_ERR(cell);
--              return 0;
--      }
--
--      buf = (u32 *)nvmem_cell_read(cell, &len);
--      if (IS_ERR(buf))
--              return PTR_ERR(buf);
--      nvmem_cell_put(cell);
--
--      if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
--              phydev_err(phydev, "invalid efuse data\n");
--              ret = -EINVAL;
--              goto out;
--      }
--
--      ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
--      if (ret)
--              goto out;
--      ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
--      if (ret)
--              goto out;
--      ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
--      if (ret)
--              goto out;
--      ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
--      if (ret)
--              goto out;
--      ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
--      if (ret)
--              goto out;
--
--out:
--      kfree(buf);
--      return ret;
--}
--
--static int mt798x_phy_config_init(struct phy_device *phydev)
--{
--      switch (phydev->drv->phy_id) {
--      case MTK_GPHY_ID_MT7981:
--              mt7981_phy_finetune(phydev);
--              break;
--      case MTK_GPHY_ID_MT7988:
--              mt7988_phy_finetune(phydev);
--              break;
--      }
--
--      mt798x_phy_common_finetune(phydev);
--      mt798x_phy_eee(phydev);
--
--      return mt798x_phy_calibration(phydev);
--}
--
--static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
--                                  bool on)
--{
--      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
--      struct mtk_socphy_priv *priv = phydev->priv;
--      bool changed;
--
--      if (on)
--              changed = !test_and_set_bit(bit_on, &priv->led_state);
--      else
--              changed = !!test_and_clear_bit(bit_on, &priv->led_state);
--
--      changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
--                                      (index ? 16 : 0), &priv->led_state);
--      if (changed)
--              return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
--                                    MTK_PHY_LED1_ON_CTRL :
--                                    MTK_PHY_LED0_ON_CTRL,
--                                    MTK_PHY_LED_ON_MASK,
--                                    on ? MTK_PHY_LED_ON_FORCE_ON : 0);
--      else
--              return 0;
--}
--
--static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
--                                     bool blinking)
--{
--      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
--                               (index ? 16 : 0);
--      struct mtk_socphy_priv *priv = phydev->priv;
--      bool changed;
--
--      if (blinking)
--              changed = !test_and_set_bit(bit_blink, &priv->led_state);
--      else
--              changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
--
--      changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
--                            (index ? 16 : 0), &priv->led_state);
--      if (changed)
--              return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
--                                   MTK_PHY_LED1_BLINK_CTRL :
--                                   MTK_PHY_LED0_BLINK_CTRL,
--                                   blinking ?
--                                   MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
--      else
--              return 0;
--}
--
--static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
--                                  unsigned long *delay_on,
--                                  unsigned long *delay_off)
--{
--      bool blinking = false;
--      int err = 0;
--
--      if (index > 1)
--              return -EINVAL;
--
--      if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
--              blinking = true;
--              *delay_on = 50;
--              *delay_off = 50;
--      }
--
--      err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
--      if (err)
--              return err;
--
--      return mt798x_phy_hw_led_on_set(phydev, index, false);
--}
--
--static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
--                                       u8 index, enum led_brightness value)
--{
--      int err;
--
--      err = mt798x_phy_hw_led_blink_set(phydev, index, false);
--      if (err)
--              return err;
--
--      return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
--}
--
--static const unsigned long supported_triggers =
--      BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
--      BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
--      BIT(TRIGGER_NETDEV_LINK)        |
--      BIT(TRIGGER_NETDEV_LINK_10)     |
--      BIT(TRIGGER_NETDEV_LINK_100)    |
--      BIT(TRIGGER_NETDEV_LINK_1000)   |
--      BIT(TRIGGER_NETDEV_RX)          |
--      BIT(TRIGGER_NETDEV_TX);
--
--static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
--                                        unsigned long rules)
--{
--      if (index > 1)
--              return -EINVAL;
--
--      /* All combinations of the supported triggers are allowed */
--      if (rules & ~supported_triggers)
--              return -EOPNOTSUPP;
--
--      return 0;
--};
--
--static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
--                                       unsigned long *rules)
--{
--      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
--                               (index ? 16 : 0);
--      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
--      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
--      struct mtk_socphy_priv *priv = phydev->priv;
--      int on, blink;
--
--      if (index > 1)
--              return -EINVAL;
--
--      on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
--                        index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
--
--      if (on < 0)
--              return -EIO;
--
--      blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
--                           index ? MTK_PHY_LED1_BLINK_CTRL :
--                                   MTK_PHY_LED0_BLINK_CTRL);
--      if (blink < 0)
--              return -EIO;
--
--      if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
--                 MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
--          (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
--              set_bit(bit_netdev, &priv->led_state);
--      else
--              clear_bit(bit_netdev, &priv->led_state);
--
--      if (on & MTK_PHY_LED_ON_FORCE_ON)
--              set_bit(bit_on, &priv->led_state);
--      else
--              clear_bit(bit_on, &priv->led_state);
--
--      if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
--              set_bit(bit_blink, &priv->led_state);
--      else
--              clear_bit(bit_blink, &priv->led_state);
--
--      if (!rules)
--              return 0;
--
--      if (on & MTK_PHY_LED_ON_LINK)
--              *rules |= BIT(TRIGGER_NETDEV_LINK);
--
--      if (on & MTK_PHY_LED_ON_LINK10)
--              *rules |= BIT(TRIGGER_NETDEV_LINK_10);
--
--      if (on & MTK_PHY_LED_ON_LINK100)
--              *rules |= BIT(TRIGGER_NETDEV_LINK_100);
--
--      if (on & MTK_PHY_LED_ON_LINK1000)
--              *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
--
--      if (on & MTK_PHY_LED_ON_FDX)
--              *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
--
--      if (on & MTK_PHY_LED_ON_HDX)
--              *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
--
--      if (blink & MTK_PHY_LED_BLINK_RX)
--              *rules |= BIT(TRIGGER_NETDEV_RX);
--
--      if (blink & MTK_PHY_LED_BLINK_TX)
--              *rules |= BIT(TRIGGER_NETDEV_TX);
--
--      return 0;
--};
--
--static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
--                                       unsigned long rules)
--{
--      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
--      struct mtk_socphy_priv *priv = phydev->priv;
--      u16 on = 0, blink = 0;
--      int ret;
--
--      if (index > 1)
--              return -EINVAL;
--
--      if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
--              on |= MTK_PHY_LED_ON_FDX;
--
--      if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
--              on |= MTK_PHY_LED_ON_HDX;
--
--      if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
--              on |= MTK_PHY_LED_ON_LINK10;
--
--      if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
--              on |= MTK_PHY_LED_ON_LINK100;
--
--      if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
--              on |= MTK_PHY_LED_ON_LINK1000;
--
--      if (rules & BIT(TRIGGER_NETDEV_RX)) {
--              blink |= (on & MTK_PHY_LED_ON_LINK) ?
--                        (((on & MTK_PHY_LED_ON_LINK10) ?
--                          MTK_PHY_LED_BLINK_10RX : 0) |
--                         ((on & MTK_PHY_LED_ON_LINK100) ?
--                          MTK_PHY_LED_BLINK_100RX : 0) |
--                         ((on & MTK_PHY_LED_ON_LINK1000) ?
--                          MTK_PHY_LED_BLINK_1000RX : 0)) :
--                        MTK_PHY_LED_BLINK_RX;
--      }
--
--      if (rules & BIT(TRIGGER_NETDEV_TX)) {
--              blink |= (on & MTK_PHY_LED_ON_LINK) ?
--                        (((on & MTK_PHY_LED_ON_LINK10) ?
--                          MTK_PHY_LED_BLINK_10TX : 0) |
--                         ((on & MTK_PHY_LED_ON_LINK100) ?
--                          MTK_PHY_LED_BLINK_100TX : 0) |
--                         ((on & MTK_PHY_LED_ON_LINK1000) ?
--                          MTK_PHY_LED_BLINK_1000TX : 0)) :
--                        MTK_PHY_LED_BLINK_TX;
--      }
--
--      if (blink || on)
--              set_bit(bit_netdev, &priv->led_state);
--      else
--              clear_bit(bit_netdev, &priv->led_state);
--
--      ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
--                              MTK_PHY_LED1_ON_CTRL :
--                              MTK_PHY_LED0_ON_CTRL,
--                           MTK_PHY_LED_ON_FDX     |
--                           MTK_PHY_LED_ON_HDX     |
--                           MTK_PHY_LED_ON_LINK,
--                           on);
--
--      if (ret)
--              return ret;
--
--      return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
--                              MTK_PHY_LED1_BLINK_CTRL :
--                              MTK_PHY_LED0_BLINK_CTRL, blink);
--};
--
--static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
--{
--      struct mtk_socphy_shared *priv = phydev->shared->priv;
--      u32 polarities;
--
--      if (led_num == 0)
--              polarities = ~(priv->boottrap);
--      else
--              polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
--
--      if (polarities & BIT(phydev->mdio.addr))
--              return true;
--
--      return false;
--}
--
--static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
--{
--      struct pinctrl *pinctrl;
--      int index;
--
--      /* Setup LED polarity according to bootstrap use of LED pins */
--      for (index = 0; index < 2; ++index)
--              phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
--                              MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
--                             MTK_PHY_LED_ON_POLARITY,
--                             mt7988_phy_led_get_polarity(phydev, index) ?
--                              MTK_PHY_LED_ON_POLARITY : 0);
--
--      /* Only now setup pinctrl to avoid bogus blinking */
--      pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
--      if (IS_ERR(pinctrl))
--              dev_err(&phydev->mdio.bus->dev,
--                      "Failed to setup PHY LED pinctrl\n");
--
--      return 0;
--}
--
--static int mt7988_phy_probe_shared(struct phy_device *phydev)
--{
--      struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
--      struct mtk_socphy_shared *shared = phydev->shared->priv;
--      struct regmap *regmap;
--      u32 reg;
--      int ret;
--
--      /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
--       * LED_C and LED_D respectively. At the same time those pins are used to
--       * bootstrap configuration of the reference clock source (LED_A),
--       * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
--       * In practice this is done using a LED and a resistor pulling the pin
--       * either to GND or to VIO.
--       * The detected value at boot time is accessible at run-time using the
--       * TPBANK0 register located in the gpio base of the pinctrl, in order
--       * to read it here it needs to be referenced by a phandle called
--       * 'mediatek,pio' in the MDIO bus hosting the PHY.
--       * The 4 bits in TPBANK0 are kept as package shared data and are used to
--       * set LED polarity for each of the LED0.
--       */
--      regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
--      if (IS_ERR(regmap))
--              return PTR_ERR(regmap);
--
--      ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, &reg);
--      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 <[email protected]>");
--MODULE_AUTHOR("SkyLake Huang <[email protected]>");
--MODULE_LICENSE("GPL");
--
--MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
---- a/drivers/net/phy/mediatek-ge.c
-+++ /dev/null
-@@ -1,111 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--#include <linux/bitfield.h>
--#include <linux/module.h>
--#include <linux/phy.h>
--
--#define MTK_EXT_PAGE_ACCESS           0x1f
--#define MTK_PHY_PAGE_STANDARD         0x0000
--#define MTK_PHY_PAGE_EXTENDED         0x0001
--#define MTK_PHY_PAGE_EXTENDED_2               0x0002
--#define MTK_PHY_PAGE_EXTENDED_3               0x0003
--#define MTK_PHY_PAGE_EXTENDED_2A30    0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5    0x52b5
--
--static int mtk_gephy_read_page(struct phy_device *phydev)
--{
--      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_gephy_write_page(struct phy_device *phydev, int page)
--{
--      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
--static void mtk_gephy_config_init(struct phy_device *phydev)
--{
--      /* Enable HW auto downshift */
--      phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
--
--      /* Increase SlvDPSready time */
--      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
--      __phy_write(phydev, 0x10, 0xafae);
--      __phy_write(phydev, 0x12, 0x2f);
--      __phy_write(phydev, 0x10, 0x8fae);
--      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
--      /* Adjust 100_mse_threshold */
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
--
--      /* Disable mcc */
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
--}
--
--static int mt7530_phy_config_init(struct phy_device *phydev)
--{
--      mtk_gephy_config_init(phydev);
--
--      /* Increase post_update_timer */
--      phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
--
--      return 0;
--}
--
--static int mt7531_phy_config_init(struct phy_device *phydev)
--{
--      mtk_gephy_config_init(phydev);
--
--      /* PHY link down power saving enable */
--      phy_set_bits(phydev, 0x17, BIT(4));
--      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
--
--      /* Set TX Pair delay selection */
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
--      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
--
--      return 0;
--}
--
--static struct phy_driver mtk_gephy_driver[] = {
--      {
--              PHY_ID_MATCH_EXACT(0x03a29412),
--              .name           = "MediaTek MT7530 PHY",
--              .config_init    = mt7530_phy_config_init,
--              /* Interrupts are handled by the switch, not the PHY
--               * itself.
--               */
--              .config_intr    = genphy_no_config_intr,
--              .handle_interrupt = genphy_handle_interrupt_no_ack,
--              .suspend        = genphy_suspend,
--              .resume         = genphy_resume,
--              .read_page      = mtk_gephy_read_page,
--              .write_page     = mtk_gephy_write_page,
--      },
--      {
--              PHY_ID_MATCH_EXACT(0x03a29441),
--              .name           = "MediaTek MT7531 PHY",
--              .config_init    = mt7531_phy_config_init,
--              /* Interrupts are handled by the switch, not the PHY
--               * itself.
--               */
--              .config_intr    = genphy_no_config_intr,
--              .handle_interrupt = genphy_handle_interrupt_no_ack,
--              .suspend        = genphy_suspend,
--              .resume         = genphy_resume,
--              .read_page      = mtk_gephy_read_page,
--              .write_page     = mtk_gephy_write_page,
--      },
--};
--
--module_phy_driver(mtk_gephy_driver);
--
--static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
--      { PHY_ID_MATCH_EXACT(0x03a29441) },
--      { PHY_ID_MATCH_EXACT(0x03a29412) },
--      { }
--};
--
--MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
--MODULE_AUTHOR("DENG, Qingfang <[email protected]>");
--MODULE_LICENSE("GPL");
--
--MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -0,0 +1,1610 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+#include <linux/bitfield.h>
-+#include <linux/bitmap.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/nvmem-consumer.h>
-+#include <linux/pinctrl/consumer.h>
-+#include <linux/phy.h>
-+#include <linux/regmap.h>
-+
-+#define MTK_GPHY_ID_MT7981                    0x03a29461
-+#define MTK_GPHY_ID_MT7988                    0x03a29481
-+
-+#define MTK_EXT_PAGE_ACCESS                   0x1f
-+#define MTK_PHY_PAGE_STANDARD                 0x0000
-+#define MTK_PHY_PAGE_EXTENDED_3                       0x0003
-+
-+#define MTK_PHY_LPI_REG_14                    0x14
-+#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK      GENMASK(8, 0)
-+
-+#define MTK_PHY_LPI_REG_1c                    0x1c
-+#define MTK_PHY_SMI_DET_ON_THRESH_MASK                GENMASK(13, 8)
-+
-+#define MTK_PHY_PAGE_EXTENDED_2A30            0x2a30
-+#define MTK_PHY_PAGE_EXTENDED_52B5            0x52b5
-+
-+#define ANALOG_INTERNAL_OPERATION_MAX_US      20
-+#define TXRESERVE_MIN                         0
-+#define TXRESERVE_MAX                         7
-+
-+#define MTK_PHY_ANARG_RG                      0x10
-+#define   MTK_PHY_TCLKOFFSET_MASK             GENMASK(12, 8)
-+
-+/* Registers on MDIO_MMD_VEND1 */
-+#define MTK_PHY_TXVLD_DA_RG                   0x12
-+#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK      GENMASK(15, 10)
-+#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK      GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_A2         0x16
-+#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK      GENMASK(15, 10)
-+#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK      GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_B1         0x17
-+#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK      GENMASK(13, 8)
-+#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK      GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_B2         0x18
-+#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK      GENMASK(13, 8)
-+#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK      GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_C1         0x19
-+#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK      GENMASK(13, 8)
-+#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK      GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_C2         0x20
-+#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK      GENMASK(13, 8)
-+#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK      GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_D1         0x21
-+#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK      GENMASK(13, 8)
-+#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK      GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_D2         0x22
-+#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK      GENMASK(13, 8)
-+#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK      GENMASK(5, 0)
-+
-+#define MTK_PHY_RXADC_CTRL_RG7                        0xc6
-+#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK      GENMASK(9, 8)
-+
-+#define MTK_PHY_RXADC_CTRL_RG9                        0xc8
-+#define   MTK_PHY_DA_RX_PSBN_TBT_MASK         GENMASK(14, 12)
-+#define   MTK_PHY_DA_RX_PSBN_HBT_MASK         GENMASK(10, 8)
-+#define   MTK_PHY_DA_RX_PSBN_GBE_MASK         GENMASK(6, 4)
-+#define   MTK_PHY_DA_RX_PSBN_LP_MASK          GENMASK(2, 0)
-+
-+#define MTK_PHY_LDO_OUTPUT_V                  0xd7
-+
-+#define MTK_PHY_RG_ANA_CAL_RG0                        0xdb
-+#define   MTK_PHY_RG_CAL_CKINV                        BIT(12)
-+#define   MTK_PHY_RG_ANA_CALEN                        BIT(8)
-+#define   MTK_PHY_RG_ZCALEN_A                 BIT(0)
-+
-+#define MTK_PHY_RG_ANA_CAL_RG1                        0xdc
-+#define   MTK_PHY_RG_ZCALEN_B                 BIT(12)
-+#define   MTK_PHY_RG_ZCALEN_C                 BIT(8)
-+#define   MTK_PHY_RG_ZCALEN_D                 BIT(4)
-+#define   MTK_PHY_RG_TXVOS_CALEN              BIT(0)
-+
-+#define MTK_PHY_RG_ANA_CAL_RG5                        0xe0
-+#define   MTK_PHY_RG_REXT_TRIM_MASK           GENMASK(13, 8)
-+
-+#define MTK_PHY_RG_TX_FILTER                  0xfe
-+
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120    0x120
-+#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK       GENMASK(12, 8)
-+#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK       GENMASK(4, 0)
-+
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122    0x122
-+#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK     GENMASK(7, 0)
-+
-+#define MTK_PHY_RG_TESTMUX_ADC_CTRL           0x144
-+#define   MTK_PHY_RG_TXEN_DIG_MASK            GENMASK(5, 5)
-+
-+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B               0x172
-+#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK     GENMASK(13, 8)
-+#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK     GENMASK(6, 0)
-+
-+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D               0x173
-+#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK     GENMASK(13, 8)
-+#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK     GENMASK(6, 0)
-+
-+#define MTK_PHY_RG_AD_CAL_COMP                        0x17a
-+#define   MTK_PHY_AD_CAL_COMP_OUT_MASK                GENMASK(8, 8)
-+
-+#define MTK_PHY_RG_AD_CAL_CLK                 0x17b
-+#define   MTK_PHY_DA_CAL_CLK                  BIT(0)
-+
-+#define MTK_PHY_RG_AD_CALIN                   0x17c
-+#define   MTK_PHY_DA_CALIN_FLAG                       BIT(0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_A             0x17d
-+#define   MTK_PHY_DASN_DAC_IN0_A_MASK         GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_B             0x17e
-+#define   MTK_PHY_DASN_DAC_IN0_B_MASK         GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_C             0x17f
-+#define   MTK_PHY_DASN_DAC_IN0_C_MASK         GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_D             0x180
-+#define   MTK_PHY_DASN_DAC_IN0_D_MASK         GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_A             0x181
-+#define   MTK_PHY_DASN_DAC_IN1_A_MASK         GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_B             0x182
-+#define   MTK_PHY_DASN_DAC_IN1_B_MASK         GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_C             0x183
-+#define   MTK_PHY_DASN_DAC_IN1_C_MASK         GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_D             0x184
-+#define   MTK_PHY_DASN_DAC_IN1_D_MASK         GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DEV1E_REG19b                       0x19b
-+#define   MTK_PHY_BYPASS_DSP_LPI_READY                BIT(8)
-+
-+#define MTK_PHY_RG_LP_IIR2_K1_L                       0x22a
-+#define MTK_PHY_RG_LP_IIR2_K1_U                       0x22b
-+#define MTK_PHY_RG_LP_IIR2_K2_L                       0x22c
-+#define MTK_PHY_RG_LP_IIR2_K2_U                       0x22d
-+#define MTK_PHY_RG_LP_IIR2_K3_L                       0x22e
-+#define MTK_PHY_RG_LP_IIR2_K3_U                       0x22f
-+#define MTK_PHY_RG_LP_IIR2_K4_L                       0x230
-+#define MTK_PHY_RG_LP_IIR2_K4_U                       0x231
-+#define MTK_PHY_RG_LP_IIR2_K5_L                       0x232
-+#define MTK_PHY_RG_LP_IIR2_K5_U                       0x233
-+
-+#define MTK_PHY_RG_DEV1E_REG234                       0x234
-+#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK                GENMASK(0, 0)
-+#define   MTK_PHY_LPF_X_AVERAGE_MASK          GENMASK(7, 4)
-+#define   MTK_PHY_TR_LP_IIR_EEE_EN            BIT(12)
-+
-+#define MTK_PHY_RG_LPF_CNT_VAL                        0x235
-+
-+#define MTK_PHY_RG_DEV1E_REG238                       0x238
-+#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK  GENMASK(8, 0)
-+#define   MTK_PHY_LPI_SLV_SEND_TX_EN          BIT(12)
-+
-+#define MTK_PHY_RG_DEV1E_REG239                       0x239
-+#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK     GENMASK(8, 0)
-+#define   MTK_PHY_LPI_TXPCS_LOC_RCV           BIT(12)
-+
-+#define MTK_PHY_RG_DEV1E_REG27C                       0x27c
-+#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK   GENMASK(12, 8)
-+#define MTK_PHY_RG_DEV1E_REG27D                       0x27d
-+#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK   GENMASK(4, 0)
-+
-+#define MTK_PHY_RG_DEV1E_REG2C7                       0x2c7
-+#define   MTK_PHY_MAX_GAIN_MASK                       GENMASK(4, 0)
-+#define   MTK_PHY_MIN_GAIN_MASK                       GENMASK(12, 8)
-+
-+#define MTK_PHY_RG_DEV1E_REG2D1                       0x2d1
-+#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK        GENMASK(7, 0)
-+#define   MTK_PHY_LPI_SKIP_SD_SLV_TR          BIT(8)
-+#define   MTK_PHY_LPI_TR_READY                        BIT(9)
-+#define   MTK_PHY_LPI_VCO_EEE_STG0_EN         BIT(10)
-+
-+#define MTK_PHY_RG_DEV1E_REG323                       0x323
-+#define   MTK_PHY_EEE_WAKE_MAS_INT_DC         BIT(0)
-+#define   MTK_PHY_EEE_WAKE_SLV_INT_DC         BIT(4)
-+
-+#define MTK_PHY_RG_DEV1E_REG324                       0x324
-+#define   MTK_PHY_SMI_DETCNT_MAX_MASK         GENMASK(5, 0)
-+#define   MTK_PHY_SMI_DET_MAX_EN              BIT(8)
-+
-+#define MTK_PHY_RG_DEV1E_REG326                       0x326
-+#define   MTK_PHY_LPI_MODE_SD_ON              BIT(0)
-+#define   MTK_PHY_RESET_RANDUPD_CNT           BIT(1)
-+#define   MTK_PHY_TREC_UPDATE_ENAB_CLR                BIT(2)
-+#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF       BIT(4)
-+#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP    BIT(5)
-+
-+#define MTK_PHY_LDO_PUMP_EN_PAIRAB            0x502
-+#define MTK_PHY_LDO_PUMP_EN_PAIRCD            0x503
-+
-+#define MTK_PHY_DA_TX_R50_PAIR_A              0x53d
-+#define MTK_PHY_DA_TX_R50_PAIR_B              0x53e
-+#define MTK_PHY_DA_TX_R50_PAIR_C              0x53f
-+#define MTK_PHY_DA_TX_R50_PAIR_D              0x540
-+
-+/* Registers on MDIO_MMD_VEND2 */
-+#define MTK_PHY_LED0_ON_CTRL                  0x24
-+#define MTK_PHY_LED1_ON_CTRL                  0x26
-+#define   MTK_PHY_LED_ON_MASK                 GENMASK(6, 0)
-+#define   MTK_PHY_LED_ON_LINK1000             BIT(0)
-+#define   MTK_PHY_LED_ON_LINK100              BIT(1)
-+#define   MTK_PHY_LED_ON_LINK10                       BIT(2)
-+#define   MTK_PHY_LED_ON_LINK                 (MTK_PHY_LED_ON_LINK10 |\
-+                                               MTK_PHY_LED_ON_LINK100 |\
-+                                               MTK_PHY_LED_ON_LINK1000)
-+#define   MTK_PHY_LED_ON_LINKDOWN             BIT(3)
-+#define   MTK_PHY_LED_ON_FDX                  BIT(4) /* Full duplex */
-+#define   MTK_PHY_LED_ON_HDX                  BIT(5) /* Half duplex */
-+#define   MTK_PHY_LED_ON_FORCE_ON             BIT(6)
-+#define   MTK_PHY_LED_ON_POLARITY             BIT(14)
-+#define   MTK_PHY_LED_ON_ENABLE                       BIT(15)
-+
-+#define MTK_PHY_LED0_BLINK_CTRL                       0x25
-+#define MTK_PHY_LED1_BLINK_CTRL                       0x27
-+#define   MTK_PHY_LED_BLINK_1000TX            BIT(0)
-+#define   MTK_PHY_LED_BLINK_1000RX            BIT(1)
-+#define   MTK_PHY_LED_BLINK_100TX             BIT(2)
-+#define   MTK_PHY_LED_BLINK_100RX             BIT(3)
-+#define   MTK_PHY_LED_BLINK_10TX              BIT(4)
-+#define   MTK_PHY_LED_BLINK_10RX              BIT(5)
-+#define   MTK_PHY_LED_BLINK_RX                        (MTK_PHY_LED_BLINK_10RX |\
-+                                               MTK_PHY_LED_BLINK_100RX |\
-+                                               MTK_PHY_LED_BLINK_1000RX)
-+#define   MTK_PHY_LED_BLINK_TX                        (MTK_PHY_LED_BLINK_10TX |\
-+                                               MTK_PHY_LED_BLINK_100TX |\
-+                                               MTK_PHY_LED_BLINK_1000TX)
-+#define   MTK_PHY_LED_BLINK_COLLISION         BIT(6)
-+#define   MTK_PHY_LED_BLINK_RX_CRC_ERR                BIT(7)
-+#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR               BIT(8)
-+#define   MTK_PHY_LED_BLINK_FORCE_BLINK               BIT(9)
-+
-+#define MTK_PHY_LED1_DEFAULT_POLARITIES               BIT(1)
-+
-+#define MTK_PHY_RG_BG_RASEL                   0x115
-+#define   MTK_PHY_RG_BG_RASEL_MASK            GENMASK(2, 0)
-+
-+/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
-+#define RG_GPIO_MISC_TPBANK0                  0x6f0
-+#define   RG_GPIO_MISC_TPBANK0_BOOTMODE               GENMASK(11, 8)
-+
-+/* These macro privides efuse parsing for internal phy. */
-+#define EFS_DA_TX_I2MPB_A(x)                  (((x) >> 0) & GENMASK(5, 0))
-+#define EFS_DA_TX_I2MPB_B(x)                  (((x) >> 6) & GENMASK(5, 0))
-+#define EFS_DA_TX_I2MPB_C(x)                  (((x) >> 12) & GENMASK(5, 0))
-+#define EFS_DA_TX_I2MPB_D(x)                  (((x) >> 18) & GENMASK(5, 0))
-+#define EFS_DA_TX_AMP_OFFSET_A(x)             (((x) >> 24) & GENMASK(5, 0))
-+
-+#define EFS_DA_TX_AMP_OFFSET_B(x)             (((x) >> 0) & GENMASK(5, 0))
-+#define EFS_DA_TX_AMP_OFFSET_C(x)             (((x) >> 6) & GENMASK(5, 0))
-+#define EFS_DA_TX_AMP_OFFSET_D(x)             (((x) >> 12) & GENMASK(5, 0))
-+#define EFS_DA_TX_R50_A(x)                    (((x) >> 18) & GENMASK(5, 0))
-+#define EFS_DA_TX_R50_B(x)                    (((x) >> 24) & GENMASK(5, 0))
-+
-+#define EFS_DA_TX_R50_C(x)                    (((x) >> 0) & GENMASK(5, 0))
-+#define EFS_DA_TX_R50_D(x)                    (((x) >> 6) & GENMASK(5, 0))
-+
-+#define EFS_RG_BG_RASEL(x)                    (((x) >> 4) & GENMASK(2, 0))
-+#define EFS_RG_REXT_TRIM(x)                   (((x) >> 7) & GENMASK(5, 0))
-+
-+enum {
-+      NO_PAIR,
-+      PAIR_A,
-+      PAIR_B,
-+      PAIR_C,
-+      PAIR_D,
-+};
-+
-+enum calibration_mode {
-+      EFUSE_K,
-+      SW_K
-+};
-+
-+enum CAL_ITEM {
-+      REXT,
-+      TX_OFFSET,
-+      TX_AMP,
-+      TX_R50,
-+      TX_VCM
-+};
-+
-+enum CAL_MODE {
-+      EFUSE_M,
-+      SW_M
-+};
-+
-+#define MTK_PHY_LED_STATE_FORCE_ON    0
-+#define MTK_PHY_LED_STATE_FORCE_BLINK 1
-+#define MTK_PHY_LED_STATE_NETDEV      2
-+
-+struct mtk_socphy_priv {
-+      unsigned long           led_state;
-+};
-+
-+struct mtk_socphy_shared {
-+      u32                     boottrap;
-+      struct mtk_socphy_priv  priv[4];
-+};
-+
-+static int mtk_socphy_read_page(struct phy_device *phydev)
-+{
-+      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-+}
-+
-+static int mtk_socphy_write_page(struct phy_device *phydev, int page)
-+{
-+      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-+}
-+
-+/* One calibration cycle consists of:
-+ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
-+ *   until AD_CAL_COMP is ready to output calibration result.
-+ * 2.Wait until DA_CAL_CLK is available.
-+ * 3.Fetch AD_CAL_COMP_OUT.
-+ */
-+static int cal_cycle(struct phy_device *phydev, int devad,
-+                   u32 regnum, u16 mask, u16 cal_val)
-+{
-+      int reg_val;
-+      int ret;
-+
-+      phy_modify_mmd(phydev, devad, regnum,
-+                     mask, cal_val);
-+      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-+                       MTK_PHY_DA_CALIN_FLAG);
-+
-+      ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-+                                      MTK_PHY_RG_AD_CAL_CLK, reg_val,
-+                                      reg_val & MTK_PHY_DA_CAL_CLK, 500,
-+                                      ANALOG_INTERNAL_OPERATION_MAX_US,
-+                                      false);
-+      if (ret) {
-+              phydev_err(phydev, "Calibration cycle timeout\n");
-+              return ret;
-+      }
-+
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-+                         MTK_PHY_DA_CALIN_FLAG);
-+      ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
-+      if (ret < 0)
-+              return ret;
-+      ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
-+      phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
-+
-+      return ret;
-+}
-+
-+static int rext_fill_result(struct phy_device *phydev, u16 *buf)
-+{
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
-+                     MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
-+                     MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
-+
-+      return 0;
-+}
-+
-+static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
-+{
-+      u16 rext_cal_val[2];
-+
-+      rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
-+      rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
-+      rext_fill_result(phydev, rext_cal_val);
-+
-+      return 0;
-+}
-+
-+static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
-+{
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-+                     MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-+                     MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-+                     MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-+                     MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
-+
-+      return 0;
-+}
-+
-+static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
-+{
-+      u16 tx_offset_cal_val[4];
-+
-+      tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
-+      tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
-+      tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
-+      tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
-+
-+      tx_offset_fill_result(phydev, tx_offset_cal_val);
-+
-+      return 0;
-+}
-+
-+static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
-+{
-+      const int vals_9481[16] = { 10, 6, 6, 10,
-+                                  10, 6, 6, 10,
-+                                  10, 6, 6, 10,
-+                                  10, 6, 6, 10 };
-+      const int vals_9461[16] = { 7, 1, 4, 7,
-+                                  7, 1, 4, 7,
-+                                  7, 1, 4, 7,
-+                                  7, 1, 4, 7 };
-+      int bias[16] = {};
-+      int i;
-+
-+      switch (phydev->drv->phy_id) {
-+      case MTK_GPHY_ID_MT7981:
-+              /* We add some calibration to efuse values
-+               * due to board level influence.
-+               * GBE: +7, TBT: +1, HBT: +4, TST: +7
-+               */
-+              memcpy(bias, (const void *)vals_9461, sizeof(bias));
-+              break;
-+      case MTK_GPHY_ID_MT7988:
-+              memcpy(bias, (const void *)vals_9481, sizeof(bias));
-+              break;
-+      }
-+
-+      /* Prevent overflow */
-+      for (i = 0; i < 12; i++) {
-+              if (buf[i >> 2] + bias[i] > 63) {
-+                      buf[i >> 2] = 63;
-+                      bias[i] = 0;
-+              }
-+      }
-+
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-+                     MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+                                buf[0] + bias[0]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-+                     MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+                                buf[0] + bias[1]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-+                     MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+                                buf[0] + bias[2]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-+                     MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+                                buf[0] + bias[3]));
-+
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-+                     MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+                                buf[1] + bias[4]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-+                     MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+                                buf[1] + bias[5]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-+                     MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+                                buf[1] + bias[6]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-+                     MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+                                buf[1] + bias[7]));
-+
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-+                     MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+                                buf[2] + bias[8]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-+                     MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+                                buf[2] + bias[9]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-+                     MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+                                buf[2] + bias[10]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-+                     MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+                                buf[2] + bias[11]));
-+
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-+                     MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+                                buf[3] + bias[12]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-+                     MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+                                buf[3] + bias[13]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-+                     MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+                                buf[3] + bias[14]));
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-+                     MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+                     FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+                                buf[3] + bias[15]));
-+
-+      return 0;
-+}
-+
-+static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
-+{
-+      u16 tx_amp_cal_val[4];
-+
-+      tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
-+      tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
-+      tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
-+      tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
-+      tx_amp_fill_result(phydev, tx_amp_cal_val);
-+
-+      return 0;
-+}
-+
-+static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
-+                            u8 txg_calen_x)
-+{
-+      int bias = 0;
-+      u16 reg, val;
-+
-+      if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
-+              bias = -1;
-+
-+      val = clamp_val(bias + tx_r50_cal_val, 0, 63);
-+
-+      switch (txg_calen_x) {
-+      case PAIR_A:
-+              reg = MTK_PHY_DA_TX_R50_PAIR_A;
-+              break;
-+      case PAIR_B:
-+              reg = MTK_PHY_DA_TX_R50_PAIR_B;
-+              break;
-+      case PAIR_C:
-+              reg = MTK_PHY_DA_TX_R50_PAIR_C;
-+              break;
-+      case PAIR_D:
-+              reg = MTK_PHY_DA_TX_R50_PAIR_D;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
-+
-+      return 0;
-+}
-+
-+static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
-+                          u8 txg_calen_x)
-+{
-+      u16 tx_r50_cal_val;
-+
-+      switch (txg_calen_x) {
-+      case PAIR_A:
-+              tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
-+              break;
-+      case PAIR_B:
-+              tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
-+              break;
-+      case PAIR_C:
-+              tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
-+              break;
-+      case PAIR_D:
-+              tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+      tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
-+
-+      return 0;
-+}
-+
-+static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
-+{
-+      u8 lower_idx, upper_idx, txreserve_val;
-+      u8 lower_ret, upper_ret;
-+      int ret;
-+
-+      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+                       MTK_PHY_RG_ANA_CALEN);
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+                         MTK_PHY_RG_CAL_CKINV);
-+      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-+                       MTK_PHY_RG_TXVOS_CALEN);
-+
-+      switch (rg_txreserve_x) {
-+      case PAIR_A:
-+              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                                 MTK_PHY_RG_DASN_DAC_IN0_A,
-+                                 MTK_PHY_DASN_DAC_IN0_A_MASK);
-+              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                                 MTK_PHY_RG_DASN_DAC_IN1_A,
-+                                 MTK_PHY_DASN_DAC_IN1_A_MASK);
-+              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                               MTK_PHY_RG_ANA_CAL_RG0,
-+                               MTK_PHY_RG_ZCALEN_A);
-+              break;
-+      case PAIR_B:
-+              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                                 MTK_PHY_RG_DASN_DAC_IN0_B,
-+                                 MTK_PHY_DASN_DAC_IN0_B_MASK);
-+              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                                 MTK_PHY_RG_DASN_DAC_IN1_B,
-+                                 MTK_PHY_DASN_DAC_IN1_B_MASK);
-+              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                               MTK_PHY_RG_ANA_CAL_RG1,
-+                               MTK_PHY_RG_ZCALEN_B);
-+              break;
-+      case PAIR_C:
-+              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                                 MTK_PHY_RG_DASN_DAC_IN0_C,
-+                                 MTK_PHY_DASN_DAC_IN0_C_MASK);
-+              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                                 MTK_PHY_RG_DASN_DAC_IN1_C,
-+                                 MTK_PHY_DASN_DAC_IN1_C_MASK);
-+              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                               MTK_PHY_RG_ANA_CAL_RG1,
-+                               MTK_PHY_RG_ZCALEN_C);
-+              break;
-+      case PAIR_D:
-+              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                                 MTK_PHY_RG_DASN_DAC_IN0_D,
-+                                 MTK_PHY_DASN_DAC_IN0_D_MASK);
-+              phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                                 MTK_PHY_RG_DASN_DAC_IN1_D,
-+                                 MTK_PHY_DASN_DAC_IN1_D_MASK);
-+              phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                               MTK_PHY_RG_ANA_CAL_RG1,
-+                               MTK_PHY_RG_ZCALEN_D);
-+              break;
-+      default:
-+              ret = -EINVAL;
-+              goto restore;
-+      }
-+
-+      lower_idx = TXRESERVE_MIN;
-+      upper_idx = TXRESERVE_MAX;
-+
-+      phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
-+      while ((upper_idx - lower_idx) > 1) {
-+              txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
-+              ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-+                              MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+                              MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+                              MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+                              MTK_PHY_DA_RX_PSBN_LP_MASK,
-+                              txreserve_val << 12 | txreserve_val << 8 |
-+                              txreserve_val << 4 | txreserve_val);
-+              if (ret == 1) {
-+                      upper_idx = txreserve_val;
-+                      upper_ret = ret;
-+              } else if (ret == 0) {
-+                      lower_idx = txreserve_val;
-+                      lower_ret = ret;
-+              } else {
-+                      goto restore;
-+              }
-+      }
-+
-+      if (lower_idx == TXRESERVE_MIN) {
-+              lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-+                                    MTK_PHY_RXADC_CTRL_RG9,
-+                                    MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+                                    MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+                                    MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+                                    MTK_PHY_DA_RX_PSBN_LP_MASK,
-+                                    lower_idx << 12 | lower_idx << 8 |
-+                                    lower_idx << 4 | lower_idx);
-+              ret = lower_ret;
-+      } else if (upper_idx == TXRESERVE_MAX) {
-+              upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-+                                    MTK_PHY_RXADC_CTRL_RG9,
-+                                    MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+                                    MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+                                    MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+                                    MTK_PHY_DA_RX_PSBN_LP_MASK,
-+                                    upper_idx << 12 | upper_idx << 8 |
-+                                    upper_idx << 4 | upper_idx);
-+              ret = upper_ret;
-+      }
-+      if (ret < 0)
-+              goto restore;
-+
-+      /* We calibrate TX-VCM in different logic. Check upper index and then
-+       * lower index. If this calibration is valid, apply lower index's
-+       * result.
-+       */
-+      ret = upper_ret - lower_ret;
-+      if (ret == 1) {
-+              ret = 0;
-+              /* Make sure we use upper_idx in our calibration system */
-+              cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-+                        MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+                        MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+                        MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+                        MTK_PHY_DA_RX_PSBN_LP_MASK,
-+                        upper_idx << 12 | upper_idx << 8 |
-+                        upper_idx << 4 | upper_idx);
-+              phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
-+      } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
-+                 lower_ret == 1) {
-+              ret = 0;
-+              cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-+                        MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+                        MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+                        MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+                        MTK_PHY_DA_RX_PSBN_LP_MASK,
-+                        lower_idx << 12 | lower_idx << 8 |
-+                        lower_idx << 4 | lower_idx);
-+              phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
-+                          lower_idx);
-+      } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
-+                 lower_ret == 0) {
-+              ret = 0;
-+              phydev_warn(phydev,
-+                          "TX-VCM SW cal result at high margin 0x%x\n",
-+                          upper_idx);
-+      } else {
-+              ret = -EINVAL;
-+      }
-+
-+restore:
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+                         MTK_PHY_RG_ANA_CALEN);
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-+                         MTK_PHY_RG_TXVOS_CALEN);
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+                         MTK_PHY_RG_ZCALEN_A);
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-+                         MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
-+                         MTK_PHY_RG_ZCALEN_D);
-+
-+      return ret;
-+}
-+
-+static void mt798x_phy_common_finetune(struct phy_device *phydev)
-+{
-+      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+      /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
-+      __phy_write(phydev, 0x11, 0xc71);
-+      __phy_write(phydev, 0x12, 0xc);
-+      __phy_write(phydev, 0x10, 0x8fae);
-+
-+      /* EnabRandUpdTrig = 1 */
-+      __phy_write(phydev, 0x11, 0x2f00);
-+      __phy_write(phydev, 0x12, 0xe);
-+      __phy_write(phydev, 0x10, 0x8fb0);
-+
-+      /* NormMseLoThresh = 85 */
-+      __phy_write(phydev, 0x11, 0x55a0);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x83aa);
-+
-+      /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
-+      __phy_write(phydev, 0x11, 0x240);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x9680);
-+
-+      /* TrFreeze = 0 (mt7988 default) */
-+      __phy_write(phydev, 0x11, 0x0);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x9686);
-+
-+      /* SSTrKp100 = 5 */
-+      /* SSTrKf100 = 6 */
-+      /* SSTrKp1000Mas = 5 */
-+      /* SSTrKf1000Mas = 6 */
-+      /* SSTrKp1000Slv = 5 */
-+      /* SSTrKf1000Slv = 6 */
-+      __phy_write(phydev, 0x11, 0xbaef);
-+      __phy_write(phydev, 0x12, 0x2e);
-+      __phy_write(phydev, 0x10, 0x968c);
-+      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+}
-+
-+static void mt7981_phy_finetune(struct phy_device *phydev)
-+{
-+      u16 val[8] = { 0x01ce, 0x01c1,
-+                     0x020f, 0x0202,
-+                     0x03d0, 0x03c0,
-+                     0x0013, 0x0005 };
-+      int i, k;
-+
-+      /* 100M eye finetune:
-+       * Keep middle level of TX MLT3 shapper as default.
-+       * Only change TX MLT3 overshoot level here.
-+       */
-+      for (k = 0, i = 1; i < 12; i++) {
-+              if (i % 3 == 0)
-+                      continue;
-+              phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
-+      }
-+
-+      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+      /* ResetSyncOffset = 6 */
-+      __phy_write(phydev, 0x11, 0x600);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x8fc0);
-+
-+      /* VgaDecRate = 1 */
-+      __phy_write(phydev, 0x11, 0x4c2a);
-+      __phy_write(phydev, 0x12, 0x3e);
-+      __phy_write(phydev, 0x10, 0x8fa4);
-+
-+      /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
-+       * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
-+       */
-+      __phy_write(phydev, 0x11, 0xd10a);
-+      __phy_write(phydev, 0x12, 0x34);
-+      __phy_write(phydev, 0x10, 0x8f82);
-+
-+      /* VcoSlicerThreshBitsHigh */
-+      __phy_write(phydev, 0x11, 0x5555);
-+      __phy_write(phydev, 0x12, 0x55);
-+      __phy_write(phydev, 0x10, 0x8ec0);
-+      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+      /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-+                     MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+                     MTK_PHY_LPF_X_AVERAGE_MASK,
-+                     BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
-+
-+      /* rg_tr_lpf_cnt_val = 512 */
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
-+
-+      /* IIR2 related */
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
-+
-+      /* FFE peaking */
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
-+                     MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
-+                     MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
-+
-+      /* Disable LDO pump */
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
-+      /* Adjust LDO output voltage */
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
-+}
-+
-+static void mt7988_phy_finetune(struct phy_device *phydev)
-+{
-+      u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
-+                      0x020d, 0x0206, 0x0384, 0x03d0,
-+                      0x03c6, 0x030a, 0x0011, 0x0005 };
-+      int i;
-+
-+      /* Set default MLT3 shaper first */
-+      for (i = 0; i < 12; i++)
-+              phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
-+
-+      /* TCT finetune */
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
-+
-+      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+      /* ResetSyncOffset = 5 */
-+      __phy_write(phydev, 0x11, 0x500);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x8fc0);
-+
-+      /* VgaDecRate is 1 at default on mt7988 */
-+
-+      /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
-+       * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
-+       */
-+      __phy_write(phydev, 0x11, 0xb90a);
-+      __phy_write(phydev, 0x12, 0x6f);
-+      __phy_write(phydev, 0x10, 0x8f82);
-+
-+      /* RemAckCntLimitCtrl = 1 */
-+      __phy_write(phydev, 0x11, 0xfbba);
-+      __phy_write(phydev, 0x12, 0xc3);
-+      __phy_write(phydev, 0x10, 0x87f8);
-+
-+      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+      /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-+                     MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+                     MTK_PHY_LPF_X_AVERAGE_MASK,
-+                     BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
-+
-+      /* rg_tr_lpf_cnt_val = 1023 */
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
-+}
-+
-+static void mt798x_phy_eee(struct phy_device *phydev)
-+{
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
-+                     MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
-+                     MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
-+                     FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
-+                     FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
-+
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-+                     MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+                     FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+                                0xff));
-+
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                         MTK_PHY_RG_TESTMUX_ADC_CTRL,
-+                         MTK_PHY_RG_TXEN_DIG_MASK);
-+
-+      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                       MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
-+
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+                         MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
-+
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
-+                     MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
-+                     MTK_PHY_LPI_SLV_SEND_TX_EN,
-+                     FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
-+
-+      /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
-+                         MTK_PHY_LPI_TXPCS_LOC_RCV);
-+
-+      /* This also fixes some IoT issues, such as CH340 */
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
-+                     MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
-+                     FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
-+                     FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
-+
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
-+                     MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-+                     FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-+                                0x33) |
-+                     MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
-+                     MTK_PHY_LPI_VCO_EEE_STG0_EN);
-+
-+      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
-+                       MTK_PHY_EEE_WAKE_MAS_INT_DC |
-+                       MTK_PHY_EEE_WAKE_SLV_INT_DC);
-+
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
-+                     MTK_PHY_SMI_DETCNT_MAX_MASK,
-+                     FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
-+                     MTK_PHY_SMI_DET_MAX_EN);
-+
-+      phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
-+                       MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
-+                       MTK_PHY_TREC_UPDATE_ENAB_CLR |
-+                       MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
-+                       MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
-+
-+      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+      /* Regsigdet_sel_1000 = 0 */
-+      __phy_write(phydev, 0x11, 0xb);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x9690);
-+
-+      /* REG_EEE_st2TrKf1000 = 2 */
-+      __phy_write(phydev, 0x11, 0x114f);
-+      __phy_write(phydev, 0x12, 0x2);
-+      __phy_write(phydev, 0x10, 0x969a);
-+
-+      /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
-+      __phy_write(phydev, 0x11, 0x3028);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x969e);
-+
-+      /* RegEEE_slv_wake_int_timer_tar = 8 */
-+      __phy_write(phydev, 0x11, 0x5010);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x96a0);
-+
-+      /* RegEEE_trfreeze_timer2 = 586 */
-+      __phy_write(phydev, 0x11, 0x24a);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x96a8);
-+
-+      /* RegEEE100Stg1_tar = 16 */
-+      __phy_write(phydev, 0x11, 0x3210);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x96b8);
-+
-+      /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
-+      __phy_write(phydev, 0x11, 0x1463);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x96ca);
-+
-+      /* DfeTailEnableVgaThresh1000 = 27 */
-+      __phy_write(phydev, 0x11, 0x36);
-+      __phy_write(phydev, 0x12, 0x0);
-+      __phy_write(phydev, 0x10, 0x8f80);
-+      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
-+      __phy_modify(phydev, MTK_PHY_LPI_REG_14,
-+                   MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
-+                   FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
-+
-+      __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
-+                   FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
-+      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+      phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+                     MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-+                     MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+                     FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+                                0xff));
-+}
-+
-+static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
-+                u8 start_pair, u8 end_pair)
-+{
-+      u8 pair_n;
-+      int ret;
-+
-+      for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-+              /* TX_OFFSET & TX_AMP have no SW calibration. */
-+              switch (cal_item) {
-+              case TX_VCM:
-+                      ret = tx_vcm_cal_sw(phydev, pair_n);
-+                      break;
-+              default:
-+                      return -EINVAL;
-+              }
-+              if (ret)
-+                      return ret;
-+      }
-+      return 0;
-+}
-+
-+static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
-+                   u8 start_pair, u8 end_pair, u32 *buf)
-+{
-+      u8 pair_n;
-+      int ret;
-+
-+      for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-+              /* TX_VCM has no efuse calibration. */
-+              switch (cal_item) {
-+              case REXT:
-+                      ret = rext_cal_efuse(phydev, buf);
-+                      break;
-+              case TX_OFFSET:
-+                      ret = tx_offset_cal_efuse(phydev, buf);
-+                      break;
-+              case TX_AMP:
-+                      ret = tx_amp_cal_efuse(phydev, buf);
-+                      break;
-+              case TX_R50:
-+                      ret = tx_r50_cal_efuse(phydev, buf, pair_n);
-+                      break;
-+              default:
-+                      return -EINVAL;
-+              }
-+              if (ret)
-+                      return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
-+                   enum CAL_MODE cal_mode, u8 start_pair,
-+                   u8 end_pair, u32 *buf)
-+{
-+      int ret;
-+
-+      switch (cal_mode) {
-+      case EFUSE_M:
-+              ret = cal_efuse(phydev, cal_item, start_pair,
-+                              end_pair, buf);
-+              break;
-+      case SW_M:
-+              ret = cal_sw(phydev, cal_item, start_pair, end_pair);
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      if (ret) {
-+              phydev_err(phydev, "cal %d failed\n", cal_item);
-+              return -EIO;
-+      }
-+
-+      return 0;
-+}
-+
-+static int mt798x_phy_calibration(struct phy_device *phydev)
-+{
-+      struct nvmem_cell *cell;
-+      int ret = 0;
-+      size_t len;
-+      u32 *buf;
-+
-+      cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
-+      if (IS_ERR(cell)) {
-+              if (PTR_ERR(cell) == -EPROBE_DEFER)
-+                      return PTR_ERR(cell);
-+              return 0;
-+      }
-+
-+      buf = (u32 *)nvmem_cell_read(cell, &len);
-+      if (IS_ERR(buf))
-+              return PTR_ERR(buf);
-+      nvmem_cell_put(cell);
-+
-+      if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
-+              phydev_err(phydev, "invalid efuse data\n");
-+              ret = -EINVAL;
-+              goto out;
-+      }
-+
-+      ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-+      if (ret)
-+              goto out;
-+      ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-+      if (ret)
-+              goto out;
-+      ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-+      if (ret)
-+              goto out;
-+      ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
-+      if (ret)
-+              goto out;
-+      ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
-+      if (ret)
-+              goto out;
-+
-+out:
-+      kfree(buf);
-+      return ret;
-+}
-+
-+static int mt798x_phy_config_init(struct phy_device *phydev)
-+{
-+      switch (phydev->drv->phy_id) {
-+      case MTK_GPHY_ID_MT7981:
-+              mt7981_phy_finetune(phydev);
-+              break;
-+      case MTK_GPHY_ID_MT7988:
-+              mt7988_phy_finetune(phydev);
-+              break;
-+      }
-+
-+      mt798x_phy_common_finetune(phydev);
-+      mt798x_phy_eee(phydev);
-+
-+      return mt798x_phy_calibration(phydev);
-+}
-+
-+static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-+                                  bool on)
-+{
-+      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+      struct mtk_socphy_priv *priv = phydev->priv;
-+      bool changed;
-+
-+      if (on)
-+              changed = !test_and_set_bit(bit_on, &priv->led_state);
-+      else
-+              changed = !!test_and_clear_bit(bit_on, &priv->led_state);
-+
-+      changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-+                                      (index ? 16 : 0), &priv->led_state);
-+      if (changed)
-+              return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+                                    MTK_PHY_LED1_ON_CTRL :
-+                                    MTK_PHY_LED0_ON_CTRL,
-+                                    MTK_PHY_LED_ON_MASK,
-+                                    on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-+      else
-+              return 0;
-+}
-+
-+static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-+                                     bool blinking)
-+{
-+      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+                               (index ? 16 : 0);
-+      struct mtk_socphy_priv *priv = phydev->priv;
-+      bool changed;
-+
-+      if (blinking)
-+              changed = !test_and_set_bit(bit_blink, &priv->led_state);
-+      else
-+              changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
-+
-+      changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-+                            (index ? 16 : 0), &priv->led_state);
-+      if (changed)
-+              return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+                                   MTK_PHY_LED1_BLINK_CTRL :
-+                                   MTK_PHY_LED0_BLINK_CTRL,
-+                                   blinking ?
-+                                   MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-+      else
-+              return 0;
-+}
-+
-+static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
-+                                  unsigned long *delay_on,
-+                                  unsigned long *delay_off)
-+{
-+      bool blinking = false;
-+      int err = 0;
-+
-+      if (index > 1)
-+              return -EINVAL;
-+
-+      if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-+              blinking = true;
-+              *delay_on = 50;
-+              *delay_off = 50;
-+      }
-+
-+      err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
-+      if (err)
-+              return err;
-+
-+      return mt798x_phy_hw_led_on_set(phydev, index, false);
-+}
-+
-+static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
-+                                       u8 index, enum led_brightness value)
-+{
-+      int err;
-+
-+      err = mt798x_phy_hw_led_blink_set(phydev, index, false);
-+      if (err)
-+              return err;
-+
-+      return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
-+}
-+
-+static const unsigned long supported_triggers =
-+      BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-+      BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-+      BIT(TRIGGER_NETDEV_LINK)        |
-+      BIT(TRIGGER_NETDEV_LINK_10)     |
-+      BIT(TRIGGER_NETDEV_LINK_100)    |
-+      BIT(TRIGGER_NETDEV_LINK_1000)   |
-+      BIT(TRIGGER_NETDEV_RX)          |
-+      BIT(TRIGGER_NETDEV_TX);
-+
-+static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+                                        unsigned long rules)
-+{
-+      if (index > 1)
-+              return -EINVAL;
-+
-+      /* All combinations of the supported triggers are allowed */
-+      if (rules & ~supported_triggers)
-+              return -EOPNOTSUPP;
-+
-+      return 0;
-+};
-+
-+static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+                                       unsigned long *rules)
-+{
-+      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+                               (index ? 16 : 0);
-+      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+      struct mtk_socphy_priv *priv = phydev->priv;
-+      int on, blink;
-+
-+      if (index > 1)
-+              return -EINVAL;
-+
-+      on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+                        index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
-+
-+      if (on < 0)
-+              return -EIO;
-+
-+      blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+                           index ? MTK_PHY_LED1_BLINK_CTRL :
-+                                   MTK_PHY_LED0_BLINK_CTRL);
-+      if (blink < 0)
-+              return -EIO;
-+
-+      if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-+                 MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-+          (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
-+              set_bit(bit_netdev, &priv->led_state);
-+      else
-+              clear_bit(bit_netdev, &priv->led_state);
-+
-+      if (on & MTK_PHY_LED_ON_FORCE_ON)
-+              set_bit(bit_on, &priv->led_state);
-+      else
-+              clear_bit(bit_on, &priv->led_state);
-+
-+      if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-+              set_bit(bit_blink, &priv->led_state);
-+      else
-+              clear_bit(bit_blink, &priv->led_state);
-+
-+      if (!rules)
-+              return 0;
-+
-+      if (on & MTK_PHY_LED_ON_LINK)
-+              *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+      if (on & MTK_PHY_LED_ON_LINK10)
-+              *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+      if (on & MTK_PHY_LED_ON_LINK100)
-+              *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+      if (on & MTK_PHY_LED_ON_LINK1000)
-+              *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+      if (on & MTK_PHY_LED_ON_FDX)
-+              *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
-+
-+      if (on & MTK_PHY_LED_ON_HDX)
-+              *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
-+
-+      if (blink & MTK_PHY_LED_BLINK_RX)
-+              *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+      if (blink & MTK_PHY_LED_BLINK_TX)
-+              *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+      return 0;
-+};
-+
-+static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+                                       unsigned long rules)
-+{
-+      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+      struct mtk_socphy_priv *priv = phydev->priv;
-+      u16 on = 0, blink = 0;
-+      int ret;
-+
-+      if (index > 1)
-+              return -EINVAL;
-+
-+      if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-+              on |= MTK_PHY_LED_ON_FDX;
-+
-+      if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-+              on |= MTK_PHY_LED_ON_HDX;
-+
-+      if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-+              on |= MTK_PHY_LED_ON_LINK10;
-+
-+      if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-+              on |= MTK_PHY_LED_ON_LINK100;
-+
-+      if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-+              on |= MTK_PHY_LED_ON_LINK1000;
-+
-+      if (rules & BIT(TRIGGER_NETDEV_RX)) {
-+              blink |= (on & MTK_PHY_LED_ON_LINK) ?
-+                        (((on & MTK_PHY_LED_ON_LINK10) ?
-+                          MTK_PHY_LED_BLINK_10RX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK100) ?
-+                          MTK_PHY_LED_BLINK_100RX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK1000) ?
-+                          MTK_PHY_LED_BLINK_1000RX : 0)) :
-+                        MTK_PHY_LED_BLINK_RX;
-+      }
-+
-+      if (rules & BIT(TRIGGER_NETDEV_TX)) {
-+              blink |= (on & MTK_PHY_LED_ON_LINK) ?
-+                        (((on & MTK_PHY_LED_ON_LINK10) ?
-+                          MTK_PHY_LED_BLINK_10TX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK100) ?
-+                          MTK_PHY_LED_BLINK_100TX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK1000) ?
-+                          MTK_PHY_LED_BLINK_1000TX : 0)) :
-+                        MTK_PHY_LED_BLINK_TX;
-+      }
-+
-+      if (blink || on)
-+              set_bit(bit_netdev, &priv->led_state);
-+      else
-+              clear_bit(bit_netdev, &priv->led_state);
-+
-+      ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+                              MTK_PHY_LED1_ON_CTRL :
-+                              MTK_PHY_LED0_ON_CTRL,
-+                           MTK_PHY_LED_ON_FDX     |
-+                           MTK_PHY_LED_ON_HDX     |
-+                           MTK_PHY_LED_ON_LINK,
-+                           on);
-+
-+      if (ret)
-+              return ret;
-+
-+      return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+                              MTK_PHY_LED1_BLINK_CTRL :
-+                              MTK_PHY_LED0_BLINK_CTRL, blink);
-+};
-+
-+static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
-+{
-+      struct mtk_socphy_shared *priv = phydev->shared->priv;
-+      u32 polarities;
-+
-+      if (led_num == 0)
-+              polarities = ~(priv->boottrap);
-+      else
-+              polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
-+
-+      if (polarities & BIT(phydev->mdio.addr))
-+              return true;
-+
-+      return false;
-+}
-+
-+static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
-+{
-+      struct pinctrl *pinctrl;
-+      int index;
-+
-+      /* Setup LED polarity according to bootstrap use of LED pins */
-+      for (index = 0; index < 2; ++index)
-+              phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+                              MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-+                             MTK_PHY_LED_ON_POLARITY,
-+                             mt7988_phy_led_get_polarity(phydev, index) ?
-+                              MTK_PHY_LED_ON_POLARITY : 0);
-+
-+      /* Only now setup pinctrl to avoid bogus blinking */
-+      pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
-+      if (IS_ERR(pinctrl))
-+              dev_err(&phydev->mdio.bus->dev,
-+                      "Failed to setup PHY LED pinctrl\n");
-+
-+      return 0;
-+}
-+
-+static int mt7988_phy_probe_shared(struct phy_device *phydev)
-+{
-+      struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
-+      struct mtk_socphy_shared *shared = phydev->shared->priv;
-+      struct regmap *regmap;
-+      u32 reg;
-+      int ret;
-+
-+      /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
-+       * LED_C and LED_D respectively. At the same time those pins are used to
-+       * bootstrap configuration of the reference clock source (LED_A),
-+       * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
-+       * In practice this is done using a LED and a resistor pulling the pin
-+       * either to GND or to VIO.
-+       * The detected value at boot time is accessible at run-time using the
-+       * TPBANK0 register located in the gpio base of the pinctrl, in order
-+       * to read it here it needs to be referenced by a phandle called
-+       * 'mediatek,pio' in the MDIO bus hosting the PHY.
-+       * The 4 bits in TPBANK0 are kept as package shared data and are used to
-+       * set LED polarity for each of the LED0.
-+       */
-+      regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
-+      if (IS_ERR(regmap))
-+              return PTR_ERR(regmap);
-+
-+      ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, &reg);
-+      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 <[email protected]>");
-+MODULE_AUTHOR("SkyLake Huang <[email protected]>");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -0,0 +1,111 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+#include <linux/bitfield.h>
-+#include <linux/module.h>
-+#include <linux/phy.h>
-+
-+#define MTK_EXT_PAGE_ACCESS           0x1f
-+#define MTK_PHY_PAGE_STANDARD         0x0000
-+#define MTK_PHY_PAGE_EXTENDED         0x0001
-+#define MTK_PHY_PAGE_EXTENDED_2               0x0002
-+#define MTK_PHY_PAGE_EXTENDED_3               0x0003
-+#define MTK_PHY_PAGE_EXTENDED_2A30    0x2a30
-+#define MTK_PHY_PAGE_EXTENDED_52B5    0x52b5
-+
-+static int mtk_gephy_read_page(struct phy_device *phydev)
-+{
-+      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-+}
-+
-+static int mtk_gephy_write_page(struct phy_device *phydev, int page)
-+{
-+      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-+}
-+
-+static void mtk_gephy_config_init(struct phy_device *phydev)
-+{
-+      /* Enable HW auto downshift */
-+      phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
-+
-+      /* Increase SlvDPSready time */
-+      phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+      __phy_write(phydev, 0x10, 0xafae);
-+      __phy_write(phydev, 0x12, 0x2f);
-+      __phy_write(phydev, 0x10, 0x8fae);
-+      phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+      /* Adjust 100_mse_threshold */
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
-+
-+      /* Disable mcc */
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
-+}
-+
-+static int mt7530_phy_config_init(struct phy_device *phydev)
-+{
-+      mtk_gephy_config_init(phydev);
-+
-+      /* Increase post_update_timer */
-+      phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
-+
-+      return 0;
-+}
-+
-+static int mt7531_phy_config_init(struct phy_device *phydev)
-+{
-+      mtk_gephy_config_init(phydev);
-+
-+      /* PHY link down power saving enable */
-+      phy_set_bits(phydev, 0x17, BIT(4));
-+      phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
-+
-+      /* Set TX Pair delay selection */
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
-+      phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
-+
-+      return 0;
-+}
-+
-+static struct phy_driver mtk_gephy_driver[] = {
-+      {
-+              PHY_ID_MATCH_EXACT(0x03a29412),
-+              .name           = "MediaTek MT7530 PHY",
-+              .config_init    = mt7530_phy_config_init,
-+              /* Interrupts are handled by the switch, not the PHY
-+               * itself.
-+               */
-+              .config_intr    = genphy_no_config_intr,
-+              .handle_interrupt = genphy_handle_interrupt_no_ack,
-+              .suspend        = genphy_suspend,
-+              .resume         = genphy_resume,
-+              .read_page      = mtk_gephy_read_page,
-+              .write_page     = mtk_gephy_write_page,
-+      },
-+      {
-+              PHY_ID_MATCH_EXACT(0x03a29441),
-+              .name           = "MediaTek MT7531 PHY",
-+              .config_init    = mt7531_phy_config_init,
-+              /* Interrupts are handled by the switch, not the PHY
-+               * itself.
-+               */
-+              .config_intr    = genphy_no_config_intr,
-+              .handle_interrupt = genphy_handle_interrupt_no_ack,
-+              .suspend        = genphy_suspend,
-+              .resume         = genphy_resume,
-+              .read_page      = mtk_gephy_read_page,
-+              .write_page     = mtk_gephy_write_page,
-+      },
-+};
-+
-+module_phy_driver(mtk_gephy_driver);
-+
-+static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
-+      { PHY_ID_MATCH_EXACT(0x03a29441) },
-+      { PHY_ID_MATCH_EXACT(0x03a29412) },
-+      { }
-+};
-+
-+MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
-+MODULE_AUTHOR("DENG, Qingfang <[email protected]>");
-+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 (file)
index 63407ac..0000000
+++ /dev/null
@@ -1,774 +0,0 @@
-From 71d88c7409b91c853d7f9c933f5e27933d656e5e Mon Sep 17 00:00:00 2001
-From: "SkyLake.Huang" <[email protected]>
-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 <[email protected]>
-Signed-off-by: SkyLake.Huang <[email protected]>
-Signed-off-by: David S. Miller <[email protected]>
----
- MAINTAINERS                            |   2 +
- drivers/net/phy/mediatek/Kconfig       |   4 +
- drivers/net/phy/mediatek/Makefile      |   1 +
- drivers/net/phy/mediatek/mtk-ge-soc.c  | 280 +++----------------------
- drivers/net/phy/mediatek/mtk-phy-lib.c | 254 ++++++++++++++++++++++
- drivers/net/phy/mediatek/mtk.h         |  86 ++++++++
- 6 files changed, 372 insertions(+), 255 deletions(-)
- create mode 100644 drivers/net/phy/mediatek/mtk-phy-lib.c
- create mode 100644 drivers/net/phy/mediatek/mtk.h
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -14428,7 +14428,9 @@ M:     SkyLake Huang <SkyLake.Huang@mediatek
- L:    [email protected]
- S:    Maintained
- F:    drivers/net/phy/mediatek/mtk-ge-soc.c
-+F:    drivers/net/phy/mediatek/mtk-phy-lib.c
- F:    drivers/net/phy/mediatek/mtk-ge.c
-+F:    drivers/net/phy/mediatek/mtk.h
- F:    drivers/phy/mediatek/phy-mtk-xfi-tphy.c
- MEDIATEK I2C CONTROLLER DRIVER
---- a/drivers/net/phy/mediatek/Kconfig
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -1,4 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0-only
-+config MTK_NET_PHYLIB
-+      tristate
-+
- config MEDIATEK_GE_PHY
-       tristate "MediaTek Gigabit Ethernet PHYs"
-       help
-@@ -13,6 +16,7 @@ config MEDIATEK_GE_SOC_PHY
-       tristate "MediaTek SoC Ethernet PHYs"
-       depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
-       depends on NVMEM_MTK_EFUSE
-+      select MTK_NET_PHYLIB
-       help
-         Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
---- a/drivers/net/phy/mediatek/Makefile
-+++ b/drivers/net/phy/mediatek/Makefile
-@@ -1,3 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_MTK_NET_PHYLIB)          += mtk-phy-lib.o
- obj-$(CONFIG_MEDIATEK_GE_PHY)         += mtk-ge.o
- obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)     += mtk-ge-soc.o
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -8,6 +8,8 @@
- #include <linux/phy.h>
- #include <linux/regmap.h>
-+#include "mtk.h"
-+
- #define MTK_GPHY_ID_MT7981                    0x03a29461
- #define MTK_GPHY_ID_MT7988                    0x03a29481
-@@ -210,41 +212,6 @@
- #define MTK_PHY_DA_TX_R50_PAIR_D              0x540
- /* Registers on MDIO_MMD_VEND2 */
--#define MTK_PHY_LED0_ON_CTRL                  0x24
--#define MTK_PHY_LED1_ON_CTRL                  0x26
--#define   MTK_PHY_LED_ON_MASK                 GENMASK(6, 0)
--#define   MTK_PHY_LED_ON_LINK1000             BIT(0)
--#define   MTK_PHY_LED_ON_LINK100              BIT(1)
--#define   MTK_PHY_LED_ON_LINK10                       BIT(2)
--#define   MTK_PHY_LED_ON_LINK                 (MTK_PHY_LED_ON_LINK10 |\
--                                               MTK_PHY_LED_ON_LINK100 |\
--                                               MTK_PHY_LED_ON_LINK1000)
--#define   MTK_PHY_LED_ON_LINKDOWN             BIT(3)
--#define   MTK_PHY_LED_ON_FDX                  BIT(4) /* Full duplex */
--#define   MTK_PHY_LED_ON_HDX                  BIT(5) /* Half duplex */
--#define   MTK_PHY_LED_ON_FORCE_ON             BIT(6)
--#define   MTK_PHY_LED_ON_POLARITY             BIT(14)
--#define   MTK_PHY_LED_ON_ENABLE                       BIT(15)
--
--#define MTK_PHY_LED0_BLINK_CTRL                       0x25
--#define MTK_PHY_LED1_BLINK_CTRL                       0x27
--#define   MTK_PHY_LED_BLINK_1000TX            BIT(0)
--#define   MTK_PHY_LED_BLINK_1000RX            BIT(1)
--#define   MTK_PHY_LED_BLINK_100TX             BIT(2)
--#define   MTK_PHY_LED_BLINK_100RX             BIT(3)
--#define   MTK_PHY_LED_BLINK_10TX              BIT(4)
--#define   MTK_PHY_LED_BLINK_10RX              BIT(5)
--#define   MTK_PHY_LED_BLINK_RX                        (MTK_PHY_LED_BLINK_10RX |\
--                                               MTK_PHY_LED_BLINK_100RX |\
--                                               MTK_PHY_LED_BLINK_1000RX)
--#define   MTK_PHY_LED_BLINK_TX                        (MTK_PHY_LED_BLINK_10TX |\
--                                               MTK_PHY_LED_BLINK_100TX |\
--                                               MTK_PHY_LED_BLINK_1000TX)
--#define   MTK_PHY_LED_BLINK_COLLISION         BIT(6)
--#define   MTK_PHY_LED_BLINK_RX_CRC_ERR                BIT(7)
--#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR               BIT(8)
--#define   MTK_PHY_LED_BLINK_FORCE_BLINK               BIT(9)
--
- #define MTK_PHY_LED1_DEFAULT_POLARITIES               BIT(1)
- #define MTK_PHY_RG_BG_RASEL                   0x115
-@@ -299,14 +266,6 @@ enum CAL_MODE {
-       SW_M
- };
--#define MTK_PHY_LED_STATE_FORCE_ON    0
--#define MTK_PHY_LED_STATE_FORCE_BLINK 1
--#define MTK_PHY_LED_STATE_NETDEV      2
--
--struct mtk_socphy_priv {
--      unsigned long           led_state;
--};
--
- struct mtk_socphy_shared {
-       u32                     boottrap;
-       struct mtk_socphy_priv  priv[4];
-@@ -1172,76 +1131,23 @@ static int mt798x_phy_config_init(struct
-       return mt798x_phy_calibration(phydev);
- }
--static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
--                                  bool on)
--{
--      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
--      struct mtk_socphy_priv *priv = phydev->priv;
--      bool changed;
--
--      if (on)
--              changed = !test_and_set_bit(bit_on, &priv->led_state);
--      else
--              changed = !!test_and_clear_bit(bit_on, &priv->led_state);
--
--      changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
--                                      (index ? 16 : 0), &priv->led_state);
--      if (changed)
--              return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
--                                    MTK_PHY_LED1_ON_CTRL :
--                                    MTK_PHY_LED0_ON_CTRL,
--                                    MTK_PHY_LED_ON_MASK,
--                                    on ? MTK_PHY_LED_ON_FORCE_ON : 0);
--      else
--              return 0;
--}
--
--static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
--                                     bool blinking)
--{
--      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
--                               (index ? 16 : 0);
--      struct mtk_socphy_priv *priv = phydev->priv;
--      bool changed;
--
--      if (blinking)
--              changed = !test_and_set_bit(bit_blink, &priv->led_state);
--      else
--              changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
--
--      changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
--                            (index ? 16 : 0), &priv->led_state);
--      if (changed)
--              return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
--                                   MTK_PHY_LED1_BLINK_CTRL :
--                                   MTK_PHY_LED0_BLINK_CTRL,
--                                   blinking ?
--                                   MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
--      else
--              return 0;
--}
--
- static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
-                                   unsigned long *delay_on,
-                                   unsigned long *delay_off)
- {
-       bool blinking = false;
--      int err = 0;
--
--      if (index > 1)
--              return -EINVAL;
-+      int err;
--      if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
--              blinking = true;
--              *delay_on = 50;
--              *delay_off = 50;
--      }
-+      err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
-+      if (err < 0)
-+              return err;
--      err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
-+      err = mtk_phy_hw_led_blink_set(phydev, index, blinking);
-       if (err)
-               return err;
--      return mt798x_phy_hw_led_on_set(phydev, index, false);
-+      return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
-+                                   false);
- }
- static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
-@@ -1249,11 +1155,12 @@ static int mt798x_phy_led_brightness_set
- {
-       int err;
--      err = mt798x_phy_hw_led_blink_set(phydev, index, false);
-+      err = mtk_phy_hw_led_blink_set(phydev, index, false);
-       if (err)
-               return err;
--      return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
-+      return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
-+                                   (value != LED_OFF));
- }
- static const unsigned long supported_triggers =
-@@ -1269,155 +1176,26 @@ static const unsigned long supported_tri
- static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-                                         unsigned long rules)
- {
--      if (index > 1)
--              return -EINVAL;
--
--      /* All combinations of the supported triggers are allowed */
--      if (rules & ~supported_triggers)
--              return -EOPNOTSUPP;
--
--      return 0;
--};
-+      return mtk_phy_led_hw_is_supported(phydev, index, rules,
-+                                         supported_triggers);
-+}
- static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-                                        unsigned long *rules)
- {
--      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
--                               (index ? 16 : 0);
--      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
--      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
--      struct mtk_socphy_priv *priv = phydev->priv;
--      int on, blink;
--
--      if (index > 1)
--              return -EINVAL;
--
--      on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
--                        index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
--
--      if (on < 0)
--              return -EIO;
--
--      blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
--                           index ? MTK_PHY_LED1_BLINK_CTRL :
--                                   MTK_PHY_LED0_BLINK_CTRL);
--      if (blink < 0)
--              return -EIO;
--
--      if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
--                 MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
--          (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
--              set_bit(bit_netdev, &priv->led_state);
--      else
--              clear_bit(bit_netdev, &priv->led_state);
--
--      if (on & MTK_PHY_LED_ON_FORCE_ON)
--              set_bit(bit_on, &priv->led_state);
--      else
--              clear_bit(bit_on, &priv->led_state);
--
--      if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
--              set_bit(bit_blink, &priv->led_state);
--      else
--              clear_bit(bit_blink, &priv->led_state);
--
--      if (!rules)
--              return 0;
--
--      if (on & MTK_PHY_LED_ON_LINK)
--              *rules |= BIT(TRIGGER_NETDEV_LINK);
--
--      if (on & MTK_PHY_LED_ON_LINK10)
--              *rules |= BIT(TRIGGER_NETDEV_LINK_10);
--
--      if (on & MTK_PHY_LED_ON_LINK100)
--              *rules |= BIT(TRIGGER_NETDEV_LINK_100);
--
--      if (on & MTK_PHY_LED_ON_LINK1000)
--              *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
--
--      if (on & MTK_PHY_LED_ON_FDX)
--              *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
--
--      if (on & MTK_PHY_LED_ON_HDX)
--              *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
--
--      if (blink & MTK_PHY_LED_BLINK_RX)
--              *rules |= BIT(TRIGGER_NETDEV_RX);
--
--      if (blink & MTK_PHY_LED_BLINK_TX)
--              *rules |= BIT(TRIGGER_NETDEV_TX);
--
--      return 0;
-+      return mtk_phy_led_hw_ctrl_get(phydev, index, rules,
-+                                     MTK_GPHY_LED_ON_SET,
-+                                     MTK_GPHY_LED_RX_BLINK_SET,
-+                                     MTK_GPHY_LED_TX_BLINK_SET);
- };
- static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-                                        unsigned long rules)
- {
--      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
--      struct mtk_socphy_priv *priv = phydev->priv;
--      u16 on = 0, blink = 0;
--      int ret;
--
--      if (index > 1)
--              return -EINVAL;
--
--      if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
--              on |= MTK_PHY_LED_ON_FDX;
--
--      if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
--              on |= MTK_PHY_LED_ON_HDX;
--
--      if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
--              on |= MTK_PHY_LED_ON_LINK10;
--
--      if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
--              on |= MTK_PHY_LED_ON_LINK100;
--
--      if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
--              on |= MTK_PHY_LED_ON_LINK1000;
--
--      if (rules & BIT(TRIGGER_NETDEV_RX)) {
--              blink |= (on & MTK_PHY_LED_ON_LINK) ?
--                        (((on & MTK_PHY_LED_ON_LINK10) ?
--                          MTK_PHY_LED_BLINK_10RX : 0) |
--                         ((on & MTK_PHY_LED_ON_LINK100) ?
--                          MTK_PHY_LED_BLINK_100RX : 0) |
--                         ((on & MTK_PHY_LED_ON_LINK1000) ?
--                          MTK_PHY_LED_BLINK_1000RX : 0)) :
--                        MTK_PHY_LED_BLINK_RX;
--      }
--
--      if (rules & BIT(TRIGGER_NETDEV_TX)) {
--              blink |= (on & MTK_PHY_LED_ON_LINK) ?
--                        (((on & MTK_PHY_LED_ON_LINK10) ?
--                          MTK_PHY_LED_BLINK_10TX : 0) |
--                         ((on & MTK_PHY_LED_ON_LINK100) ?
--                          MTK_PHY_LED_BLINK_100TX : 0) |
--                         ((on & MTK_PHY_LED_ON_LINK1000) ?
--                          MTK_PHY_LED_BLINK_1000TX : 0)) :
--                        MTK_PHY_LED_BLINK_TX;
--      }
--
--      if (blink || on)
--              set_bit(bit_netdev, &priv->led_state);
--      else
--              clear_bit(bit_netdev, &priv->led_state);
--
--      ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
--                              MTK_PHY_LED1_ON_CTRL :
--                              MTK_PHY_LED0_ON_CTRL,
--                           MTK_PHY_LED_ON_FDX     |
--                           MTK_PHY_LED_ON_HDX     |
--                           MTK_PHY_LED_ON_LINK,
--                           on);
--
--      if (ret)
--              return ret;
--
--      return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
--                              MTK_PHY_LED1_BLINK_CTRL :
--                              MTK_PHY_LED0_BLINK_CTRL, blink);
-+      return mtk_phy_led_hw_ctrl_set(phydev, index, rules,
-+                                     MTK_GPHY_LED_ON_SET,
-+                                     MTK_GPHY_LED_RX_BLINK_SET,
-+                                     MTK_GPHY_LED_TX_BLINK_SET);
- };
- static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
-@@ -1492,14 +1270,6 @@ static int mt7988_phy_probe_shared(struc
-       return 0;
- }
--static void mt798x_phy_leds_state_init(struct phy_device *phydev)
--{
--      int i;
--
--      for (i = 0; i < 2; ++i)
--              mt798x_phy_led_hw_control_get(phydev, i, NULL);
--}
--
- static int mt7988_phy_probe(struct phy_device *phydev)
- {
-       struct mtk_socphy_shared *shared;
-@@ -1525,7 +1295,7 @@ static int mt7988_phy_probe(struct phy_d
-       phydev->priv = priv;
--      mt798x_phy_leds_state_init(phydev);
-+      mtk_phy_leds_state_init(phydev);
-       err = mt7988_phy_fix_leds_polarities(phydev);
-       if (err)
-@@ -1552,7 +1322,7 @@ static int mt7981_phy_probe(struct phy_d
-       phydev->priv = priv;
--      mt798x_phy_leds_state_init(phydev);
-+      mtk_phy_leds_state_init(phydev);
-       return mt798x_phy_calibration(phydev);
- }
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -0,0 +1,254 @@
-+// SPDX-License-Identifier: GPL-2.0
-+#include <linux/phy.h>
-+#include <linux/module.h>
-+
-+#include <linux/netdevice.h>
-+
-+#include "mtk.h"
-+
-+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+                              unsigned long rules,
-+                              unsigned long supported_triggers)
-+{
-+      if (index > 1)
-+              return -EINVAL;
-+
-+      /* All combinations of the supported triggers are allowed */
-+      if (rules & ~supported_triggers)
-+              return -EOPNOTSUPP;
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
-+
-+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
-+                          unsigned long *rules, u16 on_set,
-+                          u16 rx_blink_set, u16 tx_blink_set)
-+{
-+      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+                               (index ? 16 : 0);
-+      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+      struct mtk_socphy_priv *priv = phydev->priv;
-+      int on, blink;
-+
-+      if (index > 1)
-+              return -EINVAL;
-+
-+      on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+                        index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
-+
-+      if (on < 0)
-+              return -EIO;
-+
-+      blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+                           index ? MTK_PHY_LED1_BLINK_CTRL :
-+                                   MTK_PHY_LED0_BLINK_CTRL);
-+      if (blink < 0)
-+              return -EIO;
-+
-+      if ((on & (on_set | MTK_PHY_LED_ON_FDX |
-+                 MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-+          (blink & (rx_blink_set | tx_blink_set)))
-+              set_bit(bit_netdev, &priv->led_state);
-+      else
-+              clear_bit(bit_netdev, &priv->led_state);
-+
-+      if (on & MTK_PHY_LED_ON_FORCE_ON)
-+              set_bit(bit_on, &priv->led_state);
-+      else
-+              clear_bit(bit_on, &priv->led_state);
-+
-+      if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-+              set_bit(bit_blink, &priv->led_state);
-+      else
-+              clear_bit(bit_blink, &priv->led_state);
-+
-+      if (!rules)
-+              return 0;
-+
-+      if (on & on_set)
-+              *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+      if (on & MTK_PHY_LED_ON_LINK10)
-+              *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+      if (on & MTK_PHY_LED_ON_LINK100)
-+              *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+      if (on & MTK_PHY_LED_ON_LINK1000)
-+              *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+      if (on & MTK_PHY_LED_ON_LINK2500)
-+              *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
-+
-+      if (on & MTK_PHY_LED_ON_FDX)
-+              *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
-+
-+      if (on & MTK_PHY_LED_ON_HDX)
-+              *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
-+
-+      if (blink & rx_blink_set)
-+              *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+      if (blink & tx_blink_set)
-+              *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
-+
-+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
-+                          unsigned long rules, u16 on_set,
-+                          u16 rx_blink_set, u16 tx_blink_set)
-+{
-+      unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+      struct mtk_socphy_priv *priv = phydev->priv;
-+      u16 on = 0, blink = 0;
-+      int ret;
-+
-+      if (index > 1)
-+              return -EINVAL;
-+
-+      if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-+              on |= MTK_PHY_LED_ON_FDX;
-+
-+      if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-+              on |= MTK_PHY_LED_ON_HDX;
-+
-+      if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-+              on |= MTK_PHY_LED_ON_LINK10;
-+
-+      if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-+              on |= MTK_PHY_LED_ON_LINK100;
-+
-+      if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-+              on |= MTK_PHY_LED_ON_LINK1000;
-+
-+      if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
-+              on |= MTK_PHY_LED_ON_LINK2500;
-+
-+      if (rules & BIT(TRIGGER_NETDEV_RX)) {
-+              blink |= (on & on_set) ?
-+                        (((on & MTK_PHY_LED_ON_LINK10) ?
-+                          MTK_PHY_LED_BLINK_10RX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK100) ?
-+                          MTK_PHY_LED_BLINK_100RX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK1000) ?
-+                          MTK_PHY_LED_BLINK_1000RX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK2500) ?
-+                          MTK_PHY_LED_BLINK_2500RX : 0)) :
-+                        rx_blink_set;
-+      }
-+
-+      if (rules & BIT(TRIGGER_NETDEV_TX)) {
-+              blink |= (on & on_set) ?
-+                        (((on & MTK_PHY_LED_ON_LINK10) ?
-+                          MTK_PHY_LED_BLINK_10TX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK100) ?
-+                          MTK_PHY_LED_BLINK_100TX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK1000) ?
-+                          MTK_PHY_LED_BLINK_1000TX : 0) |
-+                         ((on & MTK_PHY_LED_ON_LINK2500) ?
-+                          MTK_PHY_LED_BLINK_2500TX : 0)) :
-+                        tx_blink_set;
-+      }
-+
-+      if (blink || on)
-+              set_bit(bit_netdev, &priv->led_state);
-+      else
-+              clear_bit(bit_netdev, &priv->led_state);
-+
-+      ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+                           MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-+                           MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
-+                           on);
-+
-+      if (ret)
-+              return ret;
-+
-+      return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+                           MTK_PHY_LED1_BLINK_CTRL :
-+                           MTK_PHY_LED0_BLINK_CTRL, blink);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
-+
-+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
-+                          unsigned long *delay_off, bool *blinking)
-+{
-+      if (index > 1)
-+              return -EINVAL;
-+
-+      if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-+              *blinking = true;
-+              *delay_on = 50;
-+              *delay_off = 50;
-+      }
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
-+
-+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-+                        u16 led_on_mask, bool on)
-+{
-+      unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+      struct mtk_socphy_priv *priv = phydev->priv;
-+      bool changed;
-+
-+      if (on)
-+              changed = !test_and_set_bit(bit_on, &priv->led_state);
-+      else
-+              changed = !!test_and_clear_bit(bit_on, &priv->led_state);
-+
-+      changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-+                                      (index ? 16 : 0), &priv->led_state);
-+      if (changed)
-+              return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+                                    MTK_PHY_LED1_ON_CTRL :
-+                                    MTK_PHY_LED0_ON_CTRL,
-+                                    led_on_mask,
-+                                    on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-+      else
-+              return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
-+
-+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking)
-+{
-+      unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+                               (index ? 16 : 0);
-+      struct mtk_socphy_priv *priv = phydev->priv;
-+      bool changed;
-+
-+      if (blinking)
-+              changed = !test_and_set_bit(bit_blink, &priv->led_state);
-+      else
-+              changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
-+
-+      changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-+                            (index ? 16 : 0), &priv->led_state);
-+      if (changed)
-+              return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+                                   MTK_PHY_LED1_BLINK_CTRL :
-+                                   MTK_PHY_LED0_BLINK_CTRL,
-+                                   blinking ?
-+                                   MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-+      else
-+              return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
-+
-+void mtk_phy_leds_state_init(struct phy_device *phydev)
-+{
-+      int i;
-+
-+      for (i = 0; i < 2; ++i)
-+              phydev->drv->led_hw_control_get(phydev, i, NULL);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
-+
-+MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
-+MODULE_AUTHOR("Sky Huang <[email protected]>");
-+MODULE_AUTHOR("Daniel Golle <[email protected]>");
-+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 <[email protected]>
-+ * 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 (file)
index 19f3a84..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-From 3efd0595fc7aaae300f5d9f4f0ae86f432c8d2c7 Mon Sep 17 00:00:00 2001
-From: "SkyLake.Huang" <[email protected]>
-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 <[email protected]>
-Signed-off-by: SkyLake.Huang <[email protected]>
-Signed-off-by: David S. Miller <[email protected]>
----
- 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 (file)
index a5828bc..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-From 50a97d716105a5f35aaecca0bdfe8e23cba0e87f Mon Sep 17 00:00:00 2001
-From: "SkyLake.Huang" <[email protected]>
-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 <[email protected]>
-Signed-off-by: David S. Miller <[email protected]>
----
- drivers/net/phy/mediatek/Kconfig       |  1 +
- drivers/net/phy/mediatek/mtk-ge-soc.c  | 18 ++++--------------
- drivers/net/phy/mediatek/mtk-ge.c      | 20 ++++++--------------
- drivers/net/phy/mediatek/mtk-phy-lib.c | 12 ++++++++++++
- drivers/net/phy/mediatek/mtk.h         |  3 +++
- 5 files changed, 26 insertions(+), 28 deletions(-)
-
---- a/drivers/net/phy/mediatek/Kconfig
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -4,6 +4,7 @@ config MTK_NET_PHYLIB
- config MEDIATEK_GE_PHY
-       tristate "MediaTek Gigabit Ethernet PHYs"
-+      select MTK_NET_PHYLIB
-       help
-         Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -271,16 +271,6 @@ struct mtk_socphy_shared {
-       struct mtk_socphy_priv  priv[4];
- };
--static int mtk_socphy_read_page(struct phy_device *phydev)
--{
--      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_socphy_write_page(struct phy_device *phydev, int page)
--{
--      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
- /* One calibration cycle consists of:
-  * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
-  *   until AD_CAL_COMP is ready to output calibration result.
-@@ -1337,8 +1327,8 @@ static struct phy_driver mtk_socphy_driv
-               .probe          = mt7981_phy_probe,
-               .suspend        = genphy_suspend,
-               .resume         = genphy_resume,
--              .read_page      = mtk_socphy_read_page,
--              .write_page     = mtk_socphy_write_page,
-+              .read_page      = mtk_phy_read_page,
-+              .write_page     = mtk_phy_write_page,
-               .led_blink_set  = mt798x_phy_led_blink_set,
-               .led_brightness_set = mt798x_phy_led_brightness_set,
-               .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-@@ -1354,8 +1344,8 @@ static struct phy_driver mtk_socphy_driv
-               .probe          = mt7988_phy_probe,
-               .suspend        = genphy_suspend,
-               .resume         = genphy_resume,
--              .read_page      = mtk_socphy_read_page,
--              .write_page     = mtk_socphy_write_page,
-+              .read_page      = mtk_phy_read_page,
-+              .write_page     = mtk_phy_write_page,
-               .led_blink_set  = mt798x_phy_led_blink_set,
-               .led_brightness_set = mt798x_phy_led_brightness_set,
-               .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -3,6 +3,8 @@
- #include <linux/module.h>
- #include <linux/phy.h>
-+#include "mtk.h"
-+
- #define MTK_EXT_PAGE_ACCESS           0x1f
- #define MTK_PHY_PAGE_STANDARD         0x0000
- #define MTK_PHY_PAGE_EXTENDED         0x0001
-@@ -11,16 +13,6 @@
- #define MTK_PHY_PAGE_EXTENDED_2A30    0x2a30
- #define MTK_PHY_PAGE_EXTENDED_52B5    0x52b5
--static int mtk_gephy_read_page(struct phy_device *phydev)
--{
--      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_gephy_write_page(struct phy_device *phydev, int page)
--{
--      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
- static void mtk_gephy_config_init(struct phy_device *phydev)
- {
-       /* Enable HW auto downshift */
-@@ -77,8 +69,8 @@ static struct phy_driver mtk_gephy_drive
-               .handle_interrupt = genphy_handle_interrupt_no_ack,
-               .suspend        = genphy_suspend,
-               .resume         = genphy_resume,
--              .read_page      = mtk_gephy_read_page,
--              .write_page     = mtk_gephy_write_page,
-+              .read_page      = mtk_phy_read_page,
-+              .write_page     = mtk_phy_write_page,
-       },
-       {
-               PHY_ID_MATCH_EXACT(0x03a29441),
-@@ -91,8 +83,8 @@ static struct phy_driver mtk_gephy_drive
-               .handle_interrupt = genphy_handle_interrupt_no_ack,
-               .suspend        = genphy_suspend,
-               .resume         = genphy_resume,
--              .read_page      = mtk_gephy_read_page,
--              .write_page     = mtk_gephy_write_page,
-+              .read_page      = mtk_phy_read_page,
-+              .write_page     = mtk_phy_write_page,
-       },
- };
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -6,6 +6,18 @@
- #include "mtk.h"
-+int mtk_phy_read_page(struct phy_device *phydev)
-+{
-+      return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_read_page);
-+
-+int mtk_phy_write_page(struct phy_device *phydev, int page)
-+{
-+      return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_write_page);
-+
- int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-                               unsigned long rules,
-                               unsigned long supported_triggers)
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -66,6 +66,9 @@ struct mtk_socphy_priv {
-       unsigned long           led_state;
- };
-+int mtk_phy_read_page(struct phy_device *phydev);
-+int mtk_phy_write_page(struct phy_device *phydev, int page);
-+
- int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-                               unsigned long rules,
-                               unsigned long supported_triggers);
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 (file)
index 1c87384..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-From e6579df175d5b1baa605c82f8e759542262637cf Mon Sep 17 00:00:00 2001
-From: "SkyLake.Huang" <[email protected]>
-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 <[email protected]>
-Signed-off-by: SkyLake.Huang <[email protected]>
-Signed-off-by: David S. Miller <[email protected]>
----
- 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 (file)
index 669b58d..0000000
+++ /dev/null
@@ -1,700 +0,0 @@
-From e127f7380aaf2cd1614961d826a4af7ab297d37f Mon Sep 17 00:00:00 2001
-From: Christophe JAILLET <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/403c381b7d9156b67ad68ffc44b8eee70c5e86a9.1736691226.git.christophe.jaillet@wanadoo.fr
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 545e929..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-From 7e06c3dbfa5f1e39eba92eb79d854fab2a7ad5fe Mon Sep 17 00:00:00 2001
-From: Sky Huang <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 0000000..aabaa33
--- /dev/null
@@ -0,0 +1,107 @@
+From a2e1ba275eae96a8171deb19e9c7c2f5978fee7b Mon Sep 17 00:00:00 2001
+From: Daniel Golle <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ drivers/net/phy/aquantia/aquantia_main.c | 33 ++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+--- a/drivers/net/phy/aquantia/aquantia_main.c
++++ b/drivers/net/phy/aquantia/aquantia_main.c
+@@ -11,6 +11,7 @@
+ #include <linux/module.h>
+ #include <linux/delay.h>
+ #include <linux/bitfield.h>
++#include <linux/of.h>
+ #include <linux/phy.h>
+ #include "aquantia.h"
+@@ -71,6 +72,11 @@
+ #define MDIO_AN_TX_VEND_INT_MASK2             0xd401
+ #define MDIO_AN_TX_VEND_INT_MASK2_LINK                BIT(0)
++#define PMAPMD_RSVD_VEND_PROV                 0xe400
++#define PMAPMD_RSVD_VEND_PROV_MDI_CONF                GENMASK(1, 0)
++#define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE     BIT(0)
++#define PMAPMD_RSVD_VEND_PROV_MDI_FORCE               BIT(1)
++
+ #define MDIO_AN_RX_LP_STAT1                   0xe820
+ #define MDIO_AN_RX_LP_STAT1_1000BASET_FULL    BIT(15)
+ #define MDIO_AN_RX_LP_STAT1_1000BASET_HALF    BIT(14)
+@@ -485,6 +491,29 @@ static void aqr107_chip_info(struct phy_
+                  fw_major, fw_minor, build_id, prov_id);
+ }
++static int aqr107_config_mdi(struct phy_device *phydev)
++{
++      struct device_node *np = phydev->mdio.dev.of_node;
++      u32 mdi_conf;
++      int ret;
++
++      ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf);
++
++      /* Do nothing in case property "marvell,mdi-cfg-order" is not present */
++      if (ret == -ENOENT)
++              return 0;
++
++      if (ret)
++              return ret;
++
++      if (mdi_conf & ~PMAPMD_RSVD_VEND_PROV_MDI_REVERSE)
++              return -EINVAL;
++
++      return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV,
++                            PMAPMD_RSVD_VEND_PROV_MDI_CONF,
++                            mdi_conf | PMAPMD_RSVD_VEND_PROV_MDI_FORCE);
++}
++
+ static int aqr107_config_init(struct phy_device *phydev)
+ {
+       struct aqr107_priv *priv = phydev->priv;
+@@ -514,6 +543,10 @@ static int aqr107_config_init(struct phy
+       if (ret)
+               return ret;
++      ret = aqr107_config_mdi(phydev);
++      if (ret)
++              return ret;
++
+       /* Restore LED polarity state after reset */
+       for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
+               ret = aqr_phy_led_active_low_set(phydev, led_active_low, true);
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 (file)
index 0000000..565edbd
--- /dev/null
@@ -0,0 +1,31 @@
+From ce21b8fb255ebf0b49913fb4c62741d7eb05c6f6 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <[email protected]>
+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 <[email protected]>
+Closes: https://lore.kernel.org/all/[email protected]/
+Suggested-by: Hans-Frieder Vogt <[email protected]>
+Signed-off-by: Daniel Golle <[email protected]>
+---
+ 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 (file)
index 0000000..ad1d554
--- /dev/null
@@ -0,0 +1,53 @@
+From a274465cc3bef2dfd9c9ea5100848dda0a8641e1 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/91598487773d768f254d5faf06cf65b13e972f0e.1728558223.git.daniel@makrotopia.org
+Signed-off-by: Paolo Abeni <[email protected]>
+---
+ 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 (file)
index 0000000..155f796
--- /dev/null
@@ -0,0 +1,108 @@
+From 9d55e68b19f222e6334ef4021c5527998f5ab537 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/86a413b4387c42dcb54f587cc2433a06f16aae83.1728558223.git.daniel@makrotopia.org
+Signed-off-by: Paolo Abeni <[email protected]>
+---
+ 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 (file)
index 0000000..c785f8a
--- /dev/null
@@ -0,0 +1,332 @@
+From 78997e9a5e4d8a4df561e083a92c91ae23010e07 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/b6ec9050339f8244ff898898a1cecc33b13a48fc.1727741563.git.daniel@makrotopia.org
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..39bef9b
--- /dev/null
@@ -0,0 +1,28 @@
+From f95b4725e796b12e5f347a0d161e1d3843142aa8 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/cc5da0a989af8b0d49d823656d88053c4de2ab98.1728057367.git.daniel@makrotopia.org
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 (file)
index 0000000..5fd3dcc
--- /dev/null
@@ -0,0 +1,58 @@
+From eb89c79c1b8f17fc1611540768678e60df89ac42 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/180ccafa837f09908b852a8a874a3808c5ecd2d0.1728558223.git.daniel@makrotopia.org
+Signed-off-by: Paolo Abeni <[email protected]>
+---
+ 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 (file)
index 0000000..c57b577
--- /dev/null
@@ -0,0 +1,379 @@
+From 1758af47b98c17da464cb45f476875150955dd48 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Lunn <[email protected]>
+Link: https://patch.msgid.link/81f4717ab9acf38f3239727a4540ae96fd01109b.1728558223.git.daniel@makrotopia.org
+Signed-off-by: Paolo Abeni <[email protected]>
+---
+ 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 (file)
index 40ce29f..0000000
+++ /dev/null
@@ -1,448 +0,0 @@
-From 6e7370079669b0d55c9464bb7c3fb8fb7368b912 Mon Sep 17 00:00:00 2001
-From: Sky Huang <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 972a9c0..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-From c7e2fb3421ef5ebbb4c91f44bd735ab10edd755a Mon Sep 17 00:00:00 2001
-From: Sky Huang <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 47d891e..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-From 7851c73a416b15aff6f9ada9c88affc5f48ff011 Mon Sep 17 00:00:00 2001
-From: Sky Huang <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 858de09..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-From bae8c61522c4d5a5250a24dcb57d120ea593fab1 Mon Sep 17 00:00:00 2001
-From: Sky Huang <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 9778ea1..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-From e5566162af8b9690e096d2e6089e4ed955a0d13d Mon Sep 17 00:00:00 2001
-From: Christian Marangi <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Signed-off-by: Christian Marangi <[email protected]>
-Acked-by: Arnd Bergmann <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 5498ecb..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-From 4590c8bc10951feee3e439bf7fff1b458c2e6fad Mon Sep 17 00:00:00 2001
-From: Christian Marangi <[email protected]>
-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 <[email protected]>
-Signed-off-by: Christian Marangi <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 1b1dda2..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-From 34501d047ac0a6cbb13285ba9d15f75c1deb7da7 Mon Sep 17 00:00:00 2001
-From: Christian Marangi <[email protected]>
-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 <[email protected]>
-Fixes: 6a325aed130b ("net: phy: mediatek: add Airoha PHY ID to SoC driver")
-Signed-off-by: Christian Marangi <[email protected]>
-Link: https://patch.msgid.link/[email protected]
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 0000000..19268cf
--- /dev/null
@@ -0,0 +1,1250 @@
+From 7b590490e3aa6bfa38bf6e2069a529017fd3c1d2 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <[email protected]>
+Date: Fri, 13 Oct 2023 00:08:35 +0200
+Subject: [PATCH] net: dsa: mv88e6xxx: Support LED control
+
+This adds control over the hardware LEDs in the Marvell
+MV88E6xxx DSA switch and enables it for MV88E6352.
+
+This fixes an imminent problem on the Inteno XG6846 which
+has a WAN LED that simply do not work with hardware
+defaults: driver amendment is necessary.
+
+The patch is modeled after Christian Marangis LED support
+code for the QCA8k DSA switch, I got help with the register
+definitions from Tim Harvey.
+
+After this patch it is possible to activate hardware link
+indication like this (or with a similar script):
+
+  cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
+  echo netdev > trigger
+  echo 1 > link
+
+This makes the green link indicator come up on any link
+speed. It is also possible to be more elaborate, like this:
+
+  cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
+  echo netdev > trigger
+  echo 1 > link_1000
+  cd /sys/class/leds/Marvell\ 88E6352:05:01:amber:wan/
+  echo netdev > trigger
+  echo 1 > link_100
+
+Making the green LED come on for a gigabit link and the
+amber LED come on for a 100 mbit link.
+
+Each port has 2 LED slots (the hardware may use just one or
+none) and the hardware triggers are specified in four bits per
+LED, and some of the hardware triggers are only available on the
+SFP (fiber) uplink. The restrictions are described in the
+port.h header file where the registers are described. For
+example, selector 1 set for LED 1 on port 5 or 6 will indicate
+Fiber 1000 (gigabit) and activity with a blinking LED, but
+ONLY for an SFP connection. If port 5/6 is used with something
+not SFP, this selector is a noop: something else need to be
+selected.
+
+After the previous series rewriting the MV88E6xxx DT
+bindings to use YAML a "leds" subnode is already valid
+for each port, in my scratch device tree it looks like
+this:
+
+   leds {
+     #address-cells = <1>;
+     #size-cells = <0>;
+
+     led@0 {
+       reg = <0>;
+       color = <LED_COLOR_ID_GREEN>;
+       function = LED_FUNCTION_LAN;
+       default-state = "off";
+       linux,default-trigger = "netdev";
+     };
+     led@1 {
+       reg = <1>;
+       color = <LED_COLOR_ID_AMBER>;
+       function = LED_FUNCTION_LAN;
+       default-state = "off";
+     };
+   };
+
+This DT config is not yet configuring everything: when the netdev
+default trigger is assigned the hw acceleration callbacks are
+not called, and there is no way to set the netdev sub-trigger
+type (such as link_1000) from the device tree, such as if you want
+a gigabit link indicator. This has to be done from userspace at
+this point.
+
+We add LED operations to all switches in the 6352 family:
+6172, 6176, 6240 and 6352.
+
+Signed-off-by: Linus Walleij <[email protected]>
+---
+ drivers/net/dsa/mv88e6xxx/Kconfig  |  10 +
+ drivers/net/dsa/mv88e6xxx/Makefile |   1 +
+ drivers/net/dsa/mv88e6xxx/chip.c   |  38 +-
+ drivers/net/dsa/mv88e6xxx/chip.h   |  11 +
+ drivers/net/dsa/mv88e6xxx/leds.c   | 839 +++++++++++++++++++++++++++++
+ drivers/net/dsa/mv88e6xxx/port.c   |   1 +
+ drivers/net/dsa/mv88e6xxx/port.h   | 133 +++++
+ 7 files changed, 1031 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c
+
+--- a/drivers/net/dsa/mv88e6xxx/Kconfig
++++ b/drivers/net/dsa/mv88e6xxx/Kconfig
+@@ -17,3 +17,13 @@ config NET_DSA_MV88E6XXX_PTP
+       help
+         Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch
+         chips that support it.
++
++config NET_DSA_MV88E6XXX_LEDS
++      bool "LED support for Marvell 88E6xxx"
++      default y
++      depends on NET_DSA_MV88E6XXX
++      depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_MV88E6XXX
++      depends on LEDS_TRIGGERS
++      help
++        This enabled support for controlling the LEDs attached to the
++        Marvell 88E6xxx switch chips.
+--- a/drivers/net/dsa/mv88e6xxx/Makefile
++++ b/drivers/net/dsa/mv88e6xxx/Makefile
+@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
+ mv88e6xxx-objs += global2_avb.o
+ mv88e6xxx-objs += global2_scratch.o
+ mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
++mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_LEDS) += leds.o
+ mv88e6xxx-objs += pcs-6185.o
+ mv88e6xxx-objs += pcs-6352.o
+ mv88e6xxx-objs += pcs-639x.o
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -27,6 +27,7 @@
+ #include <linux/of_irq.h>
+ #include <linux/of_mdio.h>
+ #include <linux/platform_data/mv88e6xxx.h>
++#include <linux/property.h>
+ #include <linux/netdevice.h>
+ #include <linux/gpio/consumer.h>
+ #include <linux/phylink.h>
+@@ -3412,14 +3413,43 @@ static int mv88e6xxx_setup_upstream_port
+ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
+ {
+       struct device_node *phy_handle = NULL;
++      struct fwnode_handle *ports_fwnode;
++      struct fwnode_handle *port_fwnode;
+       struct dsa_switch *ds = chip->ds;
++      struct mv88e6xxx_port *p;
+       struct dsa_port *dp;
+       int tx_amp;
+       int err;
+       u16 reg;
++      u32 val;
+-      chip->ports[port].chip = chip;
+-      chip->ports[port].port = port;
++      p = &chip->ports[port];
++      p->chip = chip;
++      p->port = port;
++
++      /* Look up corresponding fwnode if any */
++      ports_fwnode = device_get_named_child_node(chip->dev, "ethernet-ports");
++      if (!ports_fwnode)
++              ports_fwnode = device_get_named_child_node(chip->dev, "ports");
++      if (ports_fwnode) {
++              fwnode_for_each_child_node(ports_fwnode, port_fwnode) {
++                      if (fwnode_property_read_u32(port_fwnode, "reg", &val))
++                              continue;
++                      if (val == port) {
++                              p->fwnode = port_fwnode;
++                              p->fiber = fwnode_property_present(port_fwnode, "sfp");
++                              break;
++                      }
++              }
++      } else {
++              dev_dbg(chip->dev, "no ethernet ports node defined for the device\n");
++      }
++
++      if (chip->info->ops->port_setup_leds) {
++              err = chip->info->ops->port_setup_leds(chip, port);
++              if (err && err != -EOPNOTSUPP)
++                      return err;
++      }
+       err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
+                                      SPEED_UNFORCED, DUPLEX_UNFORCED,
+@@ -4653,6 +4683,7 @@ static const struct mv88e6xxx_ops mv88e6
+       .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+       .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_get_cmode = mv88e6352_port_get_cmode,
++      .port_setup_leds = mv88e6xxx_port_setup_leds,
+       .port_setup_message_port = mv88e6xxx_setup_message_port,
+       .stats_snapshot = mv88e6320_g1_stats_snapshot,
+       .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+@@ -4755,6 +4786,7 @@ static const struct mv88e6xxx_ops mv88e6
+       .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+       .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_get_cmode = mv88e6352_port_get_cmode,
++      .port_setup_leds = mv88e6xxx_port_setup_leds,
+       .port_setup_message_port = mv88e6xxx_setup_message_port,
+       .stats_snapshot = mv88e6320_g1_stats_snapshot,
+       .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+@@ -5030,6 +5062,7 @@ static const struct mv88e6xxx_ops mv88e6
+       .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+       .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_get_cmode = mv88e6352_port_get_cmode,
++      .port_setup_leds = mv88e6xxx_port_setup_leds,
+       .port_setup_message_port = mv88e6xxx_setup_message_port,
+       .stats_snapshot = mv88e6320_g1_stats_snapshot,
+       .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+@@ -5460,6 +5493,7 @@ static const struct mv88e6xxx_ops mv88e6
+       .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+       .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+       .port_get_cmode = mv88e6352_port_get_cmode,
++      .port_setup_leds = mv88e6xxx_port_setup_leds,
+       .port_setup_message_port = mv88e6xxx_setup_message_port,
+       .stats_snapshot = mv88e6320_g1_stats_snapshot,
+       .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+--- a/drivers/net/dsa/mv88e6xxx/chip.h
++++ b/drivers/net/dsa/mv88e6xxx/chip.h
+@@ -13,7 +13,9 @@
+ #include <linux/irq.h>
+ #include <linux/gpio/consumer.h>
+ #include <linux/kthread.h>
++#include <linux/leds.h>
+ #include <linux/phy.h>
++#include <linux/property.h>
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/timecounter.h>
+ #include <net/dsa.h>
+@@ -276,6 +278,7 @@ struct mv88e6xxx_vlan {
+ struct mv88e6xxx_port {
+       struct mv88e6xxx_chip *chip;
+       int port;
++      struct fwnode_handle *fwnode;
+       struct mv88e6xxx_vlan bridge_pvid;
+       u64 serdes_stats[2];
+       u64 atu_member_violation;
+@@ -290,6 +293,11 @@ struct mv88e6xxx_port {
+       struct devlink_region *region;
+       void *pcs_private;
++      /* LED related information */
++      bool fiber;
++      struct led_classdev led0;
++      struct led_classdev led1;
++
+       /* MacAuth Bypass control flag */
+       bool mab;
+ };
+@@ -574,6 +582,9 @@ struct mv88e6xxx_ops {
+                             phy_interface_t mode);
+       int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
++      /* LED control */
++      int (*port_setup_leds)(struct mv88e6xxx_chip *chip, int port);
++
+       /* Some devices have a per port register indicating what is
+        * the upstream port this port should forward to.
+        */
+--- /dev/null
++++ b/drivers/net/dsa/mv88e6xxx/leds.c
+@@ -0,0 +1,839 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++#include <linux/bitfield.h>
++#include <linux/leds.h>
++#include <linux/property.h>
++
++#include "chip.h"
++#include "global2.h"
++#include "port.h"
++
++/* Offset 0x16: LED control */
++
++static int mv88e6xxx_port_led_write(struct mv88e6xxx_chip *chip, int port, u16 reg)
++{
++      reg |= MV88E6XXX_PORT_LED_CONTROL_UPDATE;
++
++      return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, reg);
++}
++
++static int mv88e6xxx_port_led_read(struct mv88e6xxx_chip *chip, int port,
++                                 u16 ptr, u16 *val)
++{
++      int err;
++
++      err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, ptr);
++      if (err)
++              return err;
++
++      err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_LED_CONTROL, val);
++      *val &= 0x3ff;
++
++      return err;
++}
++
++static int mv88e6xxx_led_brightness_set(struct mv88e6xxx_port *p, int led,
++                                      int brightness)
++{
++      u16 reg;
++      int err;
++
++      err = mv88e6xxx_port_led_read(p->chip, p->port,
++                                    MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
++                                    &reg);
++      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,
++                                    &reg);
++      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,
++                                    &reg);
++      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, &reg);
++      if (err)
++              return err;
++
++      reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
++
++      if (led == 0)
++              dev_dbg(p->chip->dev, "LED 0 hw control on port %d trigger selector 0x%02x\n",
++                      p->port,
++                      (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK));
++      else
++              dev_dbg(p->chip->dev, "LED 1 hw control on port %d trigger selector 0x%02x\n",
++                      p->port,
++                      (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK) >> 4);
++
++      return mv88e6xxx_port_led_write(p->chip, p->port, reg);
++}
++
++static int
++mv88e6xxx_led_hw_control_get(struct mv88e6xxx_port *p, int led, unsigned long *rules)
++{
++      u16 val;
++      int err;
++
++      mv88e6xxx_reg_lock(p->chip);
++      err = mv88e6xxx_port_led_read(p->chip, p->port,
++                                    MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, &val);
++      mv88e6xxx_reg_unlock(p->chip);
++      if (err)
++              return err;
++
++      /* Mask out the selector bits for this port */
++      if (led == 1) {
++              val &= MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
++              /* It's forced blinking/OFF/ON */
++              if (val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELD ||
++                  val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELE ||
++                  val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELF) {
++                      *rules = 0;
++                      return 0;
++              }
++      } else {
++              val &= MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
++              /* It's forced blinking/OFF/ON */
++              if (val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELD ||
++                  val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELE ||
++                  val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELF) {
++                      *rules = 0;
++                      return 0;
++              }
++      }
++
++      err = mv88e6xxx_led_match_rule(p, val, led, rules);
++      if (!err)
++              return 0;
++
++      dev_dbg(p->chip->dev, "couldn't find matching selector for %04x\n", val);
++      *rules = 0;
++      return 0;
++}
++
++static int
++mv88e6xxx_led0_hw_control_set(struct led_classdev *ldev, unsigned long rules)
++{
++      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
++      int err;
++
++      mv88e6xxx_reg_lock(p->chip);
++      err = mv88e6xxx_led_hw_control_set(p, 0, rules);
++      mv88e6xxx_reg_unlock(p->chip);
++
++      return err;
++}
++
++static int
++mv88e6xxx_led1_hw_control_set(struct led_classdev *ldev, unsigned long rules)
++{
++      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
++      int err;
++
++      mv88e6xxx_reg_lock(p->chip);
++      err = mv88e6xxx_led_hw_control_set(p, 1, rules);
++      mv88e6xxx_reg_unlock(p->chip);
++
++      return err;
++}
++
++static int
++mv88e6xxx_led0_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
++{
++      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
++
++      return mv88e6xxx_led_hw_control_get(p, 0, rules);
++}
++
++static int
++mv88e6xxx_led1_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
++{
++      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
++
++      return mv88e6xxx_led_hw_control_get(p, 1, rules);
++}
++
++static struct device *mv88e6xxx_led_hw_control_get_device(struct mv88e6xxx_port *p)
++{
++      struct dsa_port *dp;
++
++      dp = dsa_to_port(p->chip->ds, p->port);
++      if (!dp)
++              return NULL;
++      if (dp->user)
++              return &dp->user->dev;
++      return NULL;
++}
++
++static struct device *
++mv88e6xxx_led0_hw_control_get_device(struct led_classdev *ldev)
++{
++      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
++
++      return mv88e6xxx_led_hw_control_get_device(p);
++}
++
++static struct device *
++mv88e6xxx_led1_hw_control_get_device(struct led_classdev *ldev)
++{
++      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
++
++      return mv88e6xxx_led_hw_control_get_device(p);
++}
++
++int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port)
++{
++      struct fwnode_handle *led = NULL, *leds = NULL;
++      struct led_init_data init_data = { };
++      enum led_default_state state;
++      struct mv88e6xxx_port *p;
++      struct led_classdev *l;
++      struct device *dev;
++      u32 led_num;
++      int ret;
++
++      /* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */
++      if (port > 5)
++              return -EOPNOTSUPP;
++
++      p = &chip->ports[port];
++      if (!p->fwnode)
++              return 0;
++
++      dev = chip->dev;
++
++      leds = fwnode_get_named_child_node(p->fwnode, "leds");
++      if (!leds) {
++              dev_dbg(dev, "No Leds node specified in device tree for port %d!\n",
++                      port);
++              return 0;
++      }
++
++      fwnode_for_each_child_node(leds, led) {
++              /* Reg represent the led number of the port, max 2
++               * LEDs can be connected to each port, in some designs
++               * only one LED is connected.
++               */
++              if (fwnode_property_read_u32(led, "reg", &led_num))
++                      continue;
++              if (led_num > 1) {
++                      dev_err(dev, "invalid LED specified port %d\n", port);
++                      return -EINVAL;
++              }
++
++              if (led_num == 0)
++                      l = &p->led0;
++              else
++                      l = &p->led1;
++
++              state = led_init_default_state_get(led);
++              switch (state) {
++              case LEDS_DEFSTATE_ON:
++                      l->brightness = 1;
++                      mv88e6xxx_led_brightness_set(p, led_num, 1);
++                      break;
++              case LEDS_DEFSTATE_KEEP:
++                      break;
++              default:
++                      l->brightness = 0;
++                      mv88e6xxx_led_brightness_set(p, led_num, 0);
++              }
++
++              l->max_brightness = 1;
++              if (led_num == 0) {
++                      l->brightness_set_blocking = mv88e6xxx_led0_brightness_set_blocking;
++                      l->blink_set = mv88e6xxx_led0_blink_set;
++                      l->hw_control_is_supported = mv88e6xxx_led0_hw_control_is_supported;
++                      l->hw_control_set = mv88e6xxx_led0_hw_control_set;
++                      l->hw_control_get = mv88e6xxx_led0_hw_control_get;
++                      l->hw_control_get_device = mv88e6xxx_led0_hw_control_get_device;
++              } else {
++                      l->brightness_set_blocking = mv88e6xxx_led1_brightness_set_blocking;
++                      l->blink_set = mv88e6xxx_led1_blink_set;
++                      l->hw_control_is_supported = mv88e6xxx_led1_hw_control_is_supported;
++                      l->hw_control_set = mv88e6xxx_led1_hw_control_set;
++                      l->hw_control_get = mv88e6xxx_led1_hw_control_get;
++                      l->hw_control_get_device = mv88e6xxx_led1_hw_control_get_device;
++              }
++              l->hw_control_trigger = "netdev";
++
++              init_data.default_label = ":port";
++              init_data.fwnode = led;
++              init_data.devname_mandatory = true;
++              init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name,
++                                               port, led_num);
++              if (!init_data.devicename)
++                      return -ENOMEM;
++
++              ret = devm_led_classdev_register_ext(dev, l, &init_data);
++              kfree(init_data.devicename);
++
++              if (ret) {
++                      dev_err(dev, "Failed to init LED %d for port %d", led_num, port);
++                      return ret;
++              }
++      }
++
++      return 0;
++}
+--- a/drivers/net/dsa/mv88e6xxx/port.c
++++ b/drivers/net/dsa/mv88e6xxx/port.c
+@@ -12,6 +12,7 @@
+ #include <linux/if_bridge.h>
+ #include <linux/phy.h>
+ #include <linux/phylink.h>
++#include <linux/property.h>
+ #include "chip.h"
+ #include "global2.h"
+--- a/drivers/net/dsa/mv88e6xxx/port.h
++++ b/drivers/net/dsa/mv88e6xxx/port.h
+@@ -309,6 +309,130 @@
+ /* Offset 0x13: OutFiltered Counter */
+ #define MV88E6XXX_PORT_OUT_FILTERED   0x13
++/* Offset 0x16: LED Control */
++#define MV88E6XXX_PORT_LED_CONTROL                            0x16
++#define MV88E6XXX_PORT_LED_CONTROL_UPDATE                     BIT(15)
++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_MASK                       GENMASK(14, 12)
++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL         (0x00 << 12) /* Control for LED 0 and 1 */
++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK      (0x06 << 12) /* Stetch and Blink Rate */
++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_CNTL_SPECIAL               (0x07 << 12) /* Control for the Port's Special LED */
++#define MV88E6XXX_PORT_LED_CONTROL_DATA_MASK                  GENMASK(10, 0)
++/* Selection masks valid for either port 1,2,3,4 or 5 */
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK              GENMASK(3, 0)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK              GENMASK(7, 4)
++/* Selection control for LED 0 and 1, ports 5 and 6 only has LED 0
++ * Bits  Function
++ * 0..3  LED 0 control selector on ports 1-5
++ * 4..7  LED 1 control selector on ports 1-4 on port 5 this controls LED 0 of port 6
++ *
++ * Sel Port LED Function for the 6352 family:
++ * 0   1-4  0   Link/Act/Speed by Blink Rate (off=no link, on=link, blink=activity, blink speed=link speed)
++ *     1-4  1   Port 2's Special LED
++ *     5-6  0   Port 5 Link/Act (off=no link, on=link, blink=activity)
++ *     5-6  1   Port 6 Link/Act (off=no link, on=link 1000, blink=activity)
++ * 1   1-4  0   100/1000 Link/Act (off=no link, on=100 or 1000 link, blink=activity)
++ *     1-4  1   10/100 Link Act (off=no link, on=10 or 100 link, blink=activity)
++ *     5-6  0   Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
++ *     5-6  1   Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
++ * 2   1-4  0   1000 Link/Act (off=no link, on=link 1000, blink=activity)
++ *     1-4  1   10/100 Link/Act (off=no link, on=10 or 100 link, blink=activity)
++ *     5-6  0   Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
++ *     5-6  1   Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
++ * 3   1-4  0   Link/Act (off=no link, on=link, blink=activity)
++ *     1-4  1   1000 Link (off=no link, on=1000 link)
++ *     5-6  0   Port 0's Special LED
++ *     5-6  1   Fiber Link (off=no link, on=link)
++ * 4   1-4  0   Port 0's Special LED
++ *     1-4  1   Port 1's Special LED
++ *     5-6  0   Port 1's Special LED
++ *     5-6  1   Port 5 Link/Act (off=no link, on=link, blink=activity)
++ * 5   1-4  0   Reserved
++ *     1-4  1   Reserved
++ *     5-6  0   Port 2's Special LED
++ *     5-6  1   Port 6 Link (off=no link, on=link)
++ * 6   1-4  0   Duplex/Collision (off=half-duplex,on=full-duplex,blink=collision)
++ *     1-4  1   10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
++ *     5-6  0   Port 5 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
++ *     5-6  1   Port 6 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
++ * 7   1-4  0   10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
++ *     1-4  1   10/1000 Link (off=no link, on=10 or 1000 link)
++ *     5-6  0   Port 5 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed)
++ *     5-6  1   Port 6 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity,  blink speed=link speed)
++ * 8   1-4  0   Link (off=no link, on=link)
++ *     1-4  1   Activity (off=no link, blink on=activity)
++ *     5-6  0   Port 6 Link/Act (off=no link, on=link, blink=activity)
++ *     5-6  1   Port 0's Special LED
++ * 9   1-4  0   10 Link (off=no link, on=10 link)
++ *     1-4  1   100 Link (off=no link, on=100 link)
++ *     5-6  0   Reserved
++ *     5-6  1   Port 1's Special LED
++ * a   1-4  0   10 Link/Act (off=no link, on=10 link, blink=activity)
++ *     1-4  1   100 Link/Act (off=no link, on=100 link, blink=activity)
++ *     5-6  0   Reserved
++ *     5-6  1   Port 2's Special LED
++ * b   1-4  0   100/1000 Link (off=no link, on=100 or 1000 link)
++ *     1-4  1   10/100 Link (off=no link, on=100 link, blink=activity)
++ *     5-6  0   Reserved
++ *     5-6  1   Reserved
++ * c     *  *   PTP Act (blink on=PTP activity)
++ * d     *  *   Force Blink
++ * e     *  *   Force Off
++ * f     *  *   Force On
++ */
++/* Select LED0 output */
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0                  0x0
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1                  0x1
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2                  0x2
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3                  0x3
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL4                  0x4
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL5                  0x5
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6                  0x6
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7                  0x7
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8                  0x8
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9                  0x9
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELA                  0xa
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELB                  0xb
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELC                  0xc
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELD                  0xd
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELE                  0xe
++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELF                  0xf
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0                  (0x0 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1                  (0x1 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2                  (0x2 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3                  (0x3 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4                  (0x4 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5                  (0x5 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6                  (0x6 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7                  (0x7 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8                  (0x8 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9                  (0x9 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELA                  (0xa << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELB                  (0xb << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELC                  (0xc << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELD                  (0xd << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELE                  (0xe << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELF                  (0xf << 4)
++/* Stretch and Blink Rate Control (Index 0x06 of LED Control) */
++/* Pulse Stretch Selection for all LED's on this port */
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE    (0 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS    (1 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS    (2 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS    (3 << 4)
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS   (4 << 4)
++/* Blink Rate Selection for all LEDs on this port */
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS               0
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS               1
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS               2
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS      3
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS      4
++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS      5
++ /* Control for Special LED (Index 0x7 of LED Control on Port0) */
++#define MV88E6XXX_PORT_LED_CONTROL_0x07_P0_LAN_LINKACT_SHIFT  0 /* bits 6:0 LAN Link Activity LED */
++/* Control for Special LED (Index 0x7 of LED Control on Port 1) */
++#define MV88E6XXX_PORT_LED_CONTROL_0x07_P1_WAN_LINKACT_SHIFT  0 /* bits 6:0 WAN Link Activity LED */
++/* Control for Special LED (Index 0x7 of LED Control on Port 2) */
++#define MV88E6XXX_PORT_LED_CONTROL_0x07_P2_PTP_ACT            0 /* bits 6:0 PTP Activity */
++
+ /* Offset 0x18: IEEE Priority Mapping Table */
+ #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE                    0x18
+ #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE             0x8000
+@@ -457,6 +581,15 @@ int mv88e6393x_port_set_cmode(struct mv8
+                             phy_interface_t mode);
+ int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
+ int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
++#ifdef CONFIG_NET_DSA_MV88E6XXX_LEDS
++int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port);
++#else
++static inline int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip,
++                                          int port)
++{
++      return 0;
++}
++#endif
+ int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
+                                bool drop_untagged);
+ int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map);
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 (file)
index 2ca3f2e..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-From 952d7325362ffbefa6ce5619fb4e53c2159ec7a7 Mon Sep 17 00:00:00 2001
-From: Qingfang Deng <[email protected]>
-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 <[email protected]>
----
- 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 (file)
index e231bc8..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-From 8cae5a0d91fea01d90ce7c1827e26934a22ca2fa Mon Sep 17 00:00:00 2001
-From: Rui Salvaterra <[email protected]>
-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 <[email protected]>
----
- 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 (file)
index 48f9c1c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-From 77f5bb150132bbbcd6bc37ffdc80c9e140e373a4 Mon Sep 17 00:00:00 2001
-From: Kees Cook <[email protected]>
-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 <[email protected]>
-Link: https://lore.kernel.org/r/[email protected]
-Signed-off-by: Sebastian Reichel <[email protected]>
-
---- 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 (file)
index 0000000..f9299f9
--- /dev/null
@@ -0,0 +1,30 @@
+From b0fa00fe38f673c986633c11087274deeb7ce7b0 Mon Sep 17 00:00:00 2001
+From: Sander Vanheule <[email protected]>
+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 <[email protected]>
+Acked-by: Michael Walle <[email protected]>
+Link: https://lore.kernel.org/r/[email protected]
+Signed-off-by: Bartosz Golaszewski <[email protected]>
+---
+ 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 (file)
index 0000000..48f9c1c
--- /dev/null
@@ -0,0 +1,39 @@
+From 77f5bb150132bbbcd6bc37ffdc80c9e140e373a4 Mon Sep 17 00:00:00 2001
+From: Kees Cook <[email protected]>
+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 <[email protected]>
+Link: https://lore.kernel.org/r/[email protected]
+Signed-off-by: Sebastian Reichel <[email protected]>
+
+--- 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 (file)
index aabaa33..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-From a2e1ba275eae96a8171deb19e9c7c2f5978fee7b Mon Sep 17 00:00:00 2001
-From: Daniel Golle <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- drivers/net/phy/aquantia/aquantia_main.c | 33 ++++++++++++++++++++++++
- 1 file changed, 33 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -11,6 +11,7 @@
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/bitfield.h>
-+#include <linux/of.h>
- #include <linux/phy.h>
- #include "aquantia.h"
-@@ -71,6 +72,11 @@
- #define MDIO_AN_TX_VEND_INT_MASK2             0xd401
- #define MDIO_AN_TX_VEND_INT_MASK2_LINK                BIT(0)
-+#define PMAPMD_RSVD_VEND_PROV                 0xe400
-+#define PMAPMD_RSVD_VEND_PROV_MDI_CONF                GENMASK(1, 0)
-+#define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE     BIT(0)
-+#define PMAPMD_RSVD_VEND_PROV_MDI_FORCE               BIT(1)
-+
- #define MDIO_AN_RX_LP_STAT1                   0xe820
- #define MDIO_AN_RX_LP_STAT1_1000BASET_FULL    BIT(15)
- #define MDIO_AN_RX_LP_STAT1_1000BASET_HALF    BIT(14)
-@@ -485,6 +491,29 @@ static void aqr107_chip_info(struct phy_
-                  fw_major, fw_minor, build_id, prov_id);
- }
-+static int aqr107_config_mdi(struct phy_device *phydev)
-+{
-+      struct device_node *np = phydev->mdio.dev.of_node;
-+      u32 mdi_conf;
-+      int ret;
-+
-+      ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf);
-+
-+      /* Do nothing in case property "marvell,mdi-cfg-order" is not present */
-+      if (ret == -ENOENT)
-+              return 0;
-+
-+      if (ret)
-+              return ret;
-+
-+      if (mdi_conf & ~PMAPMD_RSVD_VEND_PROV_MDI_REVERSE)
-+              return -EINVAL;
-+
-+      return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV,
-+                            PMAPMD_RSVD_VEND_PROV_MDI_CONF,
-+                            mdi_conf | PMAPMD_RSVD_VEND_PROV_MDI_FORCE);
-+}
-+
- static int aqr107_config_init(struct phy_device *phydev)
- {
-       struct aqr107_priv *priv = phydev->priv;
-@@ -514,6 +543,10 @@ static int aqr107_config_init(struct phy
-       if (ret)
-               return ret;
-+      ret = aqr107_config_mdi(phydev);
-+      if (ret)
-+              return ret;
-+
-       /* Restore LED polarity state after reset */
-       for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
-               ret = aqr_phy_led_active_low_set(phydev, led_active_low, true);
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 (file)
index 565edbd..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-From ce21b8fb255ebf0b49913fb4c62741d7eb05c6f6 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <[email protected]>
-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 <[email protected]>
-Closes: https://lore.kernel.org/all/[email protected]/
-Suggested-by: Hans-Frieder Vogt <[email protected]>
-Signed-off-by: Daniel Golle <[email protected]>
----
- 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 (file)
index ad1d554..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-From a274465cc3bef2dfd9c9ea5100848dda0a8641e1 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/91598487773d768f254d5faf06cf65b13e972f0e.1728558223.git.daniel@makrotopia.org
-Signed-off-by: Paolo Abeni <[email protected]>
----
- 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 (file)
index 155f796..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-From 9d55e68b19f222e6334ef4021c5527998f5ab537 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/86a413b4387c42dcb54f587cc2433a06f16aae83.1728558223.git.daniel@makrotopia.org
-Signed-off-by: Paolo Abeni <[email protected]>
----
- 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 (file)
index c785f8a..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-From 78997e9a5e4d8a4df561e083a92c91ae23010e07 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/b6ec9050339f8244ff898898a1cecc33b13a48fc.1727741563.git.daniel@makrotopia.org
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 39bef9b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-From f95b4725e796b12e5f347a0d161e1d3843142aa8 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/cc5da0a989af8b0d49d823656d88053c4de2ab98.1728057367.git.daniel@makrotopia.org
-Signed-off-by: Jakub Kicinski <[email protected]>
----
- 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 (file)
index 5fd3dcc..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-From eb89c79c1b8f17fc1611540768678e60df89ac42 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/180ccafa837f09908b852a8a874a3808c5ecd2d0.1728558223.git.daniel@makrotopia.org
-Signed-off-by: Paolo Abeni <[email protected]>
----
- 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 (file)
index c57b577..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-From 1758af47b98c17da464cb45f476875150955dd48 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <[email protected]>
-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 <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Link: https://patch.msgid.link/81f4717ab9acf38f3239727a4540ae96fd01109b.1728558223.git.daniel@makrotopia.org
-Signed-off-by: Paolo Abeni <[email protected]>
----
- 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 (file)
index f9299f9..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From b0fa00fe38f673c986633c11087274deeb7ce7b0 Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <[email protected]>
-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 <[email protected]>
-Acked-by: Michael Walle <[email protected]>
-Link: https://lore.kernel.org/r/[email protected]
-Signed-off-by: Bartosz Golaszewski <[email protected]>
----
- 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 (file)
index 19268cf..0000000
+++ /dev/null
@@ -1,1250 +0,0 @@
-From 7b590490e3aa6bfa38bf6e2069a529017fd3c1d2 Mon Sep 17 00:00:00 2001
-From: Linus Walleij <[email protected]>
-Date: Fri, 13 Oct 2023 00:08:35 +0200
-Subject: [PATCH] net: dsa: mv88e6xxx: Support LED control
-
-This adds control over the hardware LEDs in the Marvell
-MV88E6xxx DSA switch and enables it for MV88E6352.
-
-This fixes an imminent problem on the Inteno XG6846 which
-has a WAN LED that simply do not work with hardware
-defaults: driver amendment is necessary.
-
-The patch is modeled after Christian Marangis LED support
-code for the QCA8k DSA switch, I got help with the register
-definitions from Tim Harvey.
-
-After this patch it is possible to activate hardware link
-indication like this (or with a similar script):
-
-  cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
-  echo netdev > trigger
-  echo 1 > link
-
-This makes the green link indicator come up on any link
-speed. It is also possible to be more elaborate, like this:
-
-  cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
-  echo netdev > trigger
-  echo 1 > link_1000
-  cd /sys/class/leds/Marvell\ 88E6352:05:01:amber:wan/
-  echo netdev > trigger
-  echo 1 > link_100
-
-Making the green LED come on for a gigabit link and the
-amber LED come on for a 100 mbit link.
-
-Each port has 2 LED slots (the hardware may use just one or
-none) and the hardware triggers are specified in four bits per
-LED, and some of the hardware triggers are only available on the
-SFP (fiber) uplink. The restrictions are described in the
-port.h header file where the registers are described. For
-example, selector 1 set for LED 1 on port 5 or 6 will indicate
-Fiber 1000 (gigabit) and activity with a blinking LED, but
-ONLY for an SFP connection. If port 5/6 is used with something
-not SFP, this selector is a noop: something else need to be
-selected.
-
-After the previous series rewriting the MV88E6xxx DT
-bindings to use YAML a "leds" subnode is already valid
-for each port, in my scratch device tree it looks like
-this:
-
-   leds {
-     #address-cells = <1>;
-     #size-cells = <0>;
-
-     led@0 {
-       reg = <0>;
-       color = <LED_COLOR_ID_GREEN>;
-       function = LED_FUNCTION_LAN;
-       default-state = "off";
-       linux,default-trigger = "netdev";
-     };
-     led@1 {
-       reg = <1>;
-       color = <LED_COLOR_ID_AMBER>;
-       function = LED_FUNCTION_LAN;
-       default-state = "off";
-     };
-   };
-
-This DT config is not yet configuring everything: when the netdev
-default trigger is assigned the hw acceleration callbacks are
-not called, and there is no way to set the netdev sub-trigger
-type (such as link_1000) from the device tree, such as if you want
-a gigabit link indicator. This has to be done from userspace at
-this point.
-
-We add LED operations to all switches in the 6352 family:
-6172, 6176, 6240 and 6352.
-
-Signed-off-by: Linus Walleij <[email protected]>
----
- drivers/net/dsa/mv88e6xxx/Kconfig  |  10 +
- drivers/net/dsa/mv88e6xxx/Makefile |   1 +
- drivers/net/dsa/mv88e6xxx/chip.c   |  38 +-
- drivers/net/dsa/mv88e6xxx/chip.h   |  11 +
- drivers/net/dsa/mv88e6xxx/leds.c   | 839 +++++++++++++++++++++++++++++
- drivers/net/dsa/mv88e6xxx/port.c   |   1 +
- drivers/net/dsa/mv88e6xxx/port.h   | 133 +++++
- 7 files changed, 1031 insertions(+), 2 deletions(-)
- create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c
-
---- a/drivers/net/dsa/mv88e6xxx/Kconfig
-+++ b/drivers/net/dsa/mv88e6xxx/Kconfig
-@@ -17,3 +17,13 @@ config NET_DSA_MV88E6XXX_PTP
-       help
-         Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch
-         chips that support it.
-+
-+config NET_DSA_MV88E6XXX_LEDS
-+      bool "LED support for Marvell 88E6xxx"
-+      default y
-+      depends on NET_DSA_MV88E6XXX
-+      depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_MV88E6XXX
-+      depends on LEDS_TRIGGERS
-+      help
-+        This enabled support for controlling the LEDs attached to the
-+        Marvell 88E6xxx switch chips.
---- a/drivers/net/dsa/mv88e6xxx/Makefile
-+++ b/drivers/net/dsa/mv88e6xxx/Makefile
-@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
- mv88e6xxx-objs += global2_avb.o
- mv88e6xxx-objs += global2_scratch.o
- mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
-+mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_LEDS) += leds.o
- mv88e6xxx-objs += pcs-6185.o
- mv88e6xxx-objs += pcs-6352.o
- mv88e6xxx-objs += pcs-639x.o
---- a/drivers/net/dsa/mv88e6xxx/chip.c
-+++ b/drivers/net/dsa/mv88e6xxx/chip.c
-@@ -27,6 +27,7 @@
- #include <linux/of_irq.h>
- #include <linux/of_mdio.h>
- #include <linux/platform_data/mv88e6xxx.h>
-+#include <linux/property.h>
- #include <linux/netdevice.h>
- #include <linux/gpio/consumer.h>
- #include <linux/phylink.h>
-@@ -3412,14 +3413,43 @@ static int mv88e6xxx_setup_upstream_port
- static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
- {
-       struct device_node *phy_handle = NULL;
-+      struct fwnode_handle *ports_fwnode;
-+      struct fwnode_handle *port_fwnode;
-       struct dsa_switch *ds = chip->ds;
-+      struct mv88e6xxx_port *p;
-       struct dsa_port *dp;
-       int tx_amp;
-       int err;
-       u16 reg;
-+      u32 val;
--      chip->ports[port].chip = chip;
--      chip->ports[port].port = port;
-+      p = &chip->ports[port];
-+      p->chip = chip;
-+      p->port = port;
-+
-+      /* Look up corresponding fwnode if any */
-+      ports_fwnode = device_get_named_child_node(chip->dev, "ethernet-ports");
-+      if (!ports_fwnode)
-+              ports_fwnode = device_get_named_child_node(chip->dev, "ports");
-+      if (ports_fwnode) {
-+              fwnode_for_each_child_node(ports_fwnode, port_fwnode) {
-+                      if (fwnode_property_read_u32(port_fwnode, "reg", &val))
-+                              continue;
-+                      if (val == port) {
-+                              p->fwnode = port_fwnode;
-+                              p->fiber = fwnode_property_present(port_fwnode, "sfp");
-+                              break;
-+                      }
-+              }
-+      } else {
-+              dev_dbg(chip->dev, "no ethernet ports node defined for the device\n");
-+      }
-+
-+      if (chip->info->ops->port_setup_leds) {
-+              err = chip->info->ops->port_setup_leds(chip, port);
-+              if (err && err != -EOPNOTSUPP)
-+                      return err;
-+      }
-       err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
-                                      SPEED_UNFORCED, DUPLEX_UNFORCED,
-@@ -4653,6 +4683,7 @@ static const struct mv88e6xxx_ops mv88e6
-       .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
-       .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
-       .port_get_cmode = mv88e6352_port_get_cmode,
-+      .port_setup_leds = mv88e6xxx_port_setup_leds,
-       .port_setup_message_port = mv88e6xxx_setup_message_port,
-       .stats_snapshot = mv88e6320_g1_stats_snapshot,
-       .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
-@@ -4755,6 +4786,7 @@ static const struct mv88e6xxx_ops mv88e6
-       .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
-       .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
-       .port_get_cmode = mv88e6352_port_get_cmode,
-+      .port_setup_leds = mv88e6xxx_port_setup_leds,
-       .port_setup_message_port = mv88e6xxx_setup_message_port,
-       .stats_snapshot = mv88e6320_g1_stats_snapshot,
-       .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
-@@ -5030,6 +5062,7 @@ static const struct mv88e6xxx_ops mv88e6
-       .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
-       .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
-       .port_get_cmode = mv88e6352_port_get_cmode,
-+      .port_setup_leds = mv88e6xxx_port_setup_leds,
-       .port_setup_message_port = mv88e6xxx_setup_message_port,
-       .stats_snapshot = mv88e6320_g1_stats_snapshot,
-       .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
-@@ -5460,6 +5493,7 @@ static const struct mv88e6xxx_ops mv88e6
-       .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
-       .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
-       .port_get_cmode = mv88e6352_port_get_cmode,
-+      .port_setup_leds = mv88e6xxx_port_setup_leds,
-       .port_setup_message_port = mv88e6xxx_setup_message_port,
-       .stats_snapshot = mv88e6320_g1_stats_snapshot,
-       .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
---- a/drivers/net/dsa/mv88e6xxx/chip.h
-+++ b/drivers/net/dsa/mv88e6xxx/chip.h
-@@ -13,7 +13,9 @@
- #include <linux/irq.h>
- #include <linux/gpio/consumer.h>
- #include <linux/kthread.h>
-+#include <linux/leds.h>
- #include <linux/phy.h>
-+#include <linux/property.h>
- #include <linux/ptp_clock_kernel.h>
- #include <linux/timecounter.h>
- #include <net/dsa.h>
-@@ -276,6 +278,7 @@ struct mv88e6xxx_vlan {
- struct mv88e6xxx_port {
-       struct mv88e6xxx_chip *chip;
-       int port;
-+      struct fwnode_handle *fwnode;
-       struct mv88e6xxx_vlan bridge_pvid;
-       u64 serdes_stats[2];
-       u64 atu_member_violation;
-@@ -290,6 +293,11 @@ struct mv88e6xxx_port {
-       struct devlink_region *region;
-       void *pcs_private;
-+      /* LED related information */
-+      bool fiber;
-+      struct led_classdev led0;
-+      struct led_classdev led1;
-+
-       /* MacAuth Bypass control flag */
-       bool mab;
- };
-@@ -574,6 +582,9 @@ struct mv88e6xxx_ops {
-                             phy_interface_t mode);
-       int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
-+      /* LED control */
-+      int (*port_setup_leds)(struct mv88e6xxx_chip *chip, int port);
-+
-       /* Some devices have a per port register indicating what is
-        * the upstream port this port should forward to.
-        */
---- /dev/null
-+++ b/drivers/net/dsa/mv88e6xxx/leds.c
-@@ -0,0 +1,839 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+#include <linux/bitfield.h>
-+#include <linux/leds.h>
-+#include <linux/property.h>
-+
-+#include "chip.h"
-+#include "global2.h"
-+#include "port.h"
-+
-+/* Offset 0x16: LED control */
-+
-+static int mv88e6xxx_port_led_write(struct mv88e6xxx_chip *chip, int port, u16 reg)
-+{
-+      reg |= MV88E6XXX_PORT_LED_CONTROL_UPDATE;
-+
-+      return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, reg);
-+}
-+
-+static int mv88e6xxx_port_led_read(struct mv88e6xxx_chip *chip, int port,
-+                                 u16 ptr, u16 *val)
-+{
-+      int err;
-+
-+      err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, ptr);
-+      if (err)
-+              return err;
-+
-+      err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_LED_CONTROL, val);
-+      *val &= 0x3ff;
-+
-+      return err;
-+}
-+
-+static int mv88e6xxx_led_brightness_set(struct mv88e6xxx_port *p, int led,
-+                                      int brightness)
-+{
-+      u16 reg;
-+      int err;
-+
-+      err = mv88e6xxx_port_led_read(p->chip, p->port,
-+                                    MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
-+                                    &reg);
-+      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,
-+                                    &reg);
-+      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,
-+                                    &reg);
-+      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, &reg);
-+      if (err)
-+              return err;
-+
-+      reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
-+
-+      if (led == 0)
-+              dev_dbg(p->chip->dev, "LED 0 hw control on port %d trigger selector 0x%02x\n",
-+                      p->port,
-+                      (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK));
-+      else
-+              dev_dbg(p->chip->dev, "LED 1 hw control on port %d trigger selector 0x%02x\n",
-+                      p->port,
-+                      (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK) >> 4);
-+
-+      return mv88e6xxx_port_led_write(p->chip, p->port, reg);
-+}
-+
-+static int
-+mv88e6xxx_led_hw_control_get(struct mv88e6xxx_port *p, int led, unsigned long *rules)
-+{
-+      u16 val;
-+      int err;
-+
-+      mv88e6xxx_reg_lock(p->chip);
-+      err = mv88e6xxx_port_led_read(p->chip, p->port,
-+                                    MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, &val);
-+      mv88e6xxx_reg_unlock(p->chip);
-+      if (err)
-+              return err;
-+
-+      /* Mask out the selector bits for this port */
-+      if (led == 1) {
-+              val &= MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
-+              /* It's forced blinking/OFF/ON */
-+              if (val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELD ||
-+                  val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELE ||
-+                  val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELF) {
-+                      *rules = 0;
-+                      return 0;
-+              }
-+      } else {
-+              val &= MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
-+              /* It's forced blinking/OFF/ON */
-+              if (val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELD ||
-+                  val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELE ||
-+                  val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELF) {
-+                      *rules = 0;
-+                      return 0;
-+              }
-+      }
-+
-+      err = mv88e6xxx_led_match_rule(p, val, led, rules);
-+      if (!err)
-+              return 0;
-+
-+      dev_dbg(p->chip->dev, "couldn't find matching selector for %04x\n", val);
-+      *rules = 0;
-+      return 0;
-+}
-+
-+static int
-+mv88e6xxx_led0_hw_control_set(struct led_classdev *ldev, unsigned long rules)
-+{
-+      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+      int err;
-+
-+      mv88e6xxx_reg_lock(p->chip);
-+      err = mv88e6xxx_led_hw_control_set(p, 0, rules);
-+      mv88e6xxx_reg_unlock(p->chip);
-+
-+      return err;
-+}
-+
-+static int
-+mv88e6xxx_led1_hw_control_set(struct led_classdev *ldev, unsigned long rules)
-+{
-+      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+      int err;
-+
-+      mv88e6xxx_reg_lock(p->chip);
-+      err = mv88e6xxx_led_hw_control_set(p, 1, rules);
-+      mv88e6xxx_reg_unlock(p->chip);
-+
-+      return err;
-+}
-+
-+static int
-+mv88e6xxx_led0_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
-+{
-+      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+
-+      return mv88e6xxx_led_hw_control_get(p, 0, rules);
-+}
-+
-+static int
-+mv88e6xxx_led1_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
-+{
-+      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+
-+      return mv88e6xxx_led_hw_control_get(p, 1, rules);
-+}
-+
-+static struct device *mv88e6xxx_led_hw_control_get_device(struct mv88e6xxx_port *p)
-+{
-+      struct dsa_port *dp;
-+
-+      dp = dsa_to_port(p->chip->ds, p->port);
-+      if (!dp)
-+              return NULL;
-+      if (dp->user)
-+              return &dp->user->dev;
-+      return NULL;
-+}
-+
-+static struct device *
-+mv88e6xxx_led0_hw_control_get_device(struct led_classdev *ldev)
-+{
-+      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+
-+      return mv88e6xxx_led_hw_control_get_device(p);
-+}
-+
-+static struct device *
-+mv88e6xxx_led1_hw_control_get_device(struct led_classdev *ldev)
-+{
-+      struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+
-+      return mv88e6xxx_led_hw_control_get_device(p);
-+}
-+
-+int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port)
-+{
-+      struct fwnode_handle *led = NULL, *leds = NULL;
-+      struct led_init_data init_data = { };
-+      enum led_default_state state;
-+      struct mv88e6xxx_port *p;
-+      struct led_classdev *l;
-+      struct device *dev;
-+      u32 led_num;
-+      int ret;
-+
-+      /* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */
-+      if (port > 5)
-+              return -EOPNOTSUPP;
-+
-+      p = &chip->ports[port];
-+      if (!p->fwnode)
-+              return 0;
-+
-+      dev = chip->dev;
-+
-+      leds = fwnode_get_named_child_node(p->fwnode, "leds");
-+      if (!leds) {
-+              dev_dbg(dev, "No Leds node specified in device tree for port %d!\n",
-+                      port);
-+              return 0;
-+      }
-+
-+      fwnode_for_each_child_node(leds, led) {
-+              /* Reg represent the led number of the port, max 2
-+               * LEDs can be connected to each port, in some designs
-+               * only one LED is connected.
-+               */
-+              if (fwnode_property_read_u32(led, "reg", &led_num))
-+                      continue;
-+              if (led_num > 1) {
-+                      dev_err(dev, "invalid LED specified port %d\n", port);
-+                      return -EINVAL;
-+              }
-+
-+              if (led_num == 0)
-+                      l = &p->led0;
-+              else
-+                      l = &p->led1;
-+
-+              state = led_init_default_state_get(led);
-+              switch (state) {
-+              case LEDS_DEFSTATE_ON:
-+                      l->brightness = 1;
-+                      mv88e6xxx_led_brightness_set(p, led_num, 1);
-+                      break;
-+              case LEDS_DEFSTATE_KEEP:
-+                      break;
-+              default:
-+                      l->brightness = 0;
-+                      mv88e6xxx_led_brightness_set(p, led_num, 0);
-+              }
-+
-+              l->max_brightness = 1;
-+              if (led_num == 0) {
-+                      l->brightness_set_blocking = mv88e6xxx_led0_brightness_set_blocking;
-+                      l->blink_set = mv88e6xxx_led0_blink_set;
-+                      l->hw_control_is_supported = mv88e6xxx_led0_hw_control_is_supported;
-+                      l->hw_control_set = mv88e6xxx_led0_hw_control_set;
-+                      l->hw_control_get = mv88e6xxx_led0_hw_control_get;
-+                      l->hw_control_get_device = mv88e6xxx_led0_hw_control_get_device;
-+              } else {
-+                      l->brightness_set_blocking = mv88e6xxx_led1_brightness_set_blocking;
-+                      l->blink_set = mv88e6xxx_led1_blink_set;
-+                      l->hw_control_is_supported = mv88e6xxx_led1_hw_control_is_supported;
-+                      l->hw_control_set = mv88e6xxx_led1_hw_control_set;
-+                      l->hw_control_get = mv88e6xxx_led1_hw_control_get;
-+                      l->hw_control_get_device = mv88e6xxx_led1_hw_control_get_device;
-+              }
-+              l->hw_control_trigger = "netdev";
-+
-+              init_data.default_label = ":port";
-+              init_data.fwnode = led;
-+              init_data.devname_mandatory = true;
-+              init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name,
-+                                               port, led_num);
-+              if (!init_data.devicename)
-+                      return -ENOMEM;
-+
-+              ret = devm_led_classdev_register_ext(dev, l, &init_data);
-+              kfree(init_data.devicename);
-+
-+              if (ret) {
-+                      dev_err(dev, "Failed to init LED %d for port %d", led_num, port);
-+                      return ret;
-+              }
-+      }
-+
-+      return 0;
-+}
---- a/drivers/net/dsa/mv88e6xxx/port.c
-+++ b/drivers/net/dsa/mv88e6xxx/port.c
-@@ -12,6 +12,7 @@
- #include <linux/if_bridge.h>
- #include <linux/phy.h>
- #include <linux/phylink.h>
-+#include <linux/property.h>
- #include "chip.h"
- #include "global2.h"
---- a/drivers/net/dsa/mv88e6xxx/port.h
-+++ b/drivers/net/dsa/mv88e6xxx/port.h
-@@ -309,6 +309,130 @@
- /* Offset 0x13: OutFiltered Counter */
- #define MV88E6XXX_PORT_OUT_FILTERED   0x13
-+/* Offset 0x16: LED Control */
-+#define MV88E6XXX_PORT_LED_CONTROL                            0x16
-+#define MV88E6XXX_PORT_LED_CONTROL_UPDATE                     BIT(15)
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_MASK                       GENMASK(14, 12)
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL         (0x00 << 12) /* Control for LED 0 and 1 */
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK      (0x06 << 12) /* Stetch and Blink Rate */
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_CNTL_SPECIAL               (0x07 << 12) /* Control for the Port's Special LED */
-+#define MV88E6XXX_PORT_LED_CONTROL_DATA_MASK                  GENMASK(10, 0)
-+/* Selection masks valid for either port 1,2,3,4 or 5 */
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK              GENMASK(3, 0)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK              GENMASK(7, 4)
-+/* Selection control for LED 0 and 1, ports 5 and 6 only has LED 0
-+ * Bits  Function
-+ * 0..3  LED 0 control selector on ports 1-5
-+ * 4..7  LED 1 control selector on ports 1-4 on port 5 this controls LED 0 of port 6
-+ *
-+ * Sel Port LED Function for the 6352 family:
-+ * 0   1-4  0   Link/Act/Speed by Blink Rate (off=no link, on=link, blink=activity, blink speed=link speed)
-+ *     1-4  1   Port 2's Special LED
-+ *     5-6  0   Port 5 Link/Act (off=no link, on=link, blink=activity)
-+ *     5-6  1   Port 6 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 1   1-4  0   100/1000 Link/Act (off=no link, on=100 or 1000 link, blink=activity)
-+ *     1-4  1   10/100 Link Act (off=no link, on=10 or 100 link, blink=activity)
-+ *     5-6  0   Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
-+ *     5-6  1   Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 2   1-4  0   1000 Link/Act (off=no link, on=link 1000, blink=activity)
-+ *     1-4  1   10/100 Link/Act (off=no link, on=10 or 100 link, blink=activity)
-+ *     5-6  0   Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
-+ *     5-6  1   Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
-+ * 3   1-4  0   Link/Act (off=no link, on=link, blink=activity)
-+ *     1-4  1   1000 Link (off=no link, on=1000 link)
-+ *     5-6  0   Port 0's Special LED
-+ *     5-6  1   Fiber Link (off=no link, on=link)
-+ * 4   1-4  0   Port 0's Special LED
-+ *     1-4  1   Port 1's Special LED
-+ *     5-6  0   Port 1's Special LED
-+ *     5-6  1   Port 5 Link/Act (off=no link, on=link, blink=activity)
-+ * 5   1-4  0   Reserved
-+ *     1-4  1   Reserved
-+ *     5-6  0   Port 2's Special LED
-+ *     5-6  1   Port 6 Link (off=no link, on=link)
-+ * 6   1-4  0   Duplex/Collision (off=half-duplex,on=full-duplex,blink=collision)
-+ *     1-4  1   10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
-+ *     5-6  0   Port 5 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
-+ *     5-6  1   Port 6 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
-+ * 7   1-4  0   10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
-+ *     1-4  1   10/1000 Link (off=no link, on=10 or 1000 link)
-+ *     5-6  0   Port 5 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed)
-+ *     5-6  1   Port 6 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity,  blink speed=link speed)
-+ * 8   1-4  0   Link (off=no link, on=link)
-+ *     1-4  1   Activity (off=no link, blink on=activity)
-+ *     5-6  0   Port 6 Link/Act (off=no link, on=link, blink=activity)
-+ *     5-6  1   Port 0's Special LED
-+ * 9   1-4  0   10 Link (off=no link, on=10 link)
-+ *     1-4  1   100 Link (off=no link, on=100 link)
-+ *     5-6  0   Reserved
-+ *     5-6  1   Port 1's Special LED
-+ * a   1-4  0   10 Link/Act (off=no link, on=10 link, blink=activity)
-+ *     1-4  1   100 Link/Act (off=no link, on=100 link, blink=activity)
-+ *     5-6  0   Reserved
-+ *     5-6  1   Port 2's Special LED
-+ * b   1-4  0   100/1000 Link (off=no link, on=100 or 1000 link)
-+ *     1-4  1   10/100 Link (off=no link, on=100 link, blink=activity)
-+ *     5-6  0   Reserved
-+ *     5-6  1   Reserved
-+ * c     *  *   PTP Act (blink on=PTP activity)
-+ * d     *  *   Force Blink
-+ * e     *  *   Force Off
-+ * f     *  *   Force On
-+ */
-+/* Select LED0 output */
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0                  0x0
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1                  0x1
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2                  0x2
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3                  0x3
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL4                  0x4
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL5                  0x5
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6                  0x6
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7                  0x7
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8                  0x8
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9                  0x9
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELA                  0xa
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELB                  0xb
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELC                  0xc
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELD                  0xd
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELE                  0xe
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELF                  0xf
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0                  (0x0 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1                  (0x1 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2                  (0x2 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3                  (0x3 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4                  (0x4 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5                  (0x5 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6                  (0x6 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7                  (0x7 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8                  (0x8 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9                  (0x9 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELA                  (0xa << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELB                  (0xb << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELC                  (0xc << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELD                  (0xd << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELE                  (0xe << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELF                  (0xf << 4)
-+/* Stretch and Blink Rate Control (Index 0x06 of LED Control) */
-+/* Pulse Stretch Selection for all LED's on this port */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE    (0 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS    (1 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS    (2 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS    (3 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS   (4 << 4)
-+/* Blink Rate Selection for all LEDs on this port */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS               0
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS               1
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS               2
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS      3
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS      4
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS      5
-+ /* Control for Special LED (Index 0x7 of LED Control on Port0) */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x07_P0_LAN_LINKACT_SHIFT  0 /* bits 6:0 LAN Link Activity LED */
-+/* Control for Special LED (Index 0x7 of LED Control on Port 1) */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x07_P1_WAN_LINKACT_SHIFT  0 /* bits 6:0 WAN Link Activity LED */
-+/* Control for Special LED (Index 0x7 of LED Control on Port 2) */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x07_P2_PTP_ACT            0 /* bits 6:0 PTP Activity */
-+
- /* Offset 0x18: IEEE Priority Mapping Table */
- #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE                    0x18
- #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE             0x8000
-@@ -457,6 +581,15 @@ int mv88e6393x_port_set_cmode(struct mv8
-                             phy_interface_t mode);
- int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
- int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
-+#ifdef CONFIG_NET_DSA_MV88E6XXX_LEDS
-+int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port);
-+#else
-+static inline int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip,
-+                                          int port)
-+{
-+      return 0;
-+}
-+#endif
- int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
-                                bool drop_untagged);
- int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map);
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 (file)
index 8dca649..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-From 239d87327dcd361b0098038995f8908f3296864f Mon Sep 17 00:00:00 2001
-From: Kees Cook <[email protected]>
-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" <[email protected]>
-Closes: https://lore.kernel.org/all/[email protected]/
-Reported-by: Nilay Shroff <[email protected]>
-Closes: https://lore.kernel.org/all/[email protected]/
-Tested-by: Nilay Shroff <[email protected]>
-Acked-by: Yury Norov <[email protected]>
-Acked-by: Greg Kroah-Hartman <[email protected]>
-Signed-off-by: Kees Cook <[email protected]>
----
- 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);                           \
- })
- /*