* [PATCH v4 0/3] phy: Add support for Airoha AN7583 USB PHY
@ 2026-09-01 12:39 Christian Marangi
2026-09-01 12:39 ` [PATCH v4 1/3] dt-bindings: phy: airoha: Document support for " Christian Marangi
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Christian Marangi @ 2026-09-01 12:39 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Marangi, linux-phy, devicetree,
linux-kernel
This small series add support for Airoha USB PHY and Gen2 PCIe
PHY.
Changes v4:
- Fix typo for Documentation patch
- Fix wrong regex for usb subnode for Documentation patch
- Improve register example for Documentation patch
- Address bugs reported by bot (off-by one and xlate function)
Changes v3:
- Fix broken patch for YAML patch
- Split the YAML for USB and PCIe
- Rework driver to direct node for PCIe PHY
Link: https://lore.kernel.org/all/20260827131551.26725-1-ansuelsmth@gmail.com/
Changes v2:
- Add Documentation
- Out of RFC
- Rework to Serdes PHY instead of SCU (following
for consistency AN7581 implementation)
Link: https://lore.kernel.org/all/20260811124724.702467-1-ansuelsmth@gmail.com/
Christian Marangi (3):
dt-bindings: phy: airoha: Document support for AN7583 USB PHY
dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY
phy: airoha: Add support for Airoha AN7583 USB PHY
.../phy/airoha,an7583-pcie-gen2-phy.yaml | 63 +
.../bindings/phy/airoha,an7583-usb-phy.yaml | 133 ++
drivers/phy/Kconfig | 1 +
drivers/phy/Makefile | 3 +-
drivers/phy/airoha/Kconfig | 11 +
drivers/phy/airoha/Makefile | 3 +
drivers/phy/airoha/phy-an7583-usb.c | 2023 +++++++++++++++++
7 files changed, 2236 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/phy/airoha,an7583-pcie-gen2-phy.yaml
create mode 100644 Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
create mode 100644 drivers/phy/airoha/Kconfig
create mode 100644 drivers/phy/airoha/Makefile
create mode 100644 drivers/phy/airoha/phy-an7583-usb.c
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 1/3] dt-bindings: phy: airoha: Document support for AN7583 USB PHY
2026-09-01 12:39 [PATCH v4 0/3] phy: Add support for Airoha AN7583 USB PHY Christian Marangi
@ 2026-09-01 12:39 ` Christian Marangi
2026-09-01 12:39 ` [PATCH v4 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY Christian Marangi
2026-09-01 12:39 ` [PATCH v4 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY Christian Marangi
2 siblings, 0 replies; 6+ messages in thread
From: Christian Marangi @ 2026-09-01 12:39 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Marangi, linux-phy, devicetree,
linux-kernel
Add documentation for Airoha AN7583 USB PHY that describe the USB PHY
for the USB controller.
Airoha AN7583 SoC support a maximum of 2 USB port. The USB 2.0 mode is
always supported. The USB 3.0 mode is optional and depends on the Serdes
mode currently configured on the system for the relevant USB port.
To correctly calibrate, the USB 2.0 port require correct value in
"airoha,usb2-monitor-clk-sel" property. Both the 2 USB 2.0 port permit
selecting one of the 4 monitor clock for calibration (internal clock not
exposed to the system) but each port have only one of the 4 actually
connected in HW hence the correct value needs to be specified in DT
based on board and the physical port. Normally it's monitor clock 1 for
USB1 and monitor clock 2 for USB2.
To correctly setup the Serdes mode attached to the USB 3.0 mode, a phys
property is required with the phandle pointing to the correct Serdes port
provided by the SCU node. Providing the phys property is optional if USB
3.0 is not used.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
.../bindings/phy/airoha,an7583-usb-phy.yaml | 133 ++++++++++++++++++
1 file changed, 133 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml b/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
new file mode 100644
index 000000000000..f1a5d83e8968
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
@@ -0,0 +1,133 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/airoha,an7583-usb-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Airoha AN7583 SoC USB PHY
+
+maintainers:
+ - Christian Marangi <ansuelsmth@gmail.com>
+
+description: >
+ The Airoha AN7583 SoC USB PHY describes the USB PHY for the USB controller..
+
+ Airoha AN7583 SoC support a maximum of 2 USB port. The USB 2.0 mode is
+ always supported. The USB 3.0 mode is optional and depends on the Serdes
+ mode currently configured on the system for the relevant USB port.
+
+ On Airoha AN7583 there is an unified PHY implementation where a single
+ PHY provide support for both the 2 USB 2.0 port and
+ optionally one 3.0 USB.
+
+properties:
+ compatible:
+ const: airoha,an7583-usb-phy
+
+ reg:
+ items:
+ - description: phy register
+ - description: ana register
+ - description: pma register
+ - description: dig register
+
+ reg-names:
+ items:
+ - const: phy
+ - const: ana
+ - const: pma
+ - const: dig
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ usb3-phy:
+ type: object
+
+ properties:
+ phys:
+ items:
+ - description: phandle to Serdes PHY
+
+ '#phy-cells':
+ description: The cell contains the mode, PHY_TYPE_USB2 or PHY_TYPE_USB3,
+ as defined in dt-bindings/phy/phy.h.
+ const: 1
+
+ required:
+ - phys
+ - '#phy-cells'
+
+ additionalProperties: false
+
+patternProperties:
+ '^usb2-phy@[0-9a-f]+$':
+ type: object
+
+ properties:
+ reg:
+ enum: [0x0, 0x1000]
+
+ airoha,usb2-monitor-clk-sel:
+ description: Describe what oscillator across the available 4
+ should be selected for USB 2.0 Slew Rate calibration.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1, 2, 3]
+
+ '#phy-cells':
+ description: The cell contains the mode, PHY_TYPE_USB2 or PHY_TYPE_USB3,
+ as defined in dt-bindings/phy/phy.h.
+ const: 1
+
+ required:
+ - reg
+ - airoha,usb2-monitor-clk-sel
+ - '#phy-cells'
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - '#address-cells'
+ - '#size-cells'
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ phy@1fac0000 {
+ compatible = "airoha,an7583-usb-phy";
+ reg = <0x1fac0000 0x1200>,
+ <0x1fa6f000 0x100>,
+ <0x1fa6e000 0x400>,
+ <0x1fa6a000 0x900>;
+ reg-names = "phy", "ana", "pma", "dig";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usb2-phy@0 {
+ reg = <0x0>;
+ airoha,usb2-monitor-clk-sel = <0>;
+
+ #phy-cells = <1>;
+ };
+
+ usb2-phy@1000 {
+ reg = <0x1000>;
+ airoha,usb2-monitor-clk-sel = <1>;
+
+ #phy-cells = <1>;
+ };
+
+ usb3-phy {
+ phys = <&serdes_phy>;
+
+ #phy-cells = <1>;
+ };
+ };
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY
2026-09-01 12:39 [PATCH v4 0/3] phy: Add support for Airoha AN7583 USB PHY Christian Marangi
2026-09-01 12:39 ` [PATCH v4 1/3] dt-bindings: phy: airoha: Document support for " Christian Marangi
@ 2026-09-01 12:39 ` Christian Marangi
2026-09-01 12:39 ` [PATCH v4 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY Christian Marangi
2 siblings, 0 replies; 6+ messages in thread
From: Christian Marangi @ 2026-09-01 12:39 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Marangi, linux-phy, devicetree,
linux-kernel
Document support for AN7583 Gen2 PCIe PHY used to make the Gen2 PCIe port
work. Add the required register to configure the PCIe PHY and provide an
example for it.
Similar to the USB 3.0 PHY, a dedicated phys property is required to
configure the serdes for PCIe or Ethernet usage.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
.../phy/airoha,an7583-pcie-gen2-phy.yaml | 63 +++++++++++++++++++
1 file changed, 63 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/airoha,an7583-pcie-gen2-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/airoha,an7583-pcie-gen2-phy.yaml b/Documentation/devicetree/bindings/phy/airoha,an7583-pcie-gen2-phy.yaml
new file mode 100644
index 000000000000..424da3c5ad01
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/airoha,an7583-pcie-gen2-phy.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/airoha,an7583-pcie-gen2-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Airoha AN7583 SoC PCIe Gen2 PHY
+
+maintainers:
+ - Christian Marangi <ansuelsmth@gmail.com>
+
+description: >
+ The Airoha AN7583 SoC PCIe Gen2 PHY describes the PCIe PHY for the
+ Gen2 PCIe controller.
+
+ This PCIe PHY makes use of a dedicated USB PHY for PCIe usage and
+ can also be used for Ethernet usage for SGMII or HSGMII mode.
+
+properties:
+ compatible:
+ const: airoha,an7583-pcie-gen2-phy
+
+ reg:
+ items:
+ - description: ana register
+ - description: pma register
+ - description: dig register
+
+ reg-names:
+ items:
+ - const: ana
+ - const: pma
+ - const: dig
+
+ phys:
+ items:
+ - description: phandle to Serdes PHY
+
+ '#phy-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - phys
+ - '#phy-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ phy@1fa5f000 {
+ compatible = "airoha,an7583-pcie-gen2-phy";
+ reg = <0x1fa5f000 0x100>,
+ <0x1fa5e000 0x400>,
+ <0x1fa5a000 0x900>;
+ reg-names = "ana", "pma", "dig";
+
+ phys = <&serdes_phy>;
+
+ #phy-cells = <0>;
+ };
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY
2026-09-01 12:39 [PATCH v4 0/3] phy: Add support for Airoha AN7583 USB PHY Christian Marangi
2026-09-01 12:39 ` [PATCH v4 1/3] dt-bindings: phy: airoha: Document support for " Christian Marangi
2026-09-01 12:39 ` [PATCH v4 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY Christian Marangi
@ 2026-09-01 12:39 ` Christian Marangi
2026-09-01 12:53 ` sashiko-bot
2 siblings, 1 reply; 6+ messages in thread
From: Christian Marangi @ 2026-09-01 12:39 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Marangi, linux-phy, devicetree,
linux-kernel
Add support for USB PHY for Airoha AN7583 SoC, this share some U2 init
from AN7581 but use a totally different init phase for PLL and
calibration for U3. Also on AN7583 there is a single USB PHY that init 2
U2 port and one U3 port. (the USB controller expose 2 hub, one with 2
usb 2.0 port and one with one 3.0 port)
A second USB PHY is used for PCIe Gen2 controller and follow the same
calibration and setup logic of USB.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/phy/Kconfig | 1 +
drivers/phy/Makefile | 3 +-
drivers/phy/airoha/Kconfig | 11 +
drivers/phy/airoha/Makefile | 3 +
drivers/phy/airoha/phy-an7583-usb.c | 2023 +++++++++++++++++++++++++++
5 files changed, 2040 insertions(+), 1 deletion(-)
create mode 100644 drivers/phy/airoha/Kconfig
create mode 100644 drivers/phy/airoha/Makefile
create mode 100644 drivers/phy/airoha/phy-an7583-usb.c
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 19f3b7d12b7d..80b7c50fd768 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -168,6 +168,7 @@ config PHY_XGENE
help
This option enables support for APM X-Gene SoC multi-purpose PHY.
+source "drivers/phy/airoha/Kconfig"
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
source "drivers/phy/apple/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index d7aa516bcc49..0baf0b7fd077 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -20,7 +20,8 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
-obj-$(CONFIG_GENERIC_PHY) += allwinner/ \
+obj-$(CONFIG_GENERIC_PHY) += airoha/ \
+ allwinner/ \
amlogic/ \
apple/ \
axiado/ \
diff --git a/drivers/phy/airoha/Kconfig b/drivers/phy/airoha/Kconfig
new file mode 100644
index 000000000000..13e49ff947e3
--- /dev/null
+++ b/drivers/phy/airoha/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config PHY_AIROHA_AN7583_USB
+ tristate "Airoha AN7583 USB PHY Driver"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+ help
+ Say 'Y' here to add support for Airoha AN7583 USB PHY driver.
+ This driver create the basic PHY instance and provides initialize
+ callback for USB port.
diff --git a/drivers/phy/airoha/Makefile b/drivers/phy/airoha/Makefile
new file mode 100644
index 000000000000..e484a803505b
--- /dev/null
+++ b/drivers/phy/airoha/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_PHY_AIROHA_AN7583_USB) += phy-an7583-usb.o
diff --git a/drivers/phy/airoha/phy-an7583-usb.c b/drivers/phy/airoha/phy-an7583-usb.c
new file mode 100644
index 000000000000..46b5f09582cf
--- /dev/null
+++ b/drivers/phy/airoha/phy-an7583-usb.c
@@ -0,0 +1,2023 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <linux/bitfield.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+/* PHY */
+#define AIROHA_USB_PHY_FMCR0 0x100
+#define AIROHA_USB_PHY_MONCLK_SEL GENMASK(27, 26)
+#define AIROHA_USB_PHY_MONCLK_SEL0 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x0)
+#define AIROHA_USB_PHY_MONCLK_SEL1 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x1)
+#define AIROHA_USB_PHY_MONCLK_SEL2 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x2)
+#define AIROHA_USB_PHY_MONCLK_SEL3 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x3)
+#define AIROHA_USB_PHY_FREQDET_EN BIT(24)
+#define AIROHA_USB_PHY_CYCLECNT GENMASK(23, 0)
+#define AIROHA_USB_PHY_FMMONR0 0x10c
+#define AIROHA_USB_PHY_USB_FM_OUT GENMASK(31, 0)
+#define AIROHA_USB_PHY_FMMONR1 0x110
+#define AIROHA_USB_PHY_FRCK_EN BIT(8)
+
+#define AIROHA_USB_PHY_USBPHYACR2 0x308
+#define AIROHA_USB_PHY_SIFSLV_MAC_BANDGAP_EN BIT(17)
+#define AIROHA_USB_PHY_USBPHYACR4 0x310
+#define AIROHA_USB_PHY_USB20_FS_CR GENMASK(10, 8)
+#define AIROHA_USB_PHY_USB20_FS_CR_MAX FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x0)
+#define AIROHA_USB_PHY_USB20_FS_CR_NORMAL FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x2)
+#define AIROHA_USB_PHY_USB20_FS_CR_SMALLER FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x4)
+#define AIROHA_USB_PHY_USB20_FS_CR_MIN FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x6)
+#define AIROHA_USB_PHY_USB20_FS_SR GENMASK(2, 0)
+#define AIROHA_USB_PHY_USB20_FS_SR_MAX FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x0)
+#define AIROHA_USB_PHY_USB20_FS_SR_NORMAL FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x2)
+#define AIROHA_USB_PHY_USB20_FS_SR_SMALLER FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x4)
+#define AIROHA_USB_PHY_USB20_FS_SR_MIN FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x6)
+#define AIROHA_USB_PHY_USBPHYACR5 0x314
+#define AIROHA_USB_PHY_USB20_DISC_FIT_EN BIT(28)
+#define AIROHA_USB_PHY_USB20_HSTX_SRCAL_EN BIT(15)
+#define AIROHA_USB_PHY_USB20_HSTX_SRCTRL GENMASK(14, 12)
+#define AIROHA_USB_PHY_USBPHYACR6 0x318
+#define AIROHA_USB_PHY_USB20_BC11_SW_EN BIT(23)
+#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL GENMASK(10, 9)
+#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_ENPLL \
+ FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, 0x0)
+#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_IDLEB_RCV_EN \
+ FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, 0x1)
+#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_NO_ENPLL_FS_BIAS_EN \
+ FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, 0x2)
+#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_USB20_HSRX_TMODE_EN \
+ FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, 0x3)
+#define AIROHA_USB_PHY_USB20_DISCTH GENMASK(7, 4)
+#define AIROHA_USB_PHY_USB20_DISCTH_400 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x0)
+#define AIROHA_USB_PHY_USB20_DISCTH_420 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x1)
+#define AIROHA_USB_PHY_USB20_DISCTH_440 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x2)
+#define AIROHA_USB_PHY_USB20_DISCTH_460 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x3)
+#define AIROHA_USB_PHY_USB20_DISCTH_480 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x4)
+#define AIROHA_USB_PHY_USB20_DISCTH_500 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x5)
+#define AIROHA_USB_PHY_USB20_DISCTH_520 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x6)
+#define AIROHA_USB_PHY_USB20_DISCTH_540 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x7)
+#define AIROHA_USB_PHY_USB20_DISCTH_560 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x8)
+#define AIROHA_USB_PHY_USB20_DISCTH_580 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x9)
+#define AIROHA_USB_PHY_USB20_DISCTH_600 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xa)
+#define AIROHA_USB_PHY_USB20_DISCTH_620 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xb)
+#define AIROHA_USB_PHY_USB20_DISCTH_640 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xc)
+#define AIROHA_USB_PHY_USB20_DISCTH_660 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xd)
+#define AIROHA_USB_PHY_USB20_DISCTH_680 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xe)
+#define AIROHA_USB_PHY_USB20_DISCTH_700 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xf)
+#define AIROHA_USB_PHY_USB20_SQTH GENMASK(3, 0)
+#define AIROHA_USB_PHY_USB20_SQTH_85 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x0)
+#define AIROHA_USB_PHY_USB20_SQTH_90 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x1)
+#define AIROHA_USB_PHY_USB20_SQTH_95 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x2)
+#define AIROHA_USB_PHY_USB20_SQTH_100 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x3)
+#define AIROHA_USB_PHY_USB20_SQTH_105 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x4)
+#define AIROHA_USB_PHY_USB20_SQTH_110 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x5)
+#define AIROHA_USB_PHY_USB20_SQTH_115 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x6)
+#define AIROHA_USB_PHY_USB20_SQTH_120 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x7)
+#define AIROHA_USB_PHY_USB20_SQTH_125 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x8)
+#define AIROHA_USB_PHY_USB20_SQTH_130 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x9)
+#define AIROHA_USB_PHY_USB20_SQTH_135 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xa)
+#define AIROHA_USB_PHY_USB20_SQTH_140 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xb)
+#define AIROHA_USB_PHY_USB20_SQTH_145 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xc)
+#define AIROHA_USB_PHY_USB20_SQTH_150 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xd)
+#define AIROHA_USB_PHY_USB20_SQTH_155 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xe)
+#define AIROHA_USB_PHY_USB20_SQTH_160 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xf)
+
+#define AIROHA_USB_PHY_U2PHYACR3 0x31c
+#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE GENMASK(25, 24)
+#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_TOGGLE FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, 0x0)
+#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_HS_TERM FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, 0x1)
+#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_FORCE_DISABLE FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, 0x2)
+#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_FORCE_ENABLE FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, 0x3)
+#define AIROHA_USB_PHY_USB20_USB11_TMODE_EN BIT(19)
+#define AIROHA_USB_PHY_USB20_TMODE_FS_LS_TX_EN BIT(18)
+#define AIROHA_USB_PHY_USB20_PUPD_BIST_EN BIT(12)
+#define AIROHA_USB_PHY_U2PHYDTM0 0x368
+#define AIROHA_USB_PHY_FORCE_XCVRSEL BIT(19)
+#define AIROHA_USB_PHY_FORCE_SUSPENDDM BIT(18)
+#define AIROHA_USB_PHY_FORCE_TERMSEL BIT(17)
+#define AIROHA_USB_PHY_XCVRSEL GENMASK(5, 4)
+#define AIROHA_USB_PHY_TERMSEL BIT(2)
+#define AIROHA_USB_PHY_U2PHYDTM1 0x36c
+#define AIROHA_USB_PHY_FORCE_IDDIG BIT(9)
+#define AIROHA_USB_PHY_IDDIG BIT(1)
+
+#define AIROHA_USB_PHY_GPIO_CTLD 0x80c
+#define AIROHA_USB_PHY_C60802_GPIO_CTLD GENMASK(31, 0)
+#define AIROHA_USB_PHY_SSUSB_IP_SW_RST BIT(31)
+#define AIROHA_USB_PHY_MCU_BUS_CK_GATE_EN BIT(30)
+#define AIROHA_USB_PHY_FORCE_SSUSB_IP_SW_RST BIT(29)
+#define AIROHA_USB_PHY_SSUSB_SW_RST BIT(28)
+
+#define AIROHA_USB_PHY_U3_PHYA_REG0 0xb00
+#define AIROHA_USB_PHY_SSUSB_BG_DIV GENMASK(29, 28)
+#define AIROHA_USB_PHY_SSUSB_BG_DIV_2 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x0)
+#define AIROHA_USB_PHY_SSUSB_BG_DIV_4 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x1)
+#define AIROHA_USB_PHY_SSUSB_BG_DIV_8 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x2)
+#define AIROHA_USB_PHY_SSUSB_BG_DIV_16 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x3)
+#define AIROHA_USB_PHY_U3_PHYA_REG1 0xb04
+#define AIROHA_USB_PHY_SSUSB_XTAL_TOP_RESERVE GENMASK(25, 10)
+#define AIROHA_USB_PHY_U3_PHYA_REG6 0xb18
+#define AIROHA_USB_PHY_SSUSB_CDR_RESERVE GENMASK(31, 24)
+#define AIROHA_USB_PHY_U3_PHYA_REG8 0xb20
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY GENMASK(7, 6)
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_32 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x0)
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_64 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x1)
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_128 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x2)
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_216 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x3)
+
+#define AIROHA_USB_PHY_U3_PHYA_DA_REG19 0xc38
+#define AIROHA_USB_PHY_SSUSB_PLL_SSC_DELTA1_U3 GENMASK(15, 0)
+
+/* ANA */
+#define AIROHA_USB_ANA_RXAFE_RESERVE 0x4
+#define AIROHA_USB_ANA_CDR_PD_10B_EN BIT(11)
+#define AIROHA_USB_ANA_CDR_PD_EDGE_DIS BIT(10)
+#define AIROHA_USB_ANA_CDR_LPF_BOT_LIM 0x8
+#define AIROHA_USB_ANA_CDR_LPF_KP_GAIN GENMASK(26, 24)
+#define AIROHA_USB_ANA_CDR_LPF_KI_GAIN GENMASK(22, 20)
+#define AIROHA_USB_ANA_CDR_LPF_MJV_LIM 0xc
+#define AIROHA_USB_ANA_CDR_LPF_RATIO GENMASK(5, 4)
+#define AIROHA_USB_ANA_CDR_PR_CKREF_DIV1 0x18
+#define AIROHA_USB_ANA_CDR_PR_KBAND_DIV GENMASK(26, 24)
+#define AIROHA_USB_ANA_CDR_PR_DAC_BAND GENMASK(12, 8)
+#define AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG 0x1c
+#define AIROHA_USB_ANA_CDR_PR_XFICK_EN BIT(30)
+#define AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE BIT(6)
+#define AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE GENMASK(5, 0)
+#define AIROHA_USB_ANA_CDR_FORCE_IBANDLPF_R_OFF 0x20
+#define AIROHA_USB_ANA_CDR_PHYCK_RSTB BIT(13)
+#define AIROHA_USB_ANA_QP_TX_MODE_16B_EN 0x28
+#define AIROHA_USB_QP_TX_RESERVE GENMASK(31, 16)
+#define AIROHA_USB_ANA_TX_VLMON_EN BIT(2)
+#define AIROHA_USB_ANA_TX_RESERVE_8 BIT(8)
+#define AIROHA_USB_ANA_RXLBTX_EN 0x2c
+#define AIROHA_USB_ANA_TX_DMEDGEGEN_EN BIT(27)
+#define AIROHA_USB_ANA_TX_RXDET_METHOD BIT(25)
+#define AIROHA_USB_ANA_SSUSB_BGR_EN 0x30
+#define AIROHA_USB_ANA_BIAS_V2V_CAL GENMASK(26, 21)
+#define AIROHA_USB_ANA_SSUSB_BG_DIV GENMASK(3, 2)
+#define AIROHA_USB_ANA_SSUSB_CHPEN BIT(1)
+#define AIROHA_USB_ANA_CLKDRV_IMPSEL 0x34
+#define AIROHA_USB_ANA_PCIE_CLKDRV_AMP GENMASK(27, 25)
+#define AIROHA_USB_ANA_PCIE_CLKDRV_FORCEIN GENMASK(24, 23)
+#define AIROHA_USB_ANA_PCIE_CLKDRV_HZ BIT(14)
+#define AIROHA_USB_ANA_PCIE_CLKDRV_RP GENMASK(13, 9)
+#define AIROHA_USB_ANA_PCIE_CLKDRV_IMPSEL GENMASK(4, 0)
+#define AIROHA_USB_ANA_TDC_FT_CK_EN 0x38
+#define AIROHA_USB_ANA_PLL_DEBUG_SEL BIT(19)
+#define AIROHA_USB_ANA_VUSB10_ON BIT(8)
+#define AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL 0x3c
+#define AIROHA_USB_ANA_PLL_PREDIV GENMASK(26, 25)
+#define AIROHA_USB_ANA_PLL_OSCAL_ENB BIT(19)
+#define AIROHA_USB_ANA_PLL_MON_LDO_SEL GENMASK(18, 16)
+#define AIROHA_USB_ANA_PLL_MONVC_EN BIT(14)
+#define AIROHA_USB_ANA_PLL_LDOLPF_VSEL GENMASK(6, 5)
+#define AIROHA_USB_ANA_PLL_SDM_ORD 0x40
+#define AIROHA_USB_ANA_PLL_SSC_TRI_EN BIT(4)
+#define AIROHA_USB_ANA_PLL_SSC_PHASE_INI BIT(3)
+
+/* PMA */
+#define AIROHA_USB_PMA_TX_DA_CTRL_0 0x0
+#define AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER GENMASK(15, 12)
+#define AIROHA_USB_PMA_RXDET_EN_WINDOW GENMASK(9, 4)
+#define AIROHA_USB_PMA_TX_DA_CTRL_1 0x4
+#define AIROHA_USB_PMA_FORCE_TX_BIT_INVERSE BIT(7)
+#define AIROHA_USB_PMA_TX_DA_CTRL_2 0x8
+#define AIROHA_USB_PMA_FORCE_TX_DEM_SEL BIT(27)
+#define AIROHA_USB_PMA_TX_DA_CTRL_3 0xc
+#define AIROHA_USB_PMA_TX_DATA_RATE_SEL GENMASK(30, 28)
+#define AIROHA_USB_PMA_PON_RXFEDIG_CTRL_0 0x100
+#define AIROHA_USB_PMA_EQ_RX500M_CK_SEL BIT(12)
+#define AIROHA_USB_PMA_PON_RXFEDIG_CTRL_8 0x120
+#define AIROHA_USB_PMA_QP_EQ_EYE_MASK GENMASK(9, 0)
+#define AIROHA_USB_PMA_PON_RXFEDIG_CTRL_10 0x128
+#define AIROHA_USB_PMA_QP_EQ_PIEYE_INI GENMASK(22, 16)
+#define AIROHA_USB_PMA_SS_LCPLL_PWCTL_SETTING_2 0x208
+#define AIROHA_USB_PMA_NCPO_ANA_MSB GENMASK(17, 16)
+#define AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2 0x230
+#define AIROHA_USB_PMA_LCPLL_NCPO_VALUE GENMASK(30, 0)
+#define AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_5 0x23c
+#define AIROHA_USB_PMA_LCPLL_NCPO_CHG BIT(24)
+#define AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1 0x248
+#define AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON GENMASK(30, 0)
+#define AIROHA_USB_PMA_INTF_CTRL_5 0x314
+#define AIROHA_USB_PMA_RX_HZ_SEL BIT(5)
+#define AIROHA_USB_PMA_RX_HZ_FORCE BIT(4)
+#define AIROHA_USB_PMA_INTF_CTRL_6 0x318
+#define AIROHA_USB_PMA_TX_DATA_EN_SEL BIT(13)
+#define AIROHA_USB_PMA_TX_DATA_EN_FORCE BIT(12)
+#define AIROHA_USB_PMA_INTF_CTRL_7 0x31c
+#define AIROHA_USB_PMA_PLL_EN_SEL BIT(5)
+#define AIROHA_USB_PMA_PLL_EN_FORCE BIT(4)
+#define AIROHA_USB_PMA_INTF_CTRL_8 0x320
+#define AIROHA_USB_PMA_XTAL_EXT_EN_SEL BIT(13)
+#define AIROHA_USB_PMA_XTAL_EXT_EN_FORCE GENMASK(12, 11)
+#define AIROHA_USB_PMA_TX_TERM_SEL_SEL BIT(7)
+#define AIROHA_USB_PMA_TX_TERM_SEL_FORCE GENMASK(6, 5)
+#define AIROHA_USB_PMA_INTF_STS_9 0x364
+#define AIROHA_USB_PMA_RX_IMP_SEL_SEL BIT(31)
+#define AIROHA_USB_PMA_RX_IMP_SEL_FORCE GENMASK(30, 26)
+#define AIROHA_USB_PMA_ADDR_INTF_STS_PLL_VCOCAL GENMASK(23, 16)
+#define AIROHA_USB_PMA_PLL_CTRL_0 0x400
+#define AIROHA_USB_PMA_AUTO_INIT BIT(0)
+#define AIROHA_USB_PMA_PLL_CTRL_1 0x404
+#define AIROHA_USB_PMA_PLL_SSC_EN BIT(30)
+#define AIROHA_USB_PMA_PLL_CTRL_2 0x408
+#define AIROHA_USB_PMA_PLL_SDM_IFM_INTF BIT(30)
+#define AIROHA_USB_PMA_PLL_RICO_SEL_INTF BIT(29)
+#define AIROHA_USB_PMA_PLL_PHY_CK_EN_INTF BIT(27)
+#define AIROHA_USB_PMA_PLL_PCK_SEL_INTF BIT(22)
+#define AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF GENMASK(21, 20)
+#define AIROHA_USB_PMA_PLL_IR_INTF GENMASK(19, 16)
+#define AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF BIT(14)
+#define AIROHA_USB_PMA_PLL_FBKSEL_INTF GENMASK(13, 12)
+#define AIROHA_USB_PMA_PLL_BR_INTF GENMASK(10, 8)
+#define AIROHA_USB_PMA_PLL_BPB_INTF GENMASK(7, 6)
+#define AIROHA_USB_PMA_PLL_BPA_INTF GENMASK(4, 2)
+#define AIROHA_USB_PMA_PLL_BC_INTF GENMASK(1, 0)
+#define AIROHA_USB_PMA_PLL_CTRL_3 0x40c
+#define AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF GENMASK(31, 16)
+#define AIROHA_USB_PMA_PLL_SSC_DELTA_INTF GENMASK(15, 0)
+#define AIROHA_USB_PMA_PLL_CTRL_4 0x410
+#define AIROHA_USB_PMA_PLL_SDM_HREN_INTF GENMASK(4, 3)
+#define AIROHA_USB_PMA_PLL_ICOLP_EN_INTF BIT(2)
+#define AIROHA_USB_PMA_PLL_CK_CTRL_0 0x414
+#define AIROHA_USB_PMA_PCIE_CLKTX_EN_INTF BIT(5)
+#define AIROHA_USB_PMA_PCIE_CLKRX_EN_INTF BIT(4)
+#define AIROHA_USB_PMA_PLL_CK_CTRL_1 0x418
+#define AIROHA_USB_PMA_PLL_FORCE_UNSTABLE BIT(19)
+#define AIROHA_USB_PMA_PLL_FORCE_STABLE BIT(18)
+#define AIROHA_USB_PMA_PLL_CK_CTRL_2 0x41c
+#define AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_OFF_EN BIT(2)
+#define AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_ON_EN BIT(1)
+#define AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_EN BIT(0)
+#define AIROHA_USB_PMA_RX_SYS_CTRL_0 0x600
+#define AIROHA_USB_PMA_ROC_CK_EN BIT(1)
+#define AIROHA_USB_PMA_RX_DLY_0 0x614
+#define AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY GENMASK(7, 0)
+#define AIROHA_USB_PMA_RX_CTRL_2 0x630
+#define AIROHA_USB_PMA_RX_EQ_EN_H_DLY GENMASK(28, 16)
+#define AIROHA_USB_PMA_RX_CTRL_5 0x63c
+#define AIROHA_USB_PMA_FREDET_CHK_CYCLE GENMASK(29, 10)
+#define AIROHA_USB_PMA_RX_CTRL_6 0x640
+#define AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE GENMASK(19, 0)
+#define AIROHA_USB_PMA_RX_CTRL_7 0x644
+#define AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE GENMASK(19, 0)
+#define AIROHA_USB_PMA_RX_CTRL_10 0x650
+#define AIROHA_USB_PMA_CRSDET_RSTB BIT(1)
+#define AIROHA_USB_PMA_RX_CTRL_11 0x654
+#define AIROHA_USB_PMA_FORCE_SIGDET_5G BIT(19)
+#define AIROHA_USB_PMA_RX_CTRL_26 0x690
+#define AIROHA_USB_PMA_QP_EQ_RETRAIN_ONLY_EN BIT(26)
+#define AIROHA_USB_PMA_LINK_ERRO_EN BIT(23)
+#define AIROHA_USB_PMA_RX_CTRL_27 0x694
+#define AIROHA_USB_PMA_QP_LINK_ERRO_CNT GENMASK(31, 0)
+#define AIROHA_USB_PMA_RX_CTRL_36 0x6b8
+#define AIROHA_USB_PMA_PCIE_USB_SYSTEM BIT(26)
+#define AIROHA_USB_PMA_LCK2DATA_DLY_TIME GENMASK(23, 16)
+#define AIROHA_USB_PMA_RX_CTRL_38 0x6C0
+#define AIROHA_USB_PMA_RESERVE_3 GENMASK(31, 24)
+#define AIROHA_USB_PMA_RX_CTRL_45 0x6dc
+#define AIROHA_USB_PMA_EQ_EN_DLY GENMASK(12, 0)
+#define AIROHA_USB_PMA_RX_CTRL_46 0x6e0
+#define AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P3_TO_P0_EN BIT(29)
+#define AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P2_TO_P0_EN BIT(28)
+#define AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P1_TO_P0_EN BIT(27)
+#define AIROHA_USB_PMA_REBACK_P0_LCK2REF_EN BIT(26)
+#define AIROHA_USB_PMA_RX_CTRL_49 0x6ec
+#define AIROHA_USB_PMA_LFPS_FINISH_TIME GENMASK(31, 21)
+#define AIROHA_USB_PMA_RX_CTRL_50 0x6f0
+#define AIROHA_USB_PMA_P3_TO_P0_DO_EQ_USB BIT(28)
+#define AIROHA_USB_PMA_P2_TO_P0_DO_EQ_USB BIT(27)
+#define AIROHA_USB_PMA_P1_TO_P0_DO_EQ_USB BIT(26)
+#define AIROHA_USB_PMA_EQ_EN_DLY_SHORT GENMASK(25, 13)
+#define AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT GENMASK(12, 0)
+
+/* DIG */
+#define AIROHA_USB_DIG_CK_RST_CTRL_3 0x30c
+#define AIROHA_USB_DIG_NS_CK_DIV_SEL BIT(25)
+#define AIROHA_USB_DIG_US_CK_DIV_SEL BIT(24)
+#define AIROHA_USB_DIG_MODE_CTRL_0 0x324
+#define AIROHA_USB_DIG_SGMII_AN_EN BIT(0)
+#define AIROHA_USB_DIG_MODE_CTRL_1 0x330
+#define AIROHA_USB_DIG_TPHY_SPEED GENMASK(3, 2)
+#define AIROHA_USB_DIG_CK_RST_CTRL_7 0x340
+#define AIROHA_USB_DIG_MULTI_USB2P5_EN BIT(26)
+#define AIROHA_USB_DIG_MULTI_USB5_EN BIT(25)
+#define AIROHA_USB_DIG_MULTI_PHY_USB_EN BIT(24)
+
+#define AIROHA_USB_PHY_U2_FM_DET_CYCLE_CNT 1024
+#define AIROHA_USB_PHY_REF_CK 20
+#define AIROHA_USB_PHY_U2_SR_COEF 28
+#define AIROHA_USB_PHY_U2_SR_COEF_DIVISOR 1000
+
+#define AIROHA_USB_PHY_FREQDET_SLEEP 1000 /* 1ms */
+#define AIROHA_USB_PHY_FREQDET_TIMEOUT (AIROHA_USB_PHY_FREQDET_SLEEP * 10)
+
+#define AIROHA_USB_PHY_U3_MAX_CALIB_TRY 50
+#define AIROHA_USB_PHY_MAX_INSTANCE 3
+#define AIROHA_PCIE_PHY_MAX_INSTANCE 1
+
+struct an7583_usb_phy_instance {
+ struct device_node *node;
+ u32 type;
+
+ u32 offset;
+ unsigned int monclk_sel;
+ struct phy *serdes_phy;
+};
+
+enum an7583_usb_phy_regs {
+ AIROHA_USB_PHY_PHY,
+ AIROHA_USB_PHY_ANA,
+ AIROHA_USB_PHY_PMA,
+ AIROHA_USB_PHY_DIG,
+
+ AIROHA_USB_PHY_REGS_MAX,
+};
+
+struct an7583_usb_phy_priv {
+ struct regmap *regs[AIROHA_USB_PHY_REGS_MAX];
+
+ struct phy *phys[AIROHA_USB_PHY_MAX_INSTANCE];
+};
+
+struct an7583_usb_phy_match_data {
+ int max_instance;
+ const char * const *regs_name;
+ int regs_num;
+ int (*parse_ports)(struct device *dev,
+ struct an7583_usb_phy_priv *priv,
+ int index, struct device_node *subnode);
+};
+
+static int an7583_usb_phy_u2_slew_rate_calibration(struct phy *phy)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev;
+ u32 offset, srctrl;
+ u32 fm_out = 0;
+
+ dev = phy->dev.parent;
+ priv = dev_get_drvdata(dev);
+ offset = instance->offset;
+
+ /* Enable HS TX SR calibration */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR5 + offset,
+ AIROHA_USB_PHY_USB20_HSTX_SRCAL_EN);
+
+ usleep_range(1000, 1500);
+
+ /* Enable Free run clock */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_FMMONR1 + offset,
+ AIROHA_USB_PHY_FRCK_EN);
+
+ /* Select Monitor Clock */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_FMCR0 + offset,
+ AIROHA_USB_PHY_MONCLK_SEL,
+ FIELD_PREP(AIROHA_USB_PHY_MONCLK_SEL,
+ instance->monclk_sel));
+
+ /* Set cyclecnt */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_FMCR0 + offset,
+ AIROHA_USB_PHY_CYCLECNT,
+ FIELD_PREP(AIROHA_USB_PHY_CYCLECNT,
+ AIROHA_USB_PHY_U2_FM_DET_CYCLE_CNT));
+
+ /* Enable Frequency meter */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_FMCR0 + offset,
+ AIROHA_USB_PHY_FREQDET_EN);
+
+ /* Timeout can happen and we will apply workaround at the end */
+ regmap_read_poll_timeout(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_FMMONR0 + offset,
+ fm_out, fm_out, AIROHA_USB_PHY_FREQDET_SLEEP,
+ AIROHA_USB_PHY_FREQDET_TIMEOUT);
+
+ /* Disable Frequency meter */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_FMCR0 + offset,
+ AIROHA_USB_PHY_FREQDET_EN);
+
+ /* Disable Free run clock */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_FMMONR1 + offset,
+ AIROHA_USB_PHY_FRCK_EN);
+
+ /* Disable HS TX SR calibration */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR5 + offset,
+ AIROHA_USB_PHY_USB20_HSTX_SRCAL_EN);
+
+ usleep_range(1000, 1500);
+
+ /* Frequency was not detected, use default SR calibration value */
+ if (!fm_out) {
+ srctrl = 0x5;
+ dev_err(dev, "Frequency not detected, using default SR calibration.\n");
+ /* (1024 / FM_OUT) * REF_CK * U2_SR_COEF (round to the nearest digits) */
+ } else {
+ srctrl = AIROHA_USB_PHY_REF_CK * AIROHA_USB_PHY_U2_SR_COEF;
+ srctrl = (srctrl * AIROHA_USB_PHY_U2_FM_DET_CYCLE_CNT) / fm_out;
+ srctrl = DIV_ROUND_CLOSEST(srctrl, AIROHA_USB_PHY_U2_SR_COEF_DIVISOR);
+ dev_dbg(dev, "SR calibration applied: %x\n", srctrl);
+ }
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR5 + offset,
+ AIROHA_USB_PHY_USB20_HSTX_SRCTRL,
+ FIELD_PREP(AIROHA_USB_PHY_USB20_HSTX_SRCTRL, srctrl));
+
+ return 0;
+}
+
+static bool an7583_usb_phy_u3_kband_is_calibrated(struct an7583_usb_phy_priv *priv)
+{
+ u32 val, res;
+
+ /* Default ICO setting */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CTRL_4,
+ AIROHA_USB_PMA_PLL_ICOLP_EN_INTF);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_SSUSB_BGR_EN,
+ AIROHA_USB_ANA_BIAS_V2V_CAL,
+ FIELD_PREP(AIROHA_USB_ANA_BIAS_V2V_CAL, 0x15));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL,
+ AIROHA_USB_ANA_PLL_OSCAL_ENB |
+ AIROHA_USB_ANA_PLL_LDOLPF_VSEL,
+ AIROHA_USB_ANA_PLL_OSCAL_ENB |
+ FIELD_PREP(AIROHA_USB_ANA_PLL_LDOLPF_VSEL, 0x1));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_RICO_SEL_INTF);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_CTRL_8,
+ AIROHA_USB_PMA_XTAL_EXT_EN_SEL |
+ AIROHA_USB_PMA_XTAL_EXT_EN_FORCE);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF);
+
+ /* Read KBand */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_TDC_FT_CK_EN,
+ AIROHA_USB_ANA_PLL_DEBUG_SEL);
+
+ usleep_range(5000, 6000);
+
+ regmap_read(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_STS_9, &val);
+ res = FIELD_GET(AIROHA_USB_PMA_ADDR_INTF_STS_PLL_VCOCAL, val) << 4;
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_TDC_FT_CK_EN,
+ AIROHA_USB_ANA_PLL_DEBUG_SEL);
+
+ usleep_range(5000, 6000);
+
+ regmap_read(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_STS_9, &val);
+ res |= FIELD_GET(AIROHA_USB_PMA_ADDR_INTF_STS_PLL_VCOCAL, val);
+
+ /*
+ * KBand is calibrated if KBand Code is NOT 0xfff and
+ * KBand Done is set.
+ */
+ return res != 0xfff && res & 0x800;
+}
+
+static int an7583_usb_phy_u2_init(struct phy *phy)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev;
+ u32 offset;
+
+ dev = phy->dev.parent;
+ priv = dev_get_drvdata(dev);
+ offset = instance->offset;
+
+ mdelay(1);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR4 + offset,
+ AIROHA_USB_PHY_USB20_FS_CR,
+ AIROHA_USB_PHY_USB20_FS_CR_MIN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR4 + offset,
+ AIROHA_USB_PHY_USB20_FS_SR,
+ AIROHA_USB_PHY_USB20_FS_SR_NORMAL);
+
+ /* FIXME: evaluate if needed */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR6 + offset,
+ AIROHA_USB_PHY_USB20_SQTH,
+ AIROHA_USB_PHY_USB20_SQTH_125);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR6 + offset,
+ AIROHA_USB_PHY_USB20_DISCTH,
+ AIROHA_USB_PHY_USB20_DISCTH_580);
+
+ /* Enable the USB port and then disable after calibration */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR6 + offset,
+ AIROHA_USB_PHY_USB20_BC11_SW_EN);
+
+ an7583_usb_phy_u2_slew_rate_calibration(phy);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR6 + offset,
+ AIROHA_USB_PHY_USB20_BC11_SW_EN);
+
+ usleep_range(1000, 1500);
+
+ return 0;
+}
+
+static int an7583_usb_phy_eth_init_sgmii(struct an7583_usb_phy_priv *priv)
+{
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_27,
+ AIROHA_USB_PMA_QP_LINK_ERRO_CNT,
+ FIELD_PREP(AIROHA_USB_PMA_QP_LINK_ERRO_CNT, 0x100000));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1,
+ AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON,
+ FIELD_PREP(AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON,
+ 0x48000000));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_DIG],
+ AIROHA_USB_DIG_MODE_CTRL_1,
+ AIROHA_USB_DIG_TPHY_SPEED,
+ FIELD_PREP(AIROHA_USB_DIG_TPHY_SPEED, 0x0));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_PCK_SEL_INTF |
+ AIROHA_USB_PMA_PLL_IR_INTF,
+ AIROHA_USB_PMA_PLL_PCK_SEL_INTF |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_IR_INTF, 0x4));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2,
+ AIROHA_USB_PMA_LCPLL_NCPO_VALUE,
+ FIELD_PREP(AIROHA_USB_PMA_LCPLL_NCPO_VALUE, 0x48000000));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_LPF_MJV_LIM,
+ AIROHA_USB_ANA_CDR_LPF_RATIO,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_RATIO, 0x2));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_CKREF_DIV1,
+ AIROHA_USB_ANA_CDR_PR_DAC_BAND,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_PR_DAC_BAND, 0xc));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_LPF_BOT_LIM,
+ AIROHA_USB_ANA_CDR_LPF_KP_GAIN |
+ AIROHA_USB_ANA_CDR_LPF_KI_GAIN,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_KP_GAIN, 0x6) |
+ FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_KI_GAIN, 0x6));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_5,
+ AIROHA_USB_PMA_FREDET_CHK_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_CHK_CYCLE, 0x28));
+
+ return 0;
+}
+
+static int an7583_usb_phy_eth_init_hsgmii(struct an7583_usb_phy_priv *priv)
+{
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1,
+ AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON,
+ FIELD_PREP(AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON,
+ 0x7a000000));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_DIG],
+ AIROHA_USB_DIG_MODE_CTRL_1,
+ AIROHA_USB_DIG_TPHY_SPEED,
+ FIELD_PREP(AIROHA_USB_DIG_TPHY_SPEED, 0x1));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_PCK_SEL_INTF |
+ AIROHA_USB_PMA_PLL_IR_INTF,
+ AIROHA_USB_PMA_PLL_PCK_SEL_INTF |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_IR_INTF, 0x6));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2,
+ AIROHA_USB_PMA_LCPLL_NCPO_VALUE,
+ FIELD_PREP(AIROHA_USB_PMA_LCPLL_NCPO_VALUE, 0x7a000000));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_LPF_MJV_LIM,
+ AIROHA_USB_ANA_CDR_LPF_RATIO,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_RATIO, 0x1));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_CKREF_DIV1,
+ AIROHA_USB_ANA_CDR_PR_DAC_BAND,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_PR_DAC_BAND, 0xf));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_LPF_BOT_LIM,
+ AIROHA_USB_ANA_CDR_LPF_KP_GAIN |
+ AIROHA_USB_ANA_CDR_LPF_KI_GAIN,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_KP_GAIN, 0x5) |
+ FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_KI_GAIN, 0x5));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_5,
+ AIROHA_USB_PMA_FREDET_CHK_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_CHK_CYCLE, 0x10));
+
+ return 0;
+}
+
+static int an7583_usb_phy_set_mode_eth(struct phy *phy, int submode)
+{
+ struct an7583_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ /* TODO handle efuse */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_8,
+ AIROHA_USB_PMA_TX_TERM_SEL_SEL |
+ AIROHA_USB_PMA_TX_TERM_SEL_FORCE,
+ AIROHA_USB_PMA_TX_TERM_SEL_SEL |
+ FIELD_PREP(AIROHA_USB_PMA_TX_TERM_SEL_FORCE, 0x1));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_STS_9,
+ AIROHA_USB_PMA_RX_IMP_SEL_SEL |
+ AIROHA_USB_PMA_RX_IMP_SEL_FORCE,
+ AIROHA_USB_PMA_RX_IMP_SEL_SEL |
+ FIELD_PREP(AIROHA_USB_PMA_RX_IMP_SEL_FORCE, 0x1));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_26,
+ AIROHA_USB_PMA_QP_EQ_RETRAIN_ONLY_EN |
+ AIROHA_USB_PMA_LINK_ERRO_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_SSUSB_BGR_EN,
+ AIROHA_USB_ANA_SSUSB_BG_DIV,
+ FIELD_PREP(AIROHA_USB_ANA_SSUSB_BG_DIV, 0x1));
+
+ /* Digital CLK trigger reverse */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PON_RXFEDIG_CTRL_0,
+ AIROHA_USB_PMA_EQ_RX500M_CK_SEL);
+
+ /* Common Setting */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_3,
+ AIROHA_USB_DIG_NS_CK_DIV_SEL |
+ AIROHA_USB_DIG_US_CK_DIV_SEL);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_1,
+ AIROHA_USB_PMA_FORCE_TX_BIT_INVERSE);
+
+ /* TODO check they report 0x8400000 */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_2,
+ AIROHA_USB_PMA_FORCE_TX_DEM_SEL);
+
+ /* PLL */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_BR_INTF |
+ AIROHA_USB_PMA_PLL_BPB_INTF |
+ AIROHA_USB_PMA_PLL_BPA_INTF |
+ AIROHA_USB_PMA_PLL_BC_INTF,
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BR_INTF, 0x3) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BPB_INTF, 0x0) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BPA_INTF, 0x5) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BC_INTF, 0x1));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL,
+ AIROHA_USB_ANA_PLL_PREDIV,
+ FIELD_PREP(AIROHA_USB_ANA_PLL_PREDIV, 0x1));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4,
+ AIROHA_USB_PMA_PLL_ICOLP_EN_INTF);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_MODE_CTRL_0,
+ AIROHA_USB_DIG_SGMII_AN_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXLBTX_EN,
+ AIROHA_USB_ANA_TX_DMEDGEGEN_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_QP_TX_MODE_16B_EN,
+ FIELD_PREP(AIROHA_USB_QP_TX_RESERVE,
+ AIROHA_USB_ANA_TX_RESERVE_8 |
+ AIROHA_USB_ANA_TX_VLMON_EN));
+
+ if (submode == PHY_INTERFACE_MODE_2500BASEX)
+ an7583_usb_phy_eth_init_hsgmii(priv);
+ else
+ an7583_usb_phy_eth_init_sgmii(priv);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_5,
+ AIROHA_USB_PMA_LCPLL_NCPO_CHG);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_5,
+ AIROHA_USB_PMA_LCPLL_NCPO_CHG);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_PWCTL_SETTING_2,
+ AIROHA_USB_PMA_NCPO_ANA_MSB,
+ FIELD_PREP(AIROHA_USB_PMA_NCPO_ANA_MSB, 0x1));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_RXAFE_RESERVE,
+ AIROHA_USB_ANA_CDR_PD_10B_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PON_RXFEDIG_CTRL_10,
+ AIROHA_USB_PMA_QP_EQ_PIEYE_INI,
+ FIELD_PREP(AIROHA_USB_PMA_QP_EQ_PIEYE_INI, 0x0));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PON_RXFEDIG_CTRL_8,
+ AIROHA_USB_PMA_QP_EQ_EYE_MASK,
+ FIELD_PREP(AIROHA_USB_PMA_QP_EQ_EYE_MASK, 0x2aa));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_6,
+ AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE, 0x64));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_7,
+ AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE, 0x2710));
+
+ /* PLL auto init */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0,
+ AIROHA_USB_PMA_AUTO_INIT);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0,
+ AIROHA_USB_PMA_AUTO_INIT);
+
+ usleep_range(100, 200);
+
+ return 0;
+}
+
+static void an7583_usb_phy_tx_pll_enable(struct an7583_usb_phy_priv *priv)
+{
+ /* PLL Reset to default */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL,
+ AIROHA_USB_ANA_PLL_MON_LDO_SEL |
+ AIROHA_USB_ANA_PLL_MONVC_EN);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_CTRL_7,
+ AIROHA_USB_PMA_PLL_EN_SEL |
+ AIROHA_USB_PMA_PLL_EN_FORCE);
+
+ /* PLL Auto Mode (For PMA) */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CK_CTRL_1,
+ AIROHA_USB_PMA_PLL_FORCE_UNSTABLE);
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CK_CTRL_1,
+ AIROHA_USB_PMA_PLL_FORCE_STABLE);
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CK_CTRL_1,
+ AIROHA_USB_PMA_PLL_FORCE_UNSTABLE);
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CK_CTRL_1,
+ AIROHA_USB_PMA_PLL_FORCE_STABLE);
+
+ /* TX Auto Mode */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_6,
+ AIROHA_USB_PMA_TX_DATA_EN_FORCE);
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_6,
+ AIROHA_USB_PMA_TX_DATA_EN_SEL);
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_6,
+ AIROHA_USB_PMA_TX_DATA_EN_FORCE);
+}
+
+static void an7583_usb_phy_kband_calibrate(struct an7583_usb_phy_priv *priv)
+{
+ /* PLL Disable */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_CTRL_8,
+ AIROHA_USB_PMA_XTAL_EXT_EN_SEL |
+ AIROHA_USB_PMA_XTAL_EXT_EN_FORCE,
+ AIROHA_USB_PMA_XTAL_EXT_EN_SEL |
+ FIELD_PREP(AIROHA_USB_PMA_XTAL_EXT_EN_FORCE, 0x3));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_CTRL_7,
+ AIROHA_USB_PMA_PLL_EN_SEL |
+ AIROHA_USB_PMA_PLL_EN_FORCE,
+ AIROHA_USB_PMA_PLL_EN_SEL);
+
+ /* PLL Config for CPR */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CTRL_4,
+ AIROHA_USB_PMA_PLL_ICOLP_EN_INTF);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_SSUSB_BGR_EN,
+ AIROHA_USB_ANA_BIAS_V2V_CAL,
+ FIELD_PREP(AIROHA_USB_ANA_BIAS_V2V_CAL, 0x0));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL,
+ AIROHA_USB_ANA_PLL_OSCAL_ENB |
+ AIROHA_USB_ANA_PLL_LDOLPF_VSEL,
+ FIELD_PREP(AIROHA_USB_ANA_PLL_LDOLPF_VSEL, 0x3));
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_RICO_SEL_INTF |
+ AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL,
+ AIROHA_USB_ANA_PLL_MON_LDO_SEL |
+ AIROHA_USB_ANA_PLL_MONVC_EN,
+ FIELD_PREP(AIROHA_USB_ANA_PLL_MON_LDO_SEL, 0x3) |
+ AIROHA_USB_ANA_PLL_MONVC_EN);
+
+ /* PLL Enable */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_CTRL_7,
+ AIROHA_USB_PMA_PLL_EN_SEL |
+ AIROHA_USB_PMA_PLL_EN_FORCE);
+}
+
+static int an7583_usb_phy_u3_init(struct phy *phy)
+{
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev;
+
+ dev = phy->dev.parent;
+ priv = dev_get_drvdata(dev);
+
+ /* Digital CLK trigger reverse */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PON_RXFEDIG_CTRL_0,
+ AIROHA_USB_PMA_EQ_RX500M_CK_SEL);
+
+ /* RX USB PCIE enable */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_36,
+ AIROHA_USB_PMA_PCIE_USB_SYSTEM);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_SYS_CTRL_0,
+ AIROHA_USB_PMA_ROC_CK_EN);
+
+ /* 50MHz XTAL */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_SSUSB_BGR_EN,
+ AIROHA_USB_ANA_SSUSB_BG_DIV |
+ AIROHA_USB_ANA_SSUSB_CHPEN,
+ FIELD_PREP(AIROHA_USB_ANA_SSUSB_BG_DIV, 0x1) |
+ AIROHA_USB_ANA_SSUSB_CHPEN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL,
+ AIROHA_USB_ANA_PLL_PREDIV,
+ FIELD_PREP(AIROHA_USB_ANA_PLL_PREDIV, 0x1));
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4,
+ AIROHA_USB_PMA_PLL_ICOLP_EN_INTF);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_7,
+ AIROHA_USB_DIG_MULTI_USB2P5_EN |
+ AIROHA_USB_DIG_MULTI_USB5_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_7,
+ AIROHA_USB_DIG_MULTI_USB2P5_EN |
+ AIROHA_USB_DIG_MULTI_USB5_EN |
+ AIROHA_USB_DIG_MULTI_PHY_USB_EN);
+
+ /* PLL */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_PHY_CK_EN_INTF |
+ AIROHA_USB_PMA_PLL_PCK_SEL_INTF |
+ AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF |
+ AIROHA_USB_PMA_PLL_IR_INTF |
+ AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF |
+ AIROHA_USB_PMA_PLL_FBKSEL_INTF |
+ AIROHA_USB_PMA_PLL_BPB_INTF |
+ AIROHA_USB_PMA_PLL_BPA_INTF |
+ AIROHA_USB_PMA_PLL_BC_INTF,
+ AIROHA_USB_PMA_PLL_PHY_CK_EN_INTF |
+ AIROHA_USB_PMA_PLL_PCK_SEL_INTF |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF, 0x0) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_IR_INTF, 0x4) |
+ AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_FBKSEL_INTF, 0x0) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BPB_INTF, 0x1) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BPA_INTF, 0x5) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BC_INTF, 0x3));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4,
+ AIROHA_USB_PMA_PLL_SDM_HREN_INTF,
+ FIELD_PREP(AIROHA_USB_PMA_PLL_SDM_HREN_INTF, 0x1));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_SDM_IFM_INTF);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_3,
+ AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF |
+ AIROHA_USB_PMA_PLL_SSC_DELTA_INTF,
+ FIELD_PREP(AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF, 0x18c) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_SSC_DELTA_INTF, 0x21e));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_1,
+ AIROHA_USB_PMA_PLL_SSC_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1,
+ AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON,
+ FIELD_PREP(AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON,
+ 0x48000000));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_PWCTL_SETTING_2,
+ AIROHA_USB_PMA_NCPO_ANA_MSB,
+ FIELD_PREP(AIROHA_USB_PMA_NCPO_ANA_MSB, 0x1));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2,
+ AIROHA_USB_PMA_LCPLL_NCPO_VALUE,
+ FIELD_PREP(AIROHA_USB_PMA_LCPLL_NCPO_VALUE, 0x48000000));
+
+ /* RX 5G */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_LPF_MJV_LIM,
+ AIROHA_USB_ANA_CDR_LPF_RATIO,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_RATIO, 0x0));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_RXAFE_RESERVE,
+ AIROHA_USB_ANA_CDR_PD_10B_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_CKREF_DIV1,
+ AIROHA_USB_ANA_CDR_PR_DAC_BAND,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_PR_DAC_BAND, 0xc));
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_FORCE_IBANDLPF_R_OFF,
+ AIROHA_USB_ANA_CDR_PHYCK_RSTB);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG,
+ AIROHA_USB_ANA_CDR_PR_XFICK_EN |
+ AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE,
+ AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_CKREF_DIV1,
+ AIROHA_USB_ANA_CDR_PR_KBAND_DIV,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_PR_KBAND_DIV, 0x3));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG,
+ AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE, 0x19));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_46,
+ AIROHA_USB_PMA_REBACK_P0_LCK2REF_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_49,
+ AIROHA_USB_PMA_LFPS_FINISH_TIME,
+ FIELD_PREP(AIROHA_USB_PMA_LFPS_FINISH_TIME, 0x1f0));
+
+ /* EQ all */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_50,
+ AIROHA_USB_PMA_P3_TO_P0_DO_EQ_USB |
+ AIROHA_USB_PMA_P2_TO_P0_DO_EQ_USB |
+ AIROHA_USB_PMA_P1_TO_P0_DO_EQ_USB);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_46,
+ AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P3_TO_P0_EN |
+ AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P2_TO_P0_EN |
+ AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P1_TO_P0_EN);
+
+ /* FIXME: ask Airoha why reserve7 is at 6c4 NOT 6c0 */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_38,
+ FIELD_PREP(AIROHA_USB_PMA_RESERVE_3, BIT(7)));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_11,
+ AIROHA_USB_PMA_FORCE_SIGDET_5G);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_36,
+ AIROHA_USB_PMA_LCK2DATA_DLY_TIME,
+ FIELD_PREP(AIROHA_USB_PMA_LCK2DATA_DLY_TIME, 0x2));
+
+ /* PI Cal */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_DLY_0,
+ AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY,
+ FIELD_PREP(AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY, 0x10));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_PLL_SDM_ORD,
+ AIROHA_USB_ANA_PLL_SSC_TRI_EN |
+ AIROHA_USB_ANA_PLL_SSC_PHASE_INI);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_3,
+ AIROHA_USB_PMA_TX_DATA_RATE_SEL);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXAFE_RESERVE,
+ AIROHA_USB_ANA_CDR_PD_EDGE_DIS);
+
+ /* Common Setting */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_3,
+ AIROHA_USB_DIG_NS_CK_DIV_SEL |
+ AIROHA_USB_DIG_US_CK_DIV_SEL);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_0,
+ AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER |
+ AIROHA_USB_PMA_RXDET_EN_WINDOW,
+ FIELD_PREP(AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER, 0x4) |
+ FIELD_PREP(AIROHA_USB_PMA_RXDET_EN_WINDOW, 0xa));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXLBTX_EN,
+ AIROHA_USB_ANA_TX_DMEDGEGEN_EN |
+ AIROHA_USB_ANA_TX_RXDET_METHOD,
+ AIROHA_USB_ANA_TX_DMEDGEGEN_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CK_CTRL_2,
+ AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_OFF_EN |
+ AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_ON_EN |
+ AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_EN);
+
+ /* RX Speed Up */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_5,
+ AIROHA_USB_PMA_FREDET_CHK_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_CHK_CYCLE, 0x28));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_6,
+ AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE, 0x64));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_7,
+ AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE, 0x2710));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_2,
+ AIROHA_USB_PMA_RX_EQ_EN_H_DLY,
+ FIELD_PREP(AIROHA_USB_PMA_RX_EQ_EN_H_DLY, 0x9c4));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_45,
+ AIROHA_USB_PMA_EQ_EN_DLY,
+ FIELD_PREP(AIROHA_USB_PMA_EQ_EN_DLY, 0x9c4));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_50,
+ AIROHA_USB_PMA_EQ_EN_DLY_SHORT |
+ AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT,
+ FIELD_PREP(AIROHA_USB_PMA_EQ_EN_DLY_SHORT, 0x9c4) |
+ FIELD_PREP(AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT, 0x9c4));
+
+ /* TCL avoid LT noice impact */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_QP_TX_MODE_16B_EN,
+ AIROHA_USB_ANA_TX_RESERVE_8);
+
+ /* PLL auto init */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0,
+ AIROHA_USB_PMA_AUTO_INIT);
+
+ usleep_range(100, 300);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CK_CTRL_2,
+ AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_EN);
+
+ if (!an7583_usb_phy_u3_kband_is_calibrated(priv)) {
+ int i;
+
+ /* TX Force Disable */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_CTRL_6,
+ AIROHA_USB_PMA_TX_DATA_EN_SEL |
+ AIROHA_USB_PMA_TX_DATA_EN_FORCE,
+ AIROHA_USB_PMA_TX_DATA_EN_SEL);
+
+ /* PLL Force Unstable */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CK_CTRL_1,
+ AIROHA_USB_PMA_PLL_FORCE_UNSTABLE);
+
+ for (i = 0; i < AIROHA_USB_PHY_U3_MAX_CALIB_TRY; i++) {
+ an7583_usb_phy_kband_calibrate(priv);
+
+ /* Exit as soon as we manage to calibrate */
+ if (an7583_usb_phy_u3_kband_is_calibrated(priv))
+ break;
+ }
+ }
+
+ an7583_usb_phy_tx_pll_enable(priv);
+
+ return !an7583_usb_phy_u3_kband_is_calibrated(priv) ? -EINVAL : 0;
+}
+
+static int an7583_usb_phy_pcie_init(struct phy *phy)
+{
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev;
+ int i;
+
+ dev = phy->dev.parent;
+ priv = dev_get_drvdata(dev);
+
+ /* TX Force Disable */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_CTRL_6,
+ AIROHA_USB_PMA_TX_DATA_EN_SEL |
+ AIROHA_USB_PMA_TX_DATA_EN_FORCE,
+ AIROHA_USB_PMA_TX_DATA_EN_SEL);
+
+ /* PLL Force Unstable */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_PLL_CK_CTRL_1,
+ AIROHA_USB_PMA_PLL_FORCE_UNSTABLE);
+
+ /* PLL Disable */
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0,
+ AIROHA_USB_PMA_AUTO_INIT);
+
+ usleep_range(1000, 1500);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0,
+ AIROHA_USB_PMA_AUTO_INIT);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_CTRL_7,
+ AIROHA_USB_PMA_PLL_EN_SEL |
+ AIROHA_USB_PMA_PLL_EN_FORCE,
+ AIROHA_USB_PMA_PLL_EN_SEL);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_36,
+ AIROHA_USB_PMA_PCIE_USB_SYSTEM);
+
+ /* 50MHz XTAL */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_SSUSB_BGR_EN,
+ AIROHA_USB_ANA_SSUSB_BG_DIV,
+ FIELD_PREP(AIROHA_USB_ANA_SSUSB_BG_DIV, 0x1));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL,
+ AIROHA_USB_ANA_PLL_PREDIV,
+ FIELD_PREP(AIROHA_USB_ANA_PLL_PREDIV, 0x1));
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4,
+ AIROHA_USB_PMA_PLL_ICOLP_EN_INTF);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_7,
+ AIROHA_USB_DIG_MULTI_USB2P5_EN |
+ AIROHA_USB_DIG_MULTI_USB5_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_7,
+ AIROHA_USB_DIG_MULTI_USB2P5_EN |
+ AIROHA_USB_DIG_MULTI_USB5_EN |
+ AIROHA_USB_DIG_MULTI_PHY_USB_EN);
+
+ /* PLL RG */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_PHY_CK_EN_INTF |
+ AIROHA_USB_PMA_PLL_PCK_SEL_INTF |
+ AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF |
+ AIROHA_USB_PMA_PLL_IR_INTF |
+ AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF |
+ AIROHA_USB_PMA_PLL_FBKSEL_INTF |
+ AIROHA_USB_PMA_PLL_BPB_INTF |
+ AIROHA_USB_PMA_PLL_BPA_INTF |
+ AIROHA_USB_PMA_PLL_BC_INTF,
+ AIROHA_USB_PMA_PLL_PCK_SEL_INTF |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF, 0x0) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_IR_INTF, 0x4) |
+ AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_FBKSEL_INTF, 0x0) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BPB_INTF, 0x1) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BPA_INTF, 0x5) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_BC_INTF, 0x3));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4,
+ AIROHA_USB_PMA_PLL_SDM_HREN_INTF,
+ FIELD_PREP(AIROHA_USB_PMA_PLL_SDM_HREN_INTF, 0x1));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2,
+ AIROHA_USB_PMA_PLL_SDM_IFM_INTF);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_3,
+ AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF |
+ AIROHA_USB_PMA_PLL_SSC_DELTA_INTF,
+ FIELD_PREP(AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF, 0x91c) |
+ FIELD_PREP(AIROHA_USB_PMA_PLL_SSC_DELTA_INTF, 0x1fd));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_1,
+ AIROHA_USB_PMA_PLL_SSC_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1,
+ AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON,
+ FIELD_PREP(AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON,
+ 0x48000000));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_PWCTL_SETTING_2,
+ AIROHA_USB_PMA_NCPO_ANA_MSB,
+ FIELD_PREP(AIROHA_USB_PMA_NCPO_ANA_MSB, 0x1));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2,
+ AIROHA_USB_PMA_LCPLL_NCPO_VALUE,
+ FIELD_PREP(AIROHA_USB_PMA_LCPLL_NCPO_VALUE, 0x48000000));
+
+ /* RX RG */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_LPF_MJV_LIM,
+ AIROHA_USB_ANA_CDR_LPF_RATIO,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_RATIO, 0x1));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_RXAFE_RESERVE,
+ AIROHA_USB_ANA_CDR_PD_10B_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_CKREF_DIV1,
+ AIROHA_USB_ANA_CDR_PR_DAC_BAND,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_PR_DAC_BAND, 0xc));
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_FORCE_IBANDLPF_R_OFF,
+ AIROHA_USB_ANA_CDR_PHYCK_RSTB);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG,
+ AIROHA_USB_ANA_CDR_PR_XFICK_EN |
+ AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE,
+ AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_CKREF_DIV1,
+ AIROHA_USB_ANA_CDR_PR_KBAND_DIV,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_PR_KBAND_DIV, 0x3));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA],
+ AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG,
+ AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE,
+ FIELD_PREP(AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE, 0x19));
+
+ /* Init L0/L0S U0/U1 */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_46,
+ AIROHA_USB_PMA_REBACK_P0_LCK2REF_EN |
+ AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P1_TO_P0_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_11,
+ AIROHA_USB_PMA_FORCE_SIGDET_5G);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_36,
+ AIROHA_USB_PMA_LCK2DATA_DLY_TIME,
+ FIELD_PREP(AIROHA_USB_PMA_LCK2DATA_DLY_TIME, 0x2));
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXAFE_RESERVE,
+ AIROHA_USB_ANA_CDR_PD_EDGE_DIS);
+
+ /* PI Calibration */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_DLY_0,
+ AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY,
+ FIELD_PREP(AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY, 0x10));
+
+ /* CRS detect and CLK TRX Control */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_10,
+ AIROHA_USB_PMA_CRSDET_RSTB);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_PLL_SDM_ORD,
+ AIROHA_USB_ANA_PLL_SSC_TRI_EN |
+ AIROHA_USB_ANA_PLL_SSC_PHASE_INI);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CK_CTRL_0,
+ AIROHA_USB_PMA_PCIE_CLKTX_EN_INTF |
+ AIROHA_USB_PMA_PCIE_CLKRX_EN_INTF,
+ AIROHA_USB_PMA_PCIE_CLKTX_EN_INTF);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_CLKDRV_IMPSEL,
+ AIROHA_USB_ANA_PCIE_CLKDRV_AMP |
+ AIROHA_USB_ANA_PCIE_CLKDRV_FORCEIN |
+ AIROHA_USB_ANA_PCIE_CLKDRV_HZ |
+ AIROHA_USB_ANA_PCIE_CLKDRV_RP |
+ AIROHA_USB_ANA_PCIE_CLKDRV_IMPSEL,
+ FIELD_PREP(AIROHA_USB_ANA_PCIE_CLKDRV_AMP, 0x4) |
+ FIELD_PREP(AIROHA_USB_ANA_PCIE_CLKDRV_FORCEIN, 0x1) |
+ FIELD_PREP(AIROHA_USB_ANA_PCIE_CLKDRV_RP, 0xc) |
+ FIELD_PREP(AIROHA_USB_ANA_PCIE_CLKDRV_IMPSEL, 0x12));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_3,
+ AIROHA_USB_PMA_TX_DATA_RATE_SEL,
+ FIELD_PREP(AIROHA_USB_PMA_TX_DATA_RATE_SEL, 0x1));
+
+ /* Common Setting */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_3,
+ AIROHA_USB_DIG_NS_CK_DIV_SEL |
+ AIROHA_USB_DIG_US_CK_DIV_SEL);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_0,
+ AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER |
+ AIROHA_USB_PMA_RXDET_EN_WINDOW,
+ FIELD_PREP(AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER, 0x4) |
+ FIELD_PREP(AIROHA_USB_PMA_RXDET_EN_WINDOW, 0xa));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXLBTX_EN,
+ AIROHA_USB_ANA_TX_DMEDGEGEN_EN |
+ AIROHA_USB_ANA_TX_RXDET_METHOD,
+ AIROHA_USB_ANA_TX_DMEDGEGEN_EN);
+
+ /* PLL auto ON/OFF at L2/U3 state */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CK_CTRL_2,
+ AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_OFF_EN |
+ AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_ON_EN |
+ AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_EN);
+
+ /* RX speed up */
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_5,
+ AIROHA_USB_PMA_FREDET_CHK_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_CHK_CYCLE, 0x28));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_6,
+ AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE, 0x64));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_7,
+ AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE,
+ FIELD_PREP(AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE, 0x2710));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_2,
+ AIROHA_USB_PMA_RX_EQ_EN_H_DLY,
+ FIELD_PREP(AIROHA_USB_PMA_RX_EQ_EN_H_DLY, 0x9c4));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_45,
+ AIROHA_USB_PMA_EQ_EN_DLY,
+ FIELD_PREP(AIROHA_USB_PMA_EQ_EN_DLY, 0x9c4));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_50,
+ AIROHA_USB_PMA_EQ_EN_DLY_SHORT |
+ AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT,
+ FIELD_PREP(AIROHA_USB_PMA_EQ_EN_DLY_SHORT, 0x9c4) |
+ FIELD_PREP(AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT, 0x9c4));
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_QP_TX_MODE_16B_EN,
+ AIROHA_USB_ANA_TX_RESERVE_8);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PON_RXFEDIG_CTRL_0,
+ AIROHA_USB_PMA_EQ_RX500M_CK_SEL);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0,
+ AIROHA_USB_PMA_AUTO_INIT);
+
+ /* Select PLL_EN to Force mode */
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA],
+ AIROHA_USB_PMA_INTF_CTRL_7,
+ AIROHA_USB_PMA_PLL_EN_SEL |
+ AIROHA_USB_PMA_PLL_EN_FORCE);
+
+ /* Try to calibrate KBand up to AIROHA_USB_PHY_U3_MAX_CALIB_TRY times */
+ for (i = 0; i < AIROHA_USB_PHY_U3_MAX_CALIB_TRY; i++) {
+ /* Check if KBand is calibrated */
+ if (an7583_usb_phy_u3_kband_is_calibrated(priv))
+ break;
+
+ /* Trigger KBand calibration */
+ an7583_usb_phy_kband_calibrate(priv);
+ }
+
+ an7583_usb_phy_tx_pll_enable(priv);
+
+ return !an7583_usb_phy_u3_kband_is_calibrated(priv) ? -EINVAL : 0;
+}
+
+static int an7583_usb_phy_init(struct phy *phy)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ return an7583_usb_phy_u2_init(phy);
+ case PHY_TYPE_USB3:
+ if (phy_get_mode(phy) == PHY_MODE_ETHERNET)
+ return 0;
+
+ return an7583_usb_phy_u3_init(phy);
+ case PHY_TYPE_PCIE:
+ if (phy_get_mode(phy) == PHY_MODE_ETHERNET)
+ return 0;
+
+ return an7583_usb_phy_pcie_init(phy);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int an7583_usb_phy_exit(struct phy *phy)
+{
+ return 0;
+}
+
+static int an7583_usb_phy_u2_power_on(struct phy *phy)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev;
+ u32 offset;
+
+ dev = phy->dev.parent;
+ priv = dev_get_drvdata(dev);
+ offset = instance->offset;
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR6 + offset,
+ AIROHA_USB_PHY_USB20_BC11_SW_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR2 + offset,
+ AIROHA_USB_PHY_SIFSLV_MAC_BANDGAP_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYACR3 + offset,
+ AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE,
+ AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_TOGGLE);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYDTM0 + offset,
+ AIROHA_USB_PHY_FORCE_XCVRSEL |
+ AIROHA_USB_PHY_XCVRSEL);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR6 + offset,
+ AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL,
+ AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_NO_ENPLL_FS_BIAS_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR5 + offset,
+ AIROHA_USB_PHY_USB20_DISC_FIT_EN);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYDTM0 + offset,
+ AIROHA_USB_PHY_FORCE_SUSPENDDM);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYACR3 + offset,
+ AIROHA_USB_PHY_USB20_USB11_TMODE_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYACR3 + offset,
+ AIROHA_USB_PHY_USB20_TMODE_FS_LS_TX_EN);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYDTM0 + offset,
+ AIROHA_USB_PHY_FORCE_TERMSEL |
+ AIROHA_USB_PHY_TERMSEL);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYACR3 + offset,
+ AIROHA_USB_PHY_USB20_PUPD_BIST_EN);
+
+ return 0;
+}
+
+static int an7583_usb_phy_u3_power_on(struct phy *phy)
+{
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev;
+
+ dev = phy->dev.parent;
+ priv = dev_get_drvdata(dev);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_TDC_FT_CK_EN,
+ AIROHA_USB_ANA_VUSB10_ON);
+
+ usleep_range(1000, 1500);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], AIROHA_USB_PHY_GPIO_CTLD,
+ AIROHA_USB_PHY_SSUSB_IP_SW_RST);
+
+ usleep_range(1000, 1500);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], AIROHA_USB_PHY_GPIO_CTLD,
+ AIROHA_USB_PHY_FORCE_SSUSB_IP_SW_RST);
+
+ usleep_range(1000, 1500);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_5,
+ AIROHA_USB_PMA_RX_HZ_FORCE);
+
+ usleep_range(1000, 1500);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_5,
+ AIROHA_USB_PMA_RX_HZ_SEL);
+
+ return 0;
+}
+
+static int an7583_usb_phy_power_on(struct phy *phy)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ return an7583_usb_phy_u2_power_on(phy);
+ case PHY_TYPE_USB3:
+ return an7583_usb_phy_u3_power_on(phy);
+ case PHY_TYPE_PCIE:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int an7583_usb_phy_u2_power_off(struct phy *phy)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev;
+ u32 offset;
+
+ dev = phy->dev.parent;
+ priv = dev_get_drvdata(dev);
+ offset = instance->offset;
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYACR3 + offset,
+ AIROHA_USB_PHY_USB20_PUPD_BIST_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYDTM0 + offset,
+ AIROHA_USB_PHY_FORCE_TERMSEL |
+ AIROHA_USB_PHY_TERMSEL);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYACR3 + offset,
+ AIROHA_USB_PHY_USB20_TMODE_FS_LS_TX_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYACR3 + offset,
+ AIROHA_USB_PHY_USB20_USB11_TMODE_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYDTM0 + offset,
+ AIROHA_USB_PHY_FORCE_SUSPENDDM);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR5 + offset,
+ AIROHA_USB_PHY_USB20_DISC_FIT_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR6 + offset,
+ AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL,
+ AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_USB20_HSRX_TMODE_EN);
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYDTM0 + offset,
+ AIROHA_USB_PHY_FORCE_XCVRSEL |
+ AIROHA_USB_PHY_XCVRSEL,
+ AIROHA_USB_PHY_FORCE_XCVRSEL |
+ FIELD_PREP(AIROHA_USB_PHY_XCVRSEL, 0x1));
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYACR3 + offset,
+ AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE,
+ AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_FORCE_DISABLE);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR2 + offset,
+ AIROHA_USB_PHY_SIFSLV_MAC_BANDGAP_EN);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_USBPHYACR6 + offset,
+ AIROHA_USB_PHY_USB20_BC11_SW_EN);
+
+ return 0;
+}
+
+static int an7583_usb_phy_u3_power_off(struct phy *phy)
+{
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev;
+
+ dev = phy->dev.parent;
+ priv = dev_get_drvdata(dev);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], AIROHA_USB_PHY_GPIO_CTLD,
+ AIROHA_USB_PHY_FORCE_SSUSB_IP_SW_RST);
+
+ usleep_range(1000, 1500);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], AIROHA_USB_PHY_GPIO_CTLD,
+ AIROHA_USB_PHY_SSUSB_IP_SW_RST);
+
+ usleep_range(1000, 1500);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_5,
+ AIROHA_USB_PMA_RX_HZ_FORCE);
+
+ usleep_range(1000, 1500);
+
+ regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_5,
+ AIROHA_USB_PMA_RX_HZ_SEL);
+
+ usleep_range(1000, 1500);
+
+ regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_TDC_FT_CK_EN,
+ AIROHA_USB_ANA_VUSB10_ON);
+
+ return 0;
+}
+
+static int an7583_usb_phy_power_off(struct phy *phy)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ return an7583_usb_phy_u2_power_off(phy);
+ case PHY_TYPE_USB3:
+ return an7583_usb_phy_u3_power_off(phy);
+ case PHY_TYPE_PCIE:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int an7583_usb_phy_u2_set_mode(struct phy *phy, enum phy_mode mode)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev;
+ u32 val = 0;
+ u32 offset;
+
+ dev = phy->dev.parent;
+ priv = dev_get_drvdata(dev);
+ offset = instance->offset;
+
+ /*
+ * For Device and Host mode, enable force IDDIG.
+ * For Device set IDDIG, for Host clear IDDIG.
+ * For OTG disable force and clear IDDIG bit while at it.
+ */
+ switch (mode) {
+ case PHY_MODE_USB_DEVICE:
+ val |= AIROHA_USB_PHY_IDDIG;
+ fallthrough;
+ case PHY_MODE_USB_HOST:
+ val |= AIROHA_USB_PHY_FORCE_IDDIG;
+ break;
+ case PHY_MODE_USB_OTG:
+ break;
+ default:
+ return 0;
+ }
+
+ regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY],
+ AIROHA_USB_PHY_U2PHYDTM1 + offset,
+ AIROHA_USB_PHY_FORCE_IDDIG |
+ AIROHA_USB_PHY_IDDIG, val);
+
+ return 0;
+}
+
+static int an7583_usb_phy_u3_set_mode(struct phy *phy, enum phy_mode mode,
+ int submode)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+ int ret;
+
+ switch (mode) {
+ case PHY_MODE_ETHERNET:
+ if (submode != PHY_INTERFACE_MODE_SGMII &&
+ submode != PHY_INTERFACE_MODE_1000BASEX &&
+ submode != PHY_INTERFACE_MODE_2500BASEX)
+ return -EOPNOTSUPP;
+
+ break;
+ case PHY_MODE_USB_DEVICE_SS:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ret = phy_set_mode_ext(instance->serdes_phy, mode, submode);
+ if (ret)
+ return ret;
+
+ if (mode == PHY_MODE_ETHERNET)
+ an7583_usb_phy_set_mode_eth(phy, submode);
+
+ return 0;
+}
+
+static int an7583_usb_phy_pcie_set_mode(struct phy *phy, enum phy_mode mode,
+ int submode)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+ int ret;
+
+ switch (mode) {
+ case PHY_MODE_ETHERNET:
+ if (submode != PHY_INTERFACE_MODE_SGMII &&
+ submode != PHY_INTERFACE_MODE_1000BASEX &&
+ submode != PHY_INTERFACE_MODE_2500BASEX)
+ return -EOPNOTSUPP;
+
+ break;
+ case PHY_MODE_PCIE:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ret = phy_set_mode_ext(instance->serdes_phy, mode, submode);
+ if (ret)
+ return ret;
+
+ if (mode == PHY_MODE_ETHERNET)
+ an7583_usb_phy_set_mode_eth(phy, submode);
+
+ return 0;
+}
+
+static int an7583_usb_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ return an7583_usb_phy_u2_set_mode(phy, mode);
+ case PHY_TYPE_USB3:
+ return an7583_usb_phy_u3_set_mode(phy, mode, submode);
+ case PHY_TYPE_PCIE:
+ return an7583_usb_phy_pcie_set_mode(phy, mode, submode);
+ default:
+ return 0;
+ }
+}
+
+static struct phy *an7583_usb_phy_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct an7583_usb_phy_priv *priv = dev_get_drvdata(dev);
+ const struct an7583_usb_phy_match_data *data;
+ struct device_node *phy_np = args->np;
+ struct phy *phy = NULL;
+ int type, index;
+
+ data = of_device_get_match_data(dev);
+
+ if (args->args_count != 1) {
+ dev_err(dev, "invalid number of cells in 'phy' property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ for (index = 0; index < data->max_instance; index++) {
+ if (!priv->phys[index])
+ continue;
+
+ if (phy_np == priv->phys[index]->dev.of_node) {
+ phy = priv->phys[index];
+ break;
+ }
+ }
+
+ if (!phy) {
+ dev_err(dev, "failed to find appropriate phy\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ type = args->args[0];
+ if (!(type == PHY_TYPE_USB2 || type == PHY_TYPE_USB3 ||
+ type == PHY_TYPE_PCIE)) {
+ dev_err(dev, "unsupported device type: %d\n", type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return phy;
+}
+
+static const struct phy_ops airoha_phy = {
+ .init = an7583_usb_phy_init,
+ .exit = an7583_usb_phy_exit,
+ .power_on = an7583_usb_phy_power_on,
+ .power_off = an7583_usb_phy_power_off,
+ .set_mode = an7583_usb_phy_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static const char * const an7583_usb_phy_regs_name[AIROHA_USB_PHY_REGS_MAX] = {
+ [AIROHA_USB_PHY_PHY] = "phy",
+ [AIROHA_USB_PHY_ANA] = "ana",
+ [AIROHA_USB_PHY_PMA] = "pma",
+ [AIROHA_USB_PHY_DIG] = "dig",
+};
+
+static const char * const airoha_pcie_phy_regs_name[AIROHA_USB_PHY_REGS_MAX] = {
+ [AIROHA_USB_PHY_ANA] = "ana",
+ [AIROHA_USB_PHY_PMA] = "pma",
+ [AIROHA_USB_PHY_DIG] = "dig",
+};
+
+static int an7583_usb_phy_parse_ports(struct device *dev,
+ struct an7583_usb_phy_priv *priv,
+ int index, struct device_node *subnode)
+{
+ const struct an7583_usb_phy_match_data *data;
+ struct an7583_usb_phy_instance *instance;
+ struct phy *phy;
+ int ret;
+
+ data = of_device_get_match_data(dev);
+
+ if (index >= data->max_instance)
+ return -EINVAL;
+
+ if (!of_device_is_available(subnode))
+ return 0;
+
+ instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
+ if (!instance)
+ return -ENOMEM;
+
+ instance->serdes_phy = devm_of_phy_optional_get(dev, subnode, NULL);
+ if (IS_ERR(instance->serdes_phy))
+ return dev_err_probe(dev, PTR_ERR(instance->serdes_phy), "error on serdes phy for USB 3.0\n");
+
+ if (!instance->serdes_phy &&
+ !of_property_present(subnode, "airoha,usb2-monitor-clk-sel"))
+ return dev_err_probe(dev, -EINVAL, "monitor clock selection or serdes PHY is mandatory for USB PHY\n");
+
+ if (instance->serdes_phy) {
+ instance->type = PHY_TYPE_USB3;
+ } else {
+ ret = of_property_read_u32(subnode, "airoha,usb2-monitor-clk-sel",
+ &instance->monclk_sel);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to parse Monitor clock selection\n");
+
+ ret = of_property_read_u32(subnode, "reg",
+ &instance->offset);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing reg for U2 PHY\n");
+
+ instance->type = PHY_TYPE_USB2;
+ }
+
+ phy = devm_phy_create(dev, subnode, &airoha_phy);
+ if (IS_ERR(phy))
+ return dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n");
+
+ priv->phys[index] = phy;
+ phy_set_drvdata(phy, instance);
+
+ return 0;
+}
+
+static int airoha_pcie_phy_parse_ports(struct device *dev,
+ struct an7583_usb_phy_priv *priv,
+ int index, struct device_node *subnode)
+{
+ const struct an7583_usb_phy_match_data *data;
+ struct an7583_usb_phy_instance *instance;
+ struct phy *phy;
+
+ data = of_device_get_match_data(dev);
+
+ if (index >= data->max_instance)
+ return -EINVAL;
+
+ if (!of_device_is_available(subnode))
+ return 0;
+
+ instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
+ if (!instance)
+ return -ENOMEM;
+
+ instance->serdes_phy = devm_phy_get(dev, NULL);
+ if (IS_ERR(instance->serdes_phy))
+ return dev_err_probe(dev, PTR_ERR(instance->serdes_phy), "error on serdes phy for PCIe PHY\n");
+
+ instance->type = PHY_TYPE_PCIE;
+
+ phy = devm_phy_create(dev, subnode, &airoha_phy);
+ if (IS_ERR(phy))
+ return dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n");
+
+ priv->phys[index] = phy;
+ phy_set_drvdata(phy, instance);
+
+ return 0;
+}
+
+static int an7583_usb_phy_probe(struct platform_device *pdev)
+{
+ const struct an7583_usb_phy_match_data *data;
+ struct phy_provider *phy_provider;
+ struct an7583_usb_phy_priv *priv;
+ struct device *dev = &pdev->dev;
+ struct device_node *child_np;
+ int i, ret;
+
+ data = of_device_get_match_data(dev);
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ for (i = 0; i < AIROHA_USB_PHY_REGS_MAX; i++) {
+ struct regmap_config conf = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ };
+ void *base;
+
+ if (!data->regs_name[i])
+ continue;
+
+ conf.name = data->regs_name[i];
+ base = devm_platform_ioremap_resource_byname(pdev,
+ data->regs_name[i]);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regs[i] = devm_regmap_init_mmio(dev, base, &conf);
+ if (IS_ERR(priv->regs[i]))
+ return PTR_ERR(priv->regs[i]);
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ if (device_is_compatible(dev, "airoha,an7583-usb-phy")) {
+ u8 port;
+
+ port = 0;
+ for_each_child_of_node(dev->of_node, child_np) {
+ ret = data->parse_ports(dev, priv, port, child_np);
+ if (ret) {
+ of_node_put(child_np);
+ return ret;
+ }
+
+ port++;
+ }
+ } else {
+ ret = data->parse_ports(dev, priv, 0, dev->of_node);
+ if (ret)
+ return ret;
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev, an7583_usb_phy_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct an7583_usb_phy_match_data an7583_usb_phy = {
+ .max_instance = AIROHA_USB_PHY_MAX_INSTANCE,
+ .regs_name = an7583_usb_phy_regs_name,
+ .parse_ports = an7583_usb_phy_parse_ports,
+};
+
+static const struct an7583_usb_phy_match_data an7583_pcie_phy = {
+ .max_instance = AIROHA_PCIE_PHY_MAX_INSTANCE,
+ .regs_name = airoha_pcie_phy_regs_name,
+ .parse_ports = airoha_pcie_phy_parse_ports,
+};
+
+static const struct of_device_id airoha_phy_id_table[] = {
+ { .compatible = "airoha,an7583-usb-phy", .data = &an7583_usb_phy },
+ { .compatible = "airoha,an7583-pcie-gen2-phy", .data = &an7583_pcie_phy },
+ { },
+};
+MODULE_DEVICE_TABLE(of, airoha_phy_id_table);
+
+static struct platform_driver an7583_usb_driver = {
+ .probe = an7583_usb_phy_probe,
+ .driver = {
+ .name = "airoha-an7583-usb-phy",
+ .of_match_table = airoha_phy_id_table,
+ },
+};
+
+module_platform_driver(an7583_usb_driver);
+
+MODULE_DESCRIPTION("Airoha AN7583 USB PHY driver");
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_LICENSE("GPL");
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v4 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY
2026-09-01 12:39 ` [PATCH v4 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY Christian Marangi
@ 2026-09-01 12:53 ` sashiko-bot
2026-09-01 13:24 ` Christian Marangi
0 siblings, 1 reply; 6+ messages in thread
From: sashiko-bot @ 2026-09-01 12:53 UTC (permalink / raw)
To: Christian Marangi
Cc: robh, linux-phy, neil.armstrong, devicetree, conor+dt, vkoul,
olteanv
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Failure to propagate PHY lifecycle calls to the underlying SerDes PHY
- [High] USB PHY instances are inaccessible due to incorrect PHY provider registration
- [Medium] Use of uninitialized stack variable due to missing regmap_read return check
- [Medium] Lockdep warning due to recursive locking of phy->mutex in set_mode callbacks
- [Low] Missing select REGMAP_MMIO in Kconfig leading to link-time errors
- [Low] Missing explicit inclusion of <linux/delay.h>
--
commit 78bb8c49d95aeffce30cf8303d7ac8de16f47e67
Author: Christian Marangi <ansuelsmth@gmail.com>
phy: airoha: Add support for Airoha AN7583 USB PHY
Add support for USB PHY for Airoha AN7583 SoC, this share some U2 init
from AN7581 but use a totally different init phase for PLL and
calibration for U3. Also on AN7583 there is a single USB PHY that init 2
U2 port and one U3 port. (the USB controller expose 2 hub, one with 2
usb 2.0 port and one with one 3.0 port)
A second USB PHY is used for PCIe Gen2 controller and follow the same
calibration and setup logic of USB.
> diff --git a/drivers/phy/airoha/Kconfig b/drivers/phy/airoha/Kconfig
> new file mode 100644
> index 0000000000000..13e49ff947e3e
> --- /dev/null
> +++ b/drivers/phy/airoha/Kconfig
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +config PHY_AIROHA_AN7583_USB
> + tristate "Airoha AN7583 USB PHY Driver"
> + depends on ARCH_AIROHA || COMPILE_TEST
> + depends on OF
> + select GENERIC_PHY
[Severity: Low]
Is a select for REGMAP_MMIO missing here? If COMPILE_TEST is enabled and no
other driver implicitly selects REGMAP_MMIO, couldn't this cause a link-time
error due to an undefined reference to __devm_regmap_init_mmio_clk?
> + help
> + Say 'Y' here to add support for Airoha AN7583 USB PHY driver.
> diff --git a/drivers/phy/airoha/phy-an7583-usb.c b/drivers/phy/airoha/phy-an7583-usb.c
> new file mode 100644
> index 0000000000000..46b5f09582cfd
> --- /dev/null
> +++ b/drivers/phy/airoha/phy-an7583-usb.c
> @@ -0,0 +1,2023 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Author: Christian Marangi <ansuelsmth@gmail.com>
> + */
> +
> +#include <dt-bindings/phy/phy.h>
> +#include <linux/bitfield.h>
> +#include <linux/math.h>
> +#include <linux/module.h>
> +#include <linux/phy.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
[Severity: Low]
Does this code rely on linux/delay.h for mdelay() and usleep_range() without
including it? This could lead to compilation failures on architectures or
configurations where it isn't implicitly included by other headers.
[ ... ]
> +static bool an7583_usb_phy_u3_kband_is_calibrated(struct an7583_usb_phy_priv *priv)
> +{
> + u32 val, res;
[ ... ]
> + regmap_read(priv->regs[AIROHA_USB_PHY_PMA],
> + AIROHA_USB_PMA_INTF_STS_9, &val);
> + res = FIELD_GET(AIROHA_USB_PMA_ADDR_INTF_STS_PLL_VCOCAL, val) << 4;
[Severity: Medium]
If the regmap_read() fails, wouldn't the uninitialized stack variable val be
accessed here? Could this result in undefined behavior and potentially bypass
the KBand calibration loop?
[ ... ]
> +static int an7583_usb_phy_init(struct phy *phy)
> +{
> + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
[Severity: High]
Does this initialization omit a call to phy_init(instance->serdes_phy)? Since
the wrapper PHY intercepts the init call, failing to forward it might leave
the physical SerDes lines uninitialized and the PCIe and USB 3.0 interfaces
non-functional.
> +
> + switch (instance->type) {
> + case PHY_TYPE_USB2:
[ ... ]
> +static int an7583_usb_phy_power_on(struct phy *phy)
> +{
> + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
[Severity: High]
Similarly, does this fail to call phy_power_on(instance->serdes_phy)? This
seems to leave the physical SerDes disabled when a consumer attempts to power
on the PHY.
> +
> + switch (instance->type) {
> + case PHY_TYPE_USB2:
[ ... ]
> +static int an7583_usb_phy_u3_set_mode(struct phy *phy, enum phy_mode mode,
> + int submode)
> +{
> + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
> + int ret;
> +
> + switch (mode) {
[ ... ]
> + }
> +
> + ret = phy_set_mode_ext(instance->serdes_phy, mode, submode);
[Severity: Medium]
Can this nested call to phy_set_mode_ext() on the child SerDes PHY cause a
lockdep warning?
Since the parent PHY's mutex is already held by the framework, and all PHY
mutexes are initialized with the same lockdep key, this might trigger a
possible recursive locking deadlock warning. This pattern also appears in
an7583_usb_phy_pcie_set_mode().
[ ... ]
> +static struct phy *an7583_usb_phy_xlate(struct device *dev,
> + const struct of_phandle_args *args)
> +{
> + struct an7583_usb_phy_priv *priv = dev_get_drvdata(dev);
> + const struct an7583_usb_phy_match_data *data;
> + struct device_node *phy_np = args->np;
> + struct phy *phy = NULL;
> + int type, index;
> +
> + data = of_device_get_match_data(dev);
> +
> + if (args->args_count != 1) {
> + dev_err(dev, "invalid number of cells in 'phy' property\n");
> + return ERR_PTR(-EINVAL);
> + }
> +
> + for (index = 0; index < data->max_instance; index++) {
> + if (!priv->phys[index])
> + continue;
> +
> + if (phy_np == priv->phys[index]->dev.of_node) {
> + phy = priv->phys[index];
> + break;
> + }
> + }
[ ... ]
> +static int an7583_usb_phy_probe(struct platform_device *pdev)
> +{
[ ... ]
> + phy_provider = devm_of_phy_provider_register(dev, an7583_usb_phy_xlate);
[Severity: High]
Does this incorrectly isolate the subnodes from the PHY core?
By registering the provider with devm_of_phy_provider_register(dev, ...)
instead of using a variant that checks the children tree, the PHY core might
fail to traverse to the child nodes when looking up the PHY.
Furthermore, in an7583_usb_phy_xlate(), comparing the parent node (args->np)
against the child node stored in priv->phys[index]->dev.of_node would
guarantee a mismatch. Would this make the USB PHY instances completely
inaccessible to any consumer?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260901123933.15388-1-ansuelsmth@gmail.com?part=3
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY
2026-09-01 12:53 ` sashiko-bot
@ 2026-09-01 13:24 ` Christian Marangi
0 siblings, 0 replies; 6+ messages in thread
From: Christian Marangi @ 2026-09-01 13:24 UTC (permalink / raw)
To: sashiko-reviews
Cc: robh, linux-phy, neil.armstrong, devicetree, conor+dt, vkoul,
olteanv
On Tue, Sep 01, 2026 at 12:53:43PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
> - [High] Failure to propagate PHY lifecycle calls to the underlying SerDes PHY
> - [High] USB PHY instances are inaccessible due to incorrect PHY provider registration
> - [Medium] Use of uninitialized stack variable due to missing regmap_read return check
> - [Medium] Lockdep warning due to recursive locking of phy->mutex in set_mode callbacks
> - [Low] Missing select REGMAP_MMIO in Kconfig leading to link-time errors
> - [Low] Missing explicit inclusion of <linux/delay.h>
> --
>
> commit 78bb8c49d95aeffce30cf8303d7ac8de16f47e67
> Author: Christian Marangi <ansuelsmth@gmail.com>
>
> phy: airoha: Add support for Airoha AN7583 USB PHY
>
> Add support for USB PHY for Airoha AN7583 SoC, this share some U2 init
> from AN7581 but use a totally different init phase for PLL and
> calibration for U3. Also on AN7583 there is a single USB PHY that init 2
> U2 port and one U3 port. (the USB controller expose 2 hub, one with 2
> usb 2.0 port and one with one 3.0 port)
>
> A second USB PHY is used for PCIe Gen2 controller and follow the same
> calibration and setup logic of USB.
>
> > diff --git a/drivers/phy/airoha/Kconfig b/drivers/phy/airoha/Kconfig
> > new file mode 100644
> > index 0000000000000..13e49ff947e3e
> > --- /dev/null
> > +++ b/drivers/phy/airoha/Kconfig
> > @@ -0,0 +1,11 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +
> > +config PHY_AIROHA_AN7583_USB
> > + tristate "Airoha AN7583 USB PHY Driver"
> > + depends on ARCH_AIROHA || COMPILE_TEST
> > + depends on OF
> > + select GENERIC_PHY
>
> [Severity: Low]
> Is a select for REGMAP_MMIO missing here? If COMPILE_TEST is enabled and no
> other driver implicitly selects REGMAP_MMIO, couldn't this cause a link-time
> error due to an undefined reference to __devm_regmap_init_mmio_clk?
>
> > + help
> > + Say 'Y' here to add support for Airoha AN7583 USB PHY driver.
>
> > diff --git a/drivers/phy/airoha/phy-an7583-usb.c b/drivers/phy/airoha/phy-an7583-usb.c
> > new file mode 100644
> > index 0000000000000..46b5f09582cfd
> > --- /dev/null
> > +++ b/drivers/phy/airoha/phy-an7583-usb.c
> > @@ -0,0 +1,2023 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Author: Christian Marangi <ansuelsmth@gmail.com>
> > + */
> > +
> > +#include <dt-bindings/phy/phy.h>
> > +#include <linux/bitfield.h>
> > +#include <linux/math.h>
> > +#include <linux/module.h>
> > +#include <linux/phy.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/mfd/syscon.h>
>
> [Severity: Low]
> Does this code rely on linux/delay.h for mdelay() and usleep_range() without
> including it? This could lead to compilation failures on architectures or
> configurations where it isn't implicitly included by other headers.
>
> [ ... ]
>
> > +static bool an7583_usb_phy_u3_kband_is_calibrated(struct an7583_usb_phy_priv *priv)
> > +{
> > + u32 val, res;
>
> [ ... ]
>
> > + regmap_read(priv->regs[AIROHA_USB_PHY_PMA],
> > + AIROHA_USB_PMA_INTF_STS_9, &val);
> > + res = FIELD_GET(AIROHA_USB_PMA_ADDR_INTF_STS_PLL_VCOCAL, val) << 4;
>
> [Severity: Medium]
> If the regmap_read() fails, wouldn't the uninitialized stack variable val be
> accessed here? Could this result in undefined behavior and potentially bypass
> the KBand calibration loop?
>
> [ ... ]
>
> > +static int an7583_usb_phy_init(struct phy *phy)
> > +{
> > + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
>
> [Severity: High]
> Does this initialization omit a call to phy_init(instance->serdes_phy)? Since
> the wrapper PHY intercepts the init call, failing to forward it might leave
> the physical SerDes lines uninitialized and the PCIe and USB 3.0 interfaces
> non-functional.
>
> > +
> > + switch (instance->type) {
> > + case PHY_TYPE_USB2:
>
> [ ... ]
>
> > +static int an7583_usb_phy_power_on(struct phy *phy)
> > +{
> > + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
>
> [Severity: High]
> Similarly, does this fail to call phy_power_on(instance->serdes_phy)? This
> seems to leave the physical SerDes disabled when a consumer attempts to power
> on the PHY.
>
> > +
> > + switch (instance->type) {
> > + case PHY_TYPE_USB2:
>
> [ ... ]
>
> > +static int an7583_usb_phy_u3_set_mode(struct phy *phy, enum phy_mode mode,
> > + int submode)
> > +{
> > + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy);
> > + int ret;
> > +
> > + switch (mode) {
>
> [ ... ]
>
> > + }
> > +
> > + ret = phy_set_mode_ext(instance->serdes_phy, mode, submode);
>
> [Severity: Medium]
> Can this nested call to phy_set_mode_ext() on the child SerDes PHY cause a
> lockdep warning?
>
> Since the parent PHY's mutex is already held by the framework, and all PHY
> mutexes are initialized with the same lockdep key, this might trigger a
> possible recursive locking deadlock warning. This pattern also appears in
> an7583_usb_phy_pcie_set_mode().
>
> [ ... ]
>
> > +static struct phy *an7583_usb_phy_xlate(struct device *dev,
> > + const struct of_phandle_args *args)
> > +{
> > + struct an7583_usb_phy_priv *priv = dev_get_drvdata(dev);
> > + const struct an7583_usb_phy_match_data *data;
> > + struct device_node *phy_np = args->np;
> > + struct phy *phy = NULL;
> > + int type, index;
> > +
> > + data = of_device_get_match_data(dev);
> > +
> > + if (args->args_count != 1) {
> > + dev_err(dev, "invalid number of cells in 'phy' property\n");
> > + return ERR_PTR(-EINVAL);
> > + }
> > +
> > + for (index = 0; index < data->max_instance; index++) {
> > + if (!priv->phys[index])
> > + continue;
> > +
> > + if (phy_np == priv->phys[index]->dev.of_node) {
> > + phy = priv->phys[index];
> > + break;
> > + }
> > + }
>
> [ ... ]
>
> > +static int an7583_usb_phy_probe(struct platform_device *pdev)
> > +{
>
> [ ... ]
>
> > + phy_provider = devm_of_phy_provider_register(dev, an7583_usb_phy_xlate);
>
> [Severity: High]
> Does this incorrectly isolate the subnodes from the PHY core?
>
> By registering the provider with devm_of_phy_provider_register(dev, ...)
> instead of using a variant that checks the children tree, the PHY core might
> fail to traverse to the child nodes when looking up the PHY.
>
> Furthermore, in an7583_usb_phy_xlate(), comparing the parent node (args->np)
> against the child node stored in priv->phys[index]->dev.of_node would
> guarantee a mismatch. Would this make the USB PHY instances completely
> inaccessible to any consumer?
>
Is AI getting drunk? Aside from the mostly unreadable message, this is
totally non-sense and out of complete speculation.
The scenario pointed out by AI is in the case where a consumer reference
the provider node in DT but this was never suggested and actually an
implementation error of the user writing the device tree.
The Documentation example instruct for USB nodes to put the phy cell in the
child node, NEVER in the provider node. Any kind of phandle will fail as
the correct cell property won't be found. So I'm not really understanding
the error pointed out here.
--
Ansuel
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-01 13:24 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 12:39 [PATCH v4 0/3] phy: Add support for Airoha AN7583 USB PHY Christian Marangi
2026-09-01 12:39 ` [PATCH v4 1/3] dt-bindings: phy: airoha: Document support for " Christian Marangi
2026-09-01 12:39 ` [PATCH v4 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY Christian Marangi
2026-09-01 12:39 ` [PATCH v4 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY Christian Marangi
2026-09-01 12:53 ` sashiko-bot
2026-09-01 13:24 ` Christian Marangi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox