* [PATCH v2 0/2] phy: Add support for Airoha AN7583 USB PHY
@ 2026-08-11 12:47 ` Christian Marangi
0 siblings, 0 replies; 6+ messages in thread
From: Christian Marangi @ 2026-08-11 12:47 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Marangi, linux-phy, devicetree,
linux-kernel
This small series ass support for Airoha USB PHY and Gen2 PCIe
PHY.
Changes v2:
- Add Documentation
- Out of RFC
- Rework to Serdes PHY instead of SCU (following
for consistency AN7581 implementation)
Christian Marangi (2):
dt-bindings: phy: Add documentation for Airoha AN7583 USB PHY
phy: airoha: Add support for Airoha AN7583 USB PHY
.../bindings/phy/airoha,an7583-usb-phy.yaml | 205 +-
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 | 2009 +++++++++++++++++
6 files changed, 2194 insertions(+), 38 deletions(-)
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] 6+ messages in thread
* [PATCH v2 0/2] phy: Add support for Airoha AN7583 USB PHY
@ 2026-08-11 12:47 ` Christian Marangi
0 siblings, 0 replies; 6+ messages in thread
From: Christian Marangi @ 2026-08-11 12:47 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Marangi, linux-phy, devicetree,
linux-kernel
This small series ass support for Airoha USB PHY and Gen2 PCIe
PHY.
Changes v2:
- Add Documentation
- Out of RFC
- Rework to Serdes PHY instead of SCU (following
for consistency AN7581 implementation)
Christian Marangi (2):
dt-bindings: phy: Add documentation for Airoha AN7583 USB PHY
phy: airoha: Add support for Airoha AN7583 USB PHY
.../bindings/phy/airoha,an7583-usb-phy.yaml | 205 +-
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 | 2009 +++++++++++++++++
6 files changed, 2194 insertions(+), 38 deletions(-)
create mode 100644 drivers/phy/airoha/Kconfig
create mode 100644 drivers/phy/airoha/Makefile
create mode 100644 drivers/phy/airoha/phy-an7583-usb.c
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] dt-bindings: phy: Add documentation for Airoha AN7583 USB PHY
2026-08-11 12:47 ` Christian Marangi
@ 2026-08-11 12:47 ` Christian Marangi
-1 siblings, 0 replies; 6+ messages in thread
From: Christian Marangi @ 2026-08-11 12:47 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.
The second USB PHY on Airoha AN7583 SoC is used for PCIe Gen2 usage and
similar to USB 3.0 require a phys property to configure the serdes.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
.../bindings/phy/airoha,an7583-usb-phy.yaml | 205 ++++++++++++++----
1 file changed, 168 insertions(+), 37 deletions(-)
diff --git a/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml b/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
index a6e2c0b1acc4..46b311040e02 100644
--- a/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
@@ -26,64 +26,195 @@ description: >
properties:
compatible:
- const: airoha,an7583-usb-phy
+ enum:
+ - airoha,an7583-usb-phy
+ - airoha,an7583-pcie-phy
reg:
- items:
- - description: phy register
- - description: ana register
- - description: pma register
- - description: dig register
+ minItems: 3
+ maxItems: 4
reg-names:
- itmes:
- const: phy
- const: ana
- const: pma
- const: dif
+ minItems: 3
+ maxItems: 4
- usb2-phy:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ usb3-phy:
type: object
properties:
- reg: [0, 0x1000]
+ phys:
+ items:
+ - description: phandle to Serdes PHY
- 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
- '#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'
- usb3-phy:
+ additionalProperties: false
+
+ pcie-phy:
+ type: object
+
+ properties:
+ phys:
+ items:
+ - description: phandle to Serdes PHY
+
+ '#phy-cells':
+ description: The cell contains the mode, PHY_TYPE_PCIE or PHY_TYPE_USB3,
+ as defined in dt-bindings/phy/phy.h.
+ const: 1
+
+ required:
+ - phys
+ - '#phy-cells'
+
+ additionalProperties: false
- phys:
- items:
- - description: phandle to Serdes PHY. Optional if USB 3.0 is not used.
+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
- - airoha,usb2-monitor-clk-sel
- - '#phy-cells'
-
-additionalProperties: false
+ - reg-names
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ const: airoha,an7583-usb-phy
+
+ then:
+ properties:
+ 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
+
+ pcie-phy: false
+
+ required:
+ - '#address-cells'
+ - '#size-cells'
+
+ - if:
+ properties:
+ compatible:
+ const: airoha,an7583-pcie-phy
+
+ then:
+ properties:
+ reg:
+ items:
+ - description: ana register
+ - description: pma register
+ - description: dig register
+
+ reg-names:
+ items:
+ - const: ana
+ - const: pma
+ - const: dig
+
+ usb3-phy: false
+
+ '#address-cells': false
+
+ '#size-cells': false
+
+ patternProperties:
+ '^usb2-phy@[0-9a-f]+$': false
+
+unevaluatedProperties: false
examples:
- |
- #include <dt-bindings/soc/airoha,scu-ssr.h>
-
phy@1fac0000 {
- compatible = "airoha,an7581-usb-phy";
- reg = <0x1fac0000 0x10000>;
+ 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>;
+ };
+ };
+
+ phy@1fa5f000 {
+ compatible = "airoha,an7583-pcie-phy";
+ reg = <0x1fa5f000 0xff>,
+ <0x1fa5e000 0x3ff>,
+ <0x1fa5a000 0x8ff>;
+ reg-names = "ana", "pma", "dig";
- airoha,usb2-monitor-clk-sel = <1>;
- phys = <&scu AIROHA_SCU_SERDES_USB1>;
+ pcie-phy {
+ phys = <&serdes_phy>;
- #phy-cells = <1>;
+ #phy-cells = <1>;
+ };
};
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] dt-bindings: phy: Add documentation for Airoha AN7583 USB PHY
@ 2026-08-11 12:47 ` Christian Marangi
0 siblings, 0 replies; 6+ messages in thread
From: Christian Marangi @ 2026-08-11 12:47 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.
The second USB PHY on Airoha AN7583 SoC is used for PCIe Gen2 usage and
similar to USB 3.0 require a phys property to configure the serdes.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
.../bindings/phy/airoha,an7583-usb-phy.yaml | 205 ++++++++++++++----
1 file changed, 168 insertions(+), 37 deletions(-)
diff --git a/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml b/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
index a6e2c0b1acc4..46b311040e02 100644
--- a/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/airoha,an7583-usb-phy.yaml
@@ -26,64 +26,195 @@ description: >
properties:
compatible:
- const: airoha,an7583-usb-phy
+ enum:
+ - airoha,an7583-usb-phy
+ - airoha,an7583-pcie-phy
reg:
- items:
- - description: phy register
- - description: ana register
- - description: pma register
- - description: dig register
+ minItems: 3
+ maxItems: 4
reg-names:
- itmes:
- const: phy
- const: ana
- const: pma
- const: dif
+ minItems: 3
+ maxItems: 4
- usb2-phy:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ usb3-phy:
type: object
properties:
- reg: [0, 0x1000]
+ phys:
+ items:
+ - description: phandle to Serdes PHY
- 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
- '#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'
- usb3-phy:
+ additionalProperties: false
+
+ pcie-phy:
+ type: object
+
+ properties:
+ phys:
+ items:
+ - description: phandle to Serdes PHY
+
+ '#phy-cells':
+ description: The cell contains the mode, PHY_TYPE_PCIE or PHY_TYPE_USB3,
+ as defined in dt-bindings/phy/phy.h.
+ const: 1
+
+ required:
+ - phys
+ - '#phy-cells'
+
+ additionalProperties: false
- phys:
- items:
- - description: phandle to Serdes PHY. Optional if USB 3.0 is not used.
+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
- - airoha,usb2-monitor-clk-sel
- - '#phy-cells'
-
-additionalProperties: false
+ - reg-names
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ const: airoha,an7583-usb-phy
+
+ then:
+ properties:
+ 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
+
+ pcie-phy: false
+
+ required:
+ - '#address-cells'
+ - '#size-cells'
+
+ - if:
+ properties:
+ compatible:
+ const: airoha,an7583-pcie-phy
+
+ then:
+ properties:
+ reg:
+ items:
+ - description: ana register
+ - description: pma register
+ - description: dig register
+
+ reg-names:
+ items:
+ - const: ana
+ - const: pma
+ - const: dig
+
+ usb3-phy: false
+
+ '#address-cells': false
+
+ '#size-cells': false
+
+ patternProperties:
+ '^usb2-phy@[0-9a-f]+$': false
+
+unevaluatedProperties: false
examples:
- |
- #include <dt-bindings/soc/airoha,scu-ssr.h>
-
phy@1fac0000 {
- compatible = "airoha,an7581-usb-phy";
- reg = <0x1fac0000 0x10000>;
+ 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>;
+ };
+ };
+
+ phy@1fa5f000 {
+ compatible = "airoha,an7583-pcie-phy";
+ reg = <0x1fa5f000 0xff>,
+ <0x1fa5e000 0x3ff>,
+ <0x1fa5a000 0x8ff>;
+ reg-names = "ana", "pma", "dig";
- airoha,usb2-monitor-clk-sel = <1>;
- phys = <&scu AIROHA_SCU_SERDES_USB1>;
+ pcie-phy {
+ phys = <&serdes_phy>;
- #phy-cells = <1>;
+ #phy-cells = <1>;
+ };
};
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] phy: airoha: Add support for Airoha AN7583 USB PHY
2026-08-11 12:47 ` Christian Marangi
@ 2026-08-11 12:47 ` Christian Marangi
-1 siblings, 0 replies; 6+ messages in thread
From: Christian Marangi @ 2026-08-11 12:47 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 | 2009 +++++++++++++++++++++++++++
5 files changed, 2026 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..17394ab0e133
--- /dev/null
+++ b/drivers/phy/airoha/phy-an7583-usb.c
@@ -0,0 +1,2009 @@
+// 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_subnode)(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_subnode(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_subnode(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;
+ u8 port;
+
+ 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);
+
+ port = 0;
+ for_each_child_of_node(dev->of_node, child_np) {
+ ret = data->parse_subnode(dev, priv, port, child_np);
+ if (ret) {
+ of_node_put(child_np);
+ return ret;
+ }
+
+ port++;
+ }
+
+ 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_subnode = an7583_usb_phy_parse_subnode,
+};
+
+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_subnode = airoha_pcie_phy_parse_subnode,
+};
+
+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
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] phy: airoha: Add support for Airoha AN7583 USB PHY
@ 2026-08-11 12:47 ` Christian Marangi
0 siblings, 0 replies; 6+ messages in thread
From: Christian Marangi @ 2026-08-11 12:47 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 | 2009 +++++++++++++++++++++++++++
5 files changed, 2026 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..17394ab0e133
--- /dev/null
+++ b/drivers/phy/airoha/phy-an7583-usb.c
@@ -0,0 +1,2009 @@
+// 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_subnode)(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_subnode(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_subnode(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;
+ u8 port;
+
+ 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);
+
+ port = 0;
+ for_each_child_of_node(dev->of_node, child_np) {
+ ret = data->parse_subnode(dev, priv, port, child_np);
+ if (ret) {
+ of_node_put(child_np);
+ return ret;
+ }
+
+ port++;
+ }
+
+ 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_subnode = an7583_usb_phy_parse_subnode,
+};
+
+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_subnode = airoha_pcie_phy_parse_subnode,
+};
+
+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] 6+ messages in thread
end of thread, other threads:[~2026-08-11 12:47 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-11 12:47 [PATCH v2 0/2] phy: Add support for Airoha AN7583 USB PHY Christian Marangi
2026-08-11 12:47 ` Christian Marangi
2026-08-11 12:47 ` [PATCH v2 1/2] dt-bindings: phy: Add documentation " Christian Marangi
2026-08-11 12:47 ` Christian Marangi
2026-08-11 12:47 ` [PATCH v2 2/2] phy: airoha: Add support " Christian Marangi
2026-08-11 12:47 ` Christian Marangi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.