* [PATCH v3 0/3] phy: Add support for Airoha AN7583 USB PHY
@ 2026-08-27 13:15 Christian Marangi
2026-08-27 13:15 ` [PATCH v3 1/3] dt-bindings: phy: airoha: Document support for " Christian Marangi
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Christian Marangi @ 2026-08-27 13:15 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 v3:
- Fix broken patch for YAML patch
- Split the YAML for USB and PCIe
- Rework driver to direct node for PCIe PHY
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 | 2016 +++++++++++++++++
7 files changed, 2229 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
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 1/3] dt-bindings: phy: airoha: Document support for AN7583 USB PHY
2026-08-27 13:15 [PATCH v3 0/3] phy: Add support for Airoha AN7583 USB PHY Christian Marangi
@ 2026-08-27 13:15 ` Christian Marangi
2026-08-27 13:25 ` sashiko-bot
2026-08-27 13:15 ` [PATCH v3 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY Christian Marangi
2026-08-27 13:15 ` [PATCH v3 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY Christian Marangi
2 siblings, 1 reply; 7+ messages in thread
From: Christian Marangi @ 2026-08-27 13:15 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..7ec655253a8e
--- /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 AN7581 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-9-a-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 0x11ff>,
+ <0x1fa6f000 0xff>,
+ <0x1fa6e000 0x3ff>,
+ <0x1fa6a000 0x8ff>;
+ 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
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY
2026-08-27 13:15 [PATCH v3 0/3] phy: Add support for Airoha AN7583 USB PHY Christian Marangi
2026-08-27 13:15 ` [PATCH v3 1/3] dt-bindings: phy: airoha: Document support for " Christian Marangi
@ 2026-08-27 13:15 ` Christian Marangi
2026-08-27 13:23 ` sashiko-bot
2026-08-27 13:15 ` [PATCH v3 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY Christian Marangi
2 siblings, 1 reply; 7+ messages in thread
From: Christian Marangi @ 2026-08-27 13:15 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..f31d838871fc
--- /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 AN7581 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-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-phy";
+ reg = <0x1fa5f000 0xff>,
+ <0x1fa5e000 0x3ff>,
+ <0x1fa5a000 0x8ff>;
+ reg-names = "ana", "pma", "dig";
+
+ phys = <&serdes_phy>;
+
+ #phy-cells = <0>;
+ };
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY
2026-08-27 13:15 [PATCH v3 0/3] phy: Add support for Airoha AN7583 USB PHY Christian Marangi
2026-08-27 13:15 ` [PATCH v3 1/3] dt-bindings: phy: airoha: Document support for " Christian Marangi
2026-08-27 13:15 ` [PATCH v3 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY Christian Marangi
@ 2026-08-27 13:15 ` Christian Marangi
2026-08-27 13:26 ` sashiko-bot
2 siblings, 1 reply; 7+ messages in thread
From: Christian Marangi @ 2026-08-27 13:15 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 | 2016 +++++++++++++++++++++++++++
5 files changed, 2033 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..33915c9f4a0d
--- /dev/null
+++ b/drivers/phy/airoha/phy-an7583-usb.c
@@ -0,0 +1,2016 @@
+// 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 fm_out, srctrl;
+ u32 offset;
+
+ 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);
+
+ mdelay(5);
+
+ 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);
+
+ mdelay(5);
+
+ 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:
+ an7583_usb_phy_u2_init(phy);
+ break;
+ case PHY_TYPE_USB3:
+ if (phy_get_mode(phy) == PHY_MODE_ETHERNET)
+ return 0;
+
+ an7583_usb_phy_u3_init(phy);
+ break;
+ case PHY_TYPE_PCIE:
+ if (phy_get_mode(phy) == PHY_MODE_ETHERNET)
+ return 0;
+
+ an7583_usb_phy_pcie_init(phy);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+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_priv *priv = dev_get_drvdata(phy->dev.parent);
+ u32 val = 0;
+
+ /*
+ * 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,
+ 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;
+ 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;
+ 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_phy_optional_get(dev, 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, ret, "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-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
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v3 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY
2026-08-27 13:15 ` [PATCH v3 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY Christian Marangi
@ 2026-08-27 13:23 ` sashiko-bot
0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-08-27 13:23 UTC (permalink / raw)
To: Christian Marangi
Cc: robh, vkoul, linux-phy, olteanv, neil.armstrong, conor+dt,
devicetree
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Low] The binding title incorrectly refers to 'AN7581' instead of 'AN7583'.
- [Low] The register sizes in the example are off-by-one, incorrectly using the maximum offset instead of the byte count.
- [Low] The binding filename 'airoha,an7583-pcie-gen2-phy.yaml' does not match the compatible string 'airoha,an7583-pcie-phy'.
--
commit a30f9e597cd1c12059c1c3ca3b0550d5e5800f4d
Author: Christian Marangi <ansuelsmth@gmail.com>
Subject: dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY
This commit documents support for the AN7583 Gen2 PCIe PHY, which is used
to make the Gen2 PCIe port work. It adds the required registers to configure
the PCIe PHY and provides a usage example.
> 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 0000000000000..f31d838871fc1
> --- /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#
[Severity: Low]
Should the filename (and consequently the $id path) match the defined
compatible string airoha,an7583-pcie-phy? The extraneous 'gen2-' in the
filename causes it to diverge from the compatible string, which typically
triggers a schema validation warning when running dt_binding_check.
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Airoha AN7581 SoC PCIe Gen2 PHY
[Severity: Low]
Does this title incorrectly refer to AN7581 instead of the intended target
AN7583?
[ ... ]
> +examples:
> + - |
> + phy@1fa5f000 {
> + compatible = "airoha,an7583-pcie-phy";
> + reg = <0x1fa5f000 0xff>,
> + <0x1fa5e000 0x3ff>,
> + <0x1fa5a000 0x8ff>;
[Severity: Low]
Are these register sizes in the example off-by-one? The sizes 0xff, 0x3ff,
and 0x8ff (255, 1023, and 2303 bytes) are not multiples of 4, meaning the
final byte of the last 32-bit register is excluded from the memory region.
A developer copying this example verbatim might create an invalid device
tree that could cause out-of-bounds accesses when the driver reads the final
register.
> + reg-names = "ana", "pma", "dig";
> +
> + phys = <&serdes_phy>;
> +
> + #phy-cells = <0>;
> + };
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260827131551.26725-1-ansuelsmth@gmail.com?part=2
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 1/3] dt-bindings: phy: airoha: Document support for AN7583 USB PHY
2026-08-27 13:15 ` [PATCH v3 1/3] dt-bindings: phy: airoha: Document support for " Christian Marangi
@ 2026-08-27 13:25 ` sashiko-bot
0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-08-27 13:25 UTC (permalink / raw)
To: Christian Marangi
Cc: linux-phy, olteanv, vkoul, devicetree, robh, neil.armstrong,
conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Malformed character range in patternProperties regex allows invalid unit addresses.
- [Low] Typo in the binding title and grammatical errors in the description.
--
commit 4a5fe874f5d1686d215561949399a35ae4b5a15b
Author: Christian Marangi <ansuelsmth@gmail.com>
dt-bindings: phy: airoha: Document support for AN7583 USB PHY
Adds documentation for the Airoha AN7583 USB PHY for the USB controller.
The binding details support for up to two USB 2.0 ports, optional USB 3.0
modes via Serdes configuration, and monitor clock calibration.
> 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 0000000000000..7ec655253a8ef
> --- /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 AN7581 SoC USB PHY
[Severity: Low]
This isn't a bug, but is the title targeting the correct SoC variant? The
compatible string and filename target AN7583, but the title mistakenly
says AN7581.
> +
> +maintainers:
> + - Christian Marangi <ansuelsmth@gmail.com>
> +
> +description: >
> + The Airoha AN7583 SoC USB PHY describes the USB PHY for the USB controller..
[Severity: Low]
This isn't a bug, but there is a typo here with the double period at the
end of the sentence.
[ ... ]
> +patternProperties:
> + '^usb2-phy@[0-9-a-f]+$':
[Severity: Medium]
Does this regex correctly restrict unit addresses?
The regex [0-9-a-f] contains a hyphen after a completed range (0-9), causing
the hyphen to be treated as a literal character rather than part of a valid
hex range. This incorrectly validates malformed device tree node names
containing hyphens in the unit address (e.g., usb2-phy@0-a).
Should this pattern be updated to [0-9a-f]+ to enforce proper hex unit
addresses?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260827131551.26725-1-ansuelsmth@gmail.com?part=1
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY
2026-08-27 13:15 ` [PATCH v3 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY Christian Marangi
@ 2026-08-27 13:26 ` sashiko-bot
0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-08-27 13:26 UTC (permalink / raw)
To: Christian Marangi
Cc: vkoul, olteanv, conor+dt, linux-phy, robh, neil.armstrong,
devicetree
Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [High] Off-by-one error in array bounds check allows out-of-bounds array write.
- [High] Incorrect device node is used to fetch the per-port serdes PHY.
- [High] Missing per-port register offset in `an7583_usb_phy_u2_set_mode` causes cross-instance state corruption.
- [Medium] Uninitialized variable `ret` is used as an error return code in `an7583_usb_phy_parse_ports`.
- [Medium] `fm_out` may be evaluated uninitialized if the regmap polling macro fails.
- [Medium] The PHY initialization error codes for USB3 and PCIe are silently ignored.
- [Medium] Nested acquisition of same-class PHY mutex triggers lockdep warning.
- [Medium] Excessive busy-waiting using mdelay() in PHY initialization loops.
- [Low] Missing `fallthrough;` annotation in switch statements triggers implicit fallthrough warnings.
--
commit e08eb2476fb864bd66e0895961c95bf0fbc89352
Author: Christian Marangi <ansuelsmth@gmail.com>
phy: airoha: Add support for Airoha AN7583 USB PHY
Adds support for USB PHY on Airoha AN7583 SoC, supporting two U2 ports and
one U3 port via a single USB PHY instance, plus a second instance for
PCIe Gen2.
> diff --git a/drivers/phy/airoha/phy-an7583-usb.c b/drivers/phy/airoha/phy-an7583-usb.c
> new file mode 100644
> index 0000000000000..33915c9f4a0de
> --- /dev/null
> +++ b/drivers/phy/airoha/phy-an7583-usb.c
> @@ -280,18 +280,18 @@ static int an7583_usb_phy_u2_slew_rate_calibration(struct phy *phy)
> /* 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) {
[Severity: Medium]
If the regmap read returns an error here in
an7583_usb_phy_u2_slew_rate_calibration(), regmap_read_poll_timeout()
will terminate early without initializing fm_out.
Will this cause the subsequent check if (!fm_out) to evaluate garbage data?
[ ... ]
> @@ -340,11 +340,11 @@ static bool an7583_usb_phy_u3_kband_is_calibrated(struct an7583_usb_phy_priv *pr
> /* Read KBand */
> regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA],
> AIROHA_USB_ANA_TDC_FT_CK_EN,
> AIROHA_USB_ANA_PLL_DEBUG_SEL);
>
> mdelay(5);
[Severity: Medium]
Can this delay in an7583_usb_phy_u3_kband_is_calibrated() cause excessive
CPU stalling?
It uses mdelay(5) twice per loop, and is called up to 50 times in
an7583_usb_phy_u3_init(). Because mdelay spins the CPU instead of sleeping,
this could freeze the CPU for up to 500ms during hardware initialization
failures.
Should this be using usleep_range() or msleep() instead?
[ ... ]
> @@ -1020,16 +1020,16 @@ 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:
> an7583_usb_phy_u2_init(phy);
> break;
> case PHY_TYPE_USB3:
> if (phy_get_mode(phy) == PHY_MODE_ETHERNET)
> return 0;
>
> an7583_usb_phy_u3_init(phy);
> break;
> case PHY_TYPE_PCIE:
> if (phy_get_mode(phy) == PHY_MODE_ETHERNET)
> return 0;
>
> an7583_usb_phy_pcie_init(phy);
[Severity: Medium]
Both an7583_usb_phy_u3_init() and an7583_usb_phy_pcie_init() return an
error code (-EINVAL) when calibration fails, but those values are ignored
here.
Does this falsely notify the PHY framework of a successful initialization?
> break;
> default:
> return -EINVAL;
> }
[ ... ]
> @@ -1176,8 +1176,8 @@ static int an7583_usb_phy_u2_set_mode(struct phy *phy, enum phy_mode mode)
> 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,
[Severity: High]
Does this code in an7583_usb_phy_u2_set_mode() write to the base register
space of port 0 instead of the correct port?
Unlike other functions (e.g., power_on or init), this directly accesses
AIROHA_USB_PHY_U2PHYDTM1 without adding instance->offset. If mode
configuration is applied to a secondary port, it seems like this will corrupt
port 0's state.
> AIROHA_USB_PHY_FORCE_IDDIG |
> AIROHA_USB_PHY_IDDIG, val);
[ ... ]
> @@ -1193,12 +1193,12 @@ 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;
> case PHY_MODE_USB_DEVICE_SS:
[Severity: Low]
Is this an intentional fallthrough?
If so, this switch block needs a fallthrough annotation to prevent compiler
warnings.
> break;
> default:
> return -EOPNOTSUPP;
> }
>
> ret = phy_set_mode_ext(instance->serdes_phy, mode, submode);
[Severity: Medium]
Will this nested call to phy_set_mode_ext() in an7583_usb_phy_u3_set_mode()
trigger a lockdep warning?
The core PHY framework invokes the driver's set_mode callback with the
primary phy->mutex held. Calling phy_set_mode_ext() on the secondary PHY
attempts to acquire the secondary PHY's mutex, which belongs to the same
lock class.
[ ... ]
> @@ -1215,12 +1215,12 @@ 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;
> case PHY_MODE_PCIE:
[Severity: Low]
Is this an intentional fallthrough?
If so, this switch block needs a fallthrough annotation to prevent compiler
warnings.
> break;
> default:
> return -EOPNOTSUPP;
> }
>
> ret = phy_set_mode_ext(instance->serdes_phy, mode, submode);
[Severity: Medium]
Will this nested call to phy_set_mode_ext() in an7583_usb_phy_pcie_set_mode()
trigger a lockdep warning?
The core PHY framework invokes the driver's set_mode callback with the
primary phy->mutex held. Calling phy_set_mode_ext() on the secondary PHY
attempts to acquire the secondary PHY's mutex, which belongs to the same
lock class.
[ ... ]
> @@ -1297,29 +1297,29 @@ 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)
[Severity: High]
Should this bounds check use >= instead of > in an7583_usb_phy_parse_ports()?
The max_instance is the size of the array (3 for USB), so allowing index to
equal max_instance will cause an out-of-bounds write when priv->phys[index]
is assigned later.
> 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_optional_get(dev, NULL);
[Severity: High]
Does devm_phy_optional_get() fetch the per-port serdes PHY from the parent
device node rather than the specific port subnode?
Because it uses dev and not subnode, it appears all subnodes will resolve to
the exact same PHY instance, which would misclassify every port as
PHY_TYPE_USB3 and break USB2 port initialization.
Should this use 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, ret, "monitor clock selection or serdes PHY is mandatory for USB PHY\n");
[Severity: Medium]
If the subnode lacks both the serdes_phy and the airoha,usb2-monitor-clk-sel
properties, the error path returns the uninitialized ret variable.
Can this return a garbage error code (or 0) leading to silent initialization
failures?
>
> 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;
[ ... ]
> @@ -1341,12 +1341,12 @@ 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)
[Severity: High]
Should this bounds check use >= instead of > in airoha_pcie_phy_parse_ports()?
The max_instance is the size of the array (1 for PCIe), so allowing index to
equal max_instance will cause an out-of-bounds write when priv->phys[index]
is assigned later.
> return -EINVAL;
>
> if (!of_device_is_available(subnode))
> return 0;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260827131551.26725-1-ansuelsmth@gmail.com?part=3
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-27 13:26 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-27 13:15 [PATCH v3 0/3] phy: Add support for Airoha AN7583 USB PHY Christian Marangi
2026-08-27 13:15 ` [PATCH v3 1/3] dt-bindings: phy: airoha: Document support for " Christian Marangi
2026-08-27 13:25 ` sashiko-bot
2026-08-27 13:15 ` [PATCH v3 2/3] dt-bindings: phy: airoha: Document support for AN7583 Gen2 PCIe PHY Christian Marangi
2026-08-27 13:23 ` sashiko-bot
2026-08-27 13:15 ` [PATCH v3 3/3] phy: airoha: Add support for Airoha AN7583 USB PHY Christian Marangi
2026-08-27 13:26 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox