aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/phy
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/phy')
-rw-r--r--roms/u-boot/drivers/phy/Kconfig272
-rw-r--r--roms/u-boot/drivers/phy/Makefile33
-rw-r--r--roms/u-boot/drivers/phy/allwinner/Kconfig13
-rw-r--r--roms/u-boot/drivers/phy/allwinner/Makefile6
-rw-r--r--roms/u-boot/drivers/phy/allwinner/phy-sun4i-usb.c651
-rw-r--r--roms/u-boot/drivers/phy/bcm6318-usbh-phy.c143
-rw-r--r--roms/u-boot/drivers/phy/bcm6348-usbh-phy.c92
-rw-r--r--roms/u-boot/drivers/phy/bcm6358-usbh-phy.c92
-rw-r--r--roms/u-boot/drivers/phy/bcm6368-usbh-phy.c196
-rw-r--r--roms/u-boot/drivers/phy/keystone-usb-phy.c134
-rw-r--r--roms/u-boot/drivers/phy/marvell/Kconfig9
-rw-r--r--roms/u-boot/drivers/phy/marvell/Makefile6
-rw-r--r--roms/u-boot/drivers/phy/marvell/comphy_a3700.c1019
-rw-r--r--roms/u-boot/drivers/phy/marvell/comphy_a3700.h263
-rw-r--r--roms/u-boot/drivers/phy/marvell/comphy_core.c215
-rw-r--r--roms/u-boot/drivers/phy/marvell/comphy_core.h144
-rw-r--r--roms/u-boot/drivers/phy/marvell/comphy_cp110.c681
-rw-r--r--roms/u-boot/drivers/phy/marvell/comphy_mux.c135
-rw-r--r--roms/u-boot/drivers/phy/marvell/sata.h29
-rw-r--r--roms/u-boot/drivers/phy/marvell/utmi_phy.h101
-rw-r--r--roms/u-boot/drivers/phy/meson-axg-mipi-dphy.c393
-rw-r--r--roms/u-boot/drivers/phy/meson-axg-mipi-pcie-analog.c233
-rw-r--r--roms/u-boot/drivers/phy/meson-g12a-usb2.c219
-rw-r--r--roms/u-boot/drivers/phy/meson-g12a-usb3-pcie.c420
-rw-r--r--roms/u-boot/drivers/phy/meson-gxbb-usb2.c236
-rw-r--r--roms/u-boot/drivers/phy/meson-gxl-usb2.c255
-rw-r--r--roms/u-boot/drivers/phy/msm8916-usbh-phy.c110
-rw-r--r--roms/u-boot/drivers/phy/mt7620-usb-phy.c110
-rw-r--r--roms/u-boot/drivers/phy/mt76x8-usb-phy.c252
-rw-r--r--roms/u-boot/drivers/phy/nop-phy.c61
-rw-r--r--roms/u-boot/drivers/phy/omap-usb2-phy.c266
-rw-r--r--roms/u-boot/drivers/phy/phy-bcm-sr-pcie.c177
-rw-r--r--roms/u-boot/drivers/phy/phy-core-mipi-dphy.c161
-rw-r--r--roms/u-boot/drivers/phy/phy-da8xx-usb.c65
-rw-r--r--roms/u-boot/drivers/phy/phy-mtk-tphy.c753
-rw-r--r--roms/u-boot/drivers/phy/phy-qcom-ipq4019-usb.c145
-rw-r--r--roms/u-boot/drivers/phy/phy-rcar-gen2.c193
-rw-r--r--roms/u-boot/drivers/phy/phy-rcar-gen3.c162
-rw-r--r--roms/u-boot/drivers/phy/phy-stm32-usbphyc.c425
-rw-r--r--roms/u-boot/drivers/phy/phy-ti-am654.c416
-rw-r--r--roms/u-boot/drivers/phy/phy-uclass.c317
-rw-r--r--roms/u-boot/drivers/phy/rockchip/Kconfig37
-rw-r--r--roms/u-boot/drivers/phy/rockchip/Makefile9
-rw-r--r--roms/u-boot/drivers/phy/rockchip/phy-rockchip-inno-usb2.c313
-rw-r--r--roms/u-boot/drivers/phy/rockchip/phy-rockchip-pcie.c272
-rw-r--r--roms/u-boot/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c157
-rw-r--r--roms/u-boot/drivers/phy/rockchip/phy-rockchip-typec.c797
-rw-r--r--roms/u-boot/drivers/phy/sandbox-phy.c120
-rw-r--r--roms/u-boot/drivers/phy/sti_usb_phy.c182
-rw-r--r--roms/u-boot/drivers/phy/ti-pipe3-phy.c609
50 files changed, 12099 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/phy/Kconfig b/roms/u-boot/drivers/phy/Kconfig
new file mode 100644
index 000000000..008186a10
--- /dev/null
+++ b/roms/u-boot/drivers/phy/Kconfig
@@ -0,0 +1,272 @@
+
+menu "PHY Subsystem"
+
+config PHY
+ bool "PHY Core"
+ depends on DM
+ help
+ PHY support.
+
+ This framework is designed to provide a generic interface for PHY
+ devices. PHY devices are dedicated hardware that handle the physical
+ layer of the protocols in the OSI model.
+ PHYs are commonly used for high speed interfaces such as Serial-ATA
+ or PCI express.
+ The API provides functions to initialize/deinitialize the
+ PHY, power on/off the PHY, and reset the PHY. It's meant to be as
+ compatible as possible with the equivalent framework found in the
+ linux kernel.
+
+config SPL_PHY
+ bool "PHY Core in SPL"
+ depends on DM && SPL
+ help
+ PHY support in SPL.
+
+ This framework is designed to provide a generic interface for PHY
+ devices. PHY devices are dedicated hardware that handle the physical
+ layer of the protocols (https://en.wikipedia.org/wiki/OSI_model).
+ PHYs are commonly used for high speed interfaces such as Serial-ATA
+ or PCI express.
+ The API provides functions to initialize/deinitialize the
+ PHY, power on/off the PHY, and reset the PHY. It's meant to be as
+ compatible as possible with the equivalent framework found in the
+ linux kernel.
+
+config PHY_SANDBOX
+ bool "Sandbox PHY support"
+ depends on SANDBOX
+ depends on PHY
+ help
+ This select a dummy sandbox PHY driver. It used only to implement
+ the unit tests for the phy framework
+
+config NOP_PHY
+ bool "NOP PHY driver"
+ depends on PHY
+ help
+ Support for a no-op PHY driver (stubbed PHY driver).
+
+ This is useful when a driver uses the PHY framework but no real PHY
+ hardware exists.
+
+config SPL_NOP_PHY
+ bool "NOP PHY driver in SPL"
+ depends on SPL_PHY
+ help
+ Support for a no-op PHY driver (stubbed PHY driver) in the SPL.
+
+ This is useful when a driver uses the PHY framework but no real PHY
+ hardware exists.
+
+config MIPI_DPHY_HELPERS
+ bool "MIPI D-PHY support helpers"
+ help
+ Provides a number of helpers a core functions for MIPI D-PHY drivers.
+
+config BCM6318_USBH_PHY
+ bool "BCM6318 USBH PHY support"
+ depends on PHY && ARCH_BMIPS
+ select POWER_DOMAIN
+ help
+ Support for the Broadcom MIPS BCM6318 USBH PHY.
+
+config BCM6348_USBH_PHY
+ bool "BCM6348 USBH PHY support"
+ depends on PHY && ARCH_BMIPS
+ help
+ Support for the Broadcom MIPS BCM6348 USBH PHY.
+
+config BCM6358_USBH_PHY
+ bool "BCM6358 USBH PHY support"
+ depends on PHY && ARCH_BMIPS
+ help
+ Support for the Broadcom MIPS BCM6358 USBH PHY.
+
+config BCM6368_USBH_PHY
+ bool "BCM6368 USBH PHY support"
+ depends on PHY && ARCH_BMIPS
+ help
+ Support for the Broadcom MIPS BCM6368 USBH PHY.
+
+config BCM_SR_PCIE_PHY
+ bool "Broadcom Stingray PCIe PHY driver"
+ depends on PHY
+ help
+ Enable this to support the Broadcom Stingray PCIe PHY
+ If unsure, say N.
+
+config PHY_DA8XX_USB
+ tristate "TI DA8xx USB PHY Driver"
+ depends on PHY && ARCH_DAVINCI
+ help
+ Enable this to support the USB PHY on DA8xx SoCs.
+
+config PIPE3_PHY
+ bool "Support omap's PIPE3 PHY"
+ depends on PHY && ARCH_OMAP2PLUS
+ help
+ Support for the omap PIPE3 phy for sata
+
+ This PHY is found on omap devices supporting SATA such as dra7, am57x
+ and omap5
+
+config SPL_PIPE3_PHY
+ bool "Support omap's PIPE3 PHY in SPL"
+ depends on SPL_PHY && ARCH_OMAP2PLUS
+ help
+ Support for the omap PIPE3 phy for sata in SPL
+
+ This PHY is found on omap devices supporting SATA such as dra7, am57x
+ and omap5
+
+config AM654_PHY
+ tristate "TI AM654 SERDES support"
+ depends on PHY && ARCH_K3
+ select REGMAP
+ select SYSCON
+ help
+ This option enables support for TI AM654 SerDes PHY used for
+ PCIe.
+
+config STI_USB_PHY
+ bool "STMicroelectronics USB2 picoPHY driver for STiH407 family"
+ depends on PHY && ARCH_STI
+ help
+ This is the generic phy driver for the picoPHY ports
+ used by USB2 and USB3 Host controllers available on
+ STiH407 SoC families.
+
+config PHY_QCOM_IPQ4019_USB
+ tristate "Qualcomm IPQ4019 USB PHY driver"
+ depends on PHY && ARCH_IPQ40XX
+ help
+ Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s.
+
+config PHY_RCAR_GEN2
+ tristate "Renesas R-Car Gen2 USB PHY"
+ depends on PHY && RCAR_GEN2
+ help
+ Support for the Renesas R-Car Gen2 USB PHY. This driver operates the
+ PHY connected to USBHS module, PCI EHCI module and USB3.0 module and
+ allows configuring the module multiplexing.
+
+config PHY_RCAR_GEN3
+ tristate "Renesas R-Car Gen3 USB PHY"
+ depends on PHY && RCAR_GEN3 && CLK && DM_REGULATOR
+ default y if RCAR_GEN3
+ help
+ Support for the Renesas R-Car Gen3 USB PHY. This driver operates the
+ PHY connected to EHCI USB module and controls USB OTG operation.
+
+config PHY_STM32_USBPHYC
+ tristate "STMicroelectronics STM32 SoC USB HS PHY driver"
+ depends on PHY && ARCH_STM32MP
+ help
+ Enable this to support the High-Speed USB transceiver that is part of
+ STMicroelectronics STM32 SoCs.
+
+ This driver controls the entire USB PHY block: the USB PHY controller
+ (USBPHYC) and the two 8-bit wide UTMI+ interface. First interface is
+ used by an HS USB Host controller, and the second one is shared
+ between an HS USB OTG controller and an HS USB Host controller,
+ selected by an USB switch.
+
+config MESON_GXBB_USB_PHY
+ bool "Amlogic Meson GXBB USB PHY"
+ depends on PHY && ARCH_MESON && MESON_GXBB
+ imply REGMAP
+ help
+ This is the generic phy driver for the Amlogic Meson GXBB
+ USB2 PHY.
+
+config MESON_GXL_USB_PHY
+ bool "Amlogic Meson GXL USB PHYs"
+ depends on PHY && ARCH_MESON && (MESON_GXL || MESON_GXM || MESON_AXG)
+ imply REGMAP
+ help
+ This is the generic phy driver for the Amlogic Meson GXL
+ USB2 and USB3 PHYS.
+
+config MESON_G12A_USB_PHY
+ bool "Amlogic Meson G12A USB PHYs"
+ depends on PHY && ARCH_MESON && MESON_G12A
+ imply REGMAP
+ help
+ This is the generic phy driver for the Amlogic Meson G12A
+ USB2 and USB3 PHYS.
+
+config MESON_AXG_MIPI_DPHY
+ bool "Amlogic Meson AXG MIPI D-PHY"
+ depends on PHY && ARCH_MESON && MESON_AXG
+ select MIPI_DPHY_HELPERS
+ imply REGMAP
+ help
+ This is the generic phy driver for the Amlogic Meson AXG
+ MIPI D-PHY.
+
+config MESON_AXG_MIPI_PCIE_ANALOG_PHY
+ bool "Amlogic Meson AXG MIPI PCIe Analog PHY"
+ depends on PHY && ARCH_MESON && MESON_AXG
+ select MIPI_DPHY_HELPERS
+ imply REGMAP
+ help
+ This is the generic phy driver for the Amlogic Meson AXG
+ MIPI PCIe Analog PHY.
+
+config MSM8916_USB_PHY
+ bool "Qualcomm MSM8916 USB PHY support"
+ depends on PHY
+ help
+ Support the USB PHY in msm8916
+
+ This PHY is found on qualcomm dragonboard410c development board.
+
+config OMAP_USB2_PHY
+ bool "Support OMAP's USB2 PHY"
+ depends on PHY
+ depends on SYSCON
+ help
+ Support for the OMAP's USB2 PHY.
+
+ This PHY is found on OMAP devices supporting USB2.
+
+
+config KEYSTONE_USB_PHY
+ bool "Support TI Keystone USB PHY"
+ depends on PHY
+ depends on ARCH_KEYSTONE
+ help
+ Support for the USB PHY found on some Keystone (k2) processors
+
+ This PHY is found on some Keystone (K2) devices supporting USB.
+
+config MT7620_USB_PHY
+ bool "MediaTek MT7620 USB PHY support"
+ depends on PHY
+ depends on SOC_MT7620
+ help
+ Support the intergated USB PHY in MediaTek MT7620 SoC
+
+config MT76X8_USB_PHY
+ bool "MediaTek MT76x8 (7628/88) USB PHY support"
+ depends on PHY
+ depends on SOC_MT7628
+ help
+ Support the USB PHY in MT76x8 SoCs
+
+ This PHY is found on MT76x8 devices supporting USB.
+
+config PHY_MTK_TPHY
+ bool "MediaTek T-PHY Driver"
+ depends on PHY
+ depends on ARCH_MEDIATEK
+ help
+ MediaTek T-PHY driver supports usb2.0, usb3.0 ports, PCIe and
+ SATA, and meanwhile supports two version T-PHY which have
+ different banks layout, the T-PHY with shared banks between
+ multi-ports is first version, otherwise is second veriosn,
+ so you can easily distinguish them by banks layout.
+
+source "drivers/phy/rockchip/Kconfig"
+endmenu
diff --git a/roms/u-boot/drivers/phy/Makefile b/roms/u-boot/drivers/phy/Makefile
new file mode 100644
index 000000000..3c4a673a8
--- /dev/null
+++ b/roms/u-boot/drivers/phy/Makefile
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+# Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+
+obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o
+obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o
+obj-$(CONFIG_MIPI_DPHY_HELPERS) += phy-core-mipi-dphy.o
+obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o
+obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o
+obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o
+obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o
+obj-$(CONFIG_BCM_SR_PCIE_PHY) += phy-bcm-sr-pcie.o
+obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o
+obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o
+obj-$(CONFIG_AM654_PHY) += phy-ti-am654.o
+obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o
+obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
+obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
+obj-$(CONFIG_PHY_RCAR_GEN3) += phy-rcar-gen3.o
+obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o
+obj-$(CONFIG_MESON_GXBB_USB_PHY) += meson-gxbb-usb2.o
+obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o
+obj-$(CONFIG_MESON_G12A_USB_PHY) += meson-g12a-usb2.o meson-g12a-usb3-pcie.o
+obj-$(CONFIG_MESON_AXG_MIPI_DPHY) += meson-axg-mipi-dphy.o
+obj-$(CONFIG_MESON_AXG_MIPI_PCIE_ANALOG_PHY) += meson-axg-mipi-pcie-analog.o
+obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o
+obj-$(CONFIG_OMAP_USB2_PHY) += omap-usb2-phy.o
+obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o
+obj-$(CONFIG_MT7620_USB_PHY) += mt7620-usb-phy.o
+obj-$(CONFIG_MT76X8_USB_PHY) += mt76x8-usb-phy.o
+obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
+obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
diff --git a/roms/u-boot/drivers/phy/allwinner/Kconfig b/roms/u-boot/drivers/phy/allwinner/Kconfig
new file mode 100644
index 000000000..dba3bae61
--- /dev/null
+++ b/roms/u-boot/drivers/phy/allwinner/Kconfig
@@ -0,0 +1,13 @@
+#
+# Phy drivers for Allwinner platforms
+#
+config PHY_SUN4I_USB
+ bool "Allwinner Sun4I USB PHY driver"
+ depends on ARCH_SUNXI
+ select PHY
+ help
+ Enable this to support the transceiver that is part of Allwinner
+ sunxi SoCs.
+
+ This driver controls the entire USB PHY block, both the USB OTG
+ parts, as well as the 2 regular USB 2 host PHYs.
diff --git a/roms/u-boot/drivers/phy/allwinner/Makefile b/roms/u-boot/drivers/phy/allwinner/Makefile
new file mode 100644
index 000000000..e709fca64
--- /dev/null
+++ b/roms/u-boot/drivers/phy/allwinner/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2016 Amarula Solutions
+#
+
+obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
diff --git a/roms/u-boot/drivers/phy/allwinner/phy-sun4i-usb.c b/roms/u-boot/drivers/phy/allwinner/phy-sun4i-usb.c
new file mode 100644
index 000000000..5723c9803
--- /dev/null
+++ b/roms/u-boot/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -0,0 +1,651 @@
+/*
+ * Allwinner sun4i USB PHY driver
+ *
+ * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com>
+ * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
+ * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com>
+ *
+ * Modelled arch/arm/mach-sunxi/usb_phy.c to compatible with generic-phy.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device.h>
+#include <generic-phy.h>
+#include <phy-sun4i-usb.h>
+#include <reset.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/cpu.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#define REG_ISCR 0x00
+#define REG_PHYCTL_A10 0x04
+#define REG_PHYBIST 0x08
+#define REG_PHYTUNE 0x0c
+#define REG_PHYCTL_A33 0x10
+#define REG_PHY_OTGCTL 0x20
+#define REG_PMU_UNK1 0x10
+
+/* Common Control Bits for Both PHYs */
+#define PHY_PLL_BW 0x03
+#define PHY_RES45_CAL_EN 0x0c
+
+/* Private Control Bits for Each PHY */
+#define PHY_TX_AMPLITUDE_TUNE 0x20
+#define PHY_TX_SLEWRATE_TUNE 0x22
+#define PHY_DISCON_TH_SEL 0x2a
+#define PHY_SQUELCH_DETECT 0x3c
+
+#define PHYCTL_DATA BIT(7)
+#define OTGCTL_ROUTE_MUSB BIT(0)
+
+#define PHY_TX_RATE BIT(4)
+#define PHY_TX_MAGNITUDE BIT(2)
+#define PHY_TX_AMPLITUDE_LEN 5
+
+#define PHY_RES45_CAL_DATA BIT(0)
+#define PHY_RES45_CAL_LEN 1
+#define PHY_DISCON_TH_LEN 2
+
+#define SUNXI_AHB_ICHR8_EN BIT(10)
+#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
+#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
+#define SUNXI_ULPI_BYPASS_EN BIT(0)
+
+/* A83T specific control bits for PHY0 */
+#define PHY_CTL_VBUSVLDEXT BIT(5)
+#define PHY_CTL_SIDDQ BIT(3)
+
+/* A83T specific control bits for PHY2 HSIC */
+#define SUNXI_EHCI_HS_FORCE BIT(20)
+#define SUNXI_HSIC_CONNECT_INT BIT(16)
+#define SUNXI_HSIC BIT(1)
+
+#define MAX_PHYS 4
+
+enum sun4i_usb_phy_type {
+ sun4i_a10_phy,
+ sun6i_a31_phy,
+ sun8i_a33_phy,
+ sun8i_a83t_phy,
+ sun8i_h3_phy,
+ sun8i_r40_phy,
+ sun8i_v3s_phy,
+ sun50i_a64_phy,
+ sun50i_h6_phy,
+};
+
+struct sun4i_usb_phy_cfg {
+ int num_phys;
+ enum sun4i_usb_phy_type type;
+ u32 disc_thresh;
+ u8 phyctl_offset;
+ bool dedicated_clocks;
+ bool enable_pmu_unk1;
+ bool phy0_dual_route;
+ int missing_phys;
+};
+
+struct sun4i_usb_phy_info {
+ const char *gpio_vbus;
+ const char *gpio_vbus_det;
+ const char *gpio_id_det;
+} phy_info[] = {
+ {
+ .gpio_vbus = CONFIG_USB0_VBUS_PIN,
+ .gpio_vbus_det = CONFIG_USB0_VBUS_DET,
+ .gpio_id_det = CONFIG_USB0_ID_DET,
+ },
+ {
+ .gpio_vbus = CONFIG_USB1_VBUS_PIN,
+ .gpio_vbus_det = NULL,
+ .gpio_id_det = NULL,
+ },
+ {
+ .gpio_vbus = CONFIG_USB2_VBUS_PIN,
+ .gpio_vbus_det = NULL,
+ .gpio_id_det = NULL,
+ },
+ {
+ .gpio_vbus = CONFIG_USB3_VBUS_PIN,
+ .gpio_vbus_det = NULL,
+ .gpio_id_det = NULL,
+ },
+};
+
+struct sun4i_usb_phy_plat {
+ void __iomem *pmu;
+ int power_on_count;
+ int gpio_vbus;
+ int gpio_vbus_det;
+ int gpio_id_det;
+ struct clk clocks;
+ struct reset_ctl resets;
+ int id;
+};
+
+struct sun4i_usb_phy_data {
+ void __iomem *base;
+ const struct sun4i_usb_phy_cfg *cfg;
+ struct sun4i_usb_phy_plat *usb_phy;
+};
+
+static int initial_usb_scan_delay = CONFIG_INITIAL_USB_SCAN_DELAY;
+
+static void sun4i_usb_phy_write(struct phy *phy, u32 addr, u32 data, int len)
+{
+ struct sun4i_usb_phy_data *phy_data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &phy_data->usb_phy[phy->id];
+ u32 temp, usbc_bit = BIT(usb_phy->id * 2);
+ void __iomem *phyctl = phy_data->base + phy_data->cfg->phyctl_offset;
+ int i;
+
+ if (phy_data->cfg->phyctl_offset == REG_PHYCTL_A33) {
+ /* SoCs newer than A33 need us to set phyctl to 0 explicitly */
+ writel(0, phyctl);
+ }
+
+ for (i = 0; i < len; i++) {
+ temp = readl(phyctl);
+
+ /* clear the address portion */
+ temp &= ~(0xff << 8);
+
+ /* set the address */
+ temp |= ((addr + i) << 8);
+ writel(temp, phyctl);
+
+ /* set the data bit and clear usbc bit*/
+ temp = readb(phyctl);
+ if (data & 0x1)
+ temp |= PHYCTL_DATA;
+ else
+ temp &= ~PHYCTL_DATA;
+ temp &= ~usbc_bit;
+ writeb(temp, phyctl);
+
+ /* pulse usbc_bit */
+ temp = readb(phyctl);
+ temp |= usbc_bit;
+ writeb(temp, phyctl);
+
+ temp = readb(phyctl);
+ temp &= ~usbc_bit;
+ writeb(temp, phyctl);
+
+ data >>= 1;
+ }
+}
+
+static void sun4i_usb_phy_passby(struct phy *phy, bool enable)
+{
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+ u32 bits, reg_value;
+
+ if (!usb_phy->pmu)
+ return;
+
+ bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
+ SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
+
+ /* A83T USB2 is HSIC */
+ if (data->cfg->type == sun8i_a83t_phy && usb_phy->id == 2)
+ bits |= SUNXI_EHCI_HS_FORCE | SUNXI_HSIC_CONNECT_INT |
+ SUNXI_HSIC;
+
+ reg_value = readl(usb_phy->pmu);
+
+ if (enable)
+ reg_value |= bits;
+ else
+ reg_value &= ~bits;
+
+ writel(reg_value, usb_phy->pmu);
+}
+
+static int sun4i_usb_phy_power_on(struct phy *phy)
+{
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+
+ if (initial_usb_scan_delay) {
+ mdelay(initial_usb_scan_delay);
+ initial_usb_scan_delay = 0;
+ }
+
+ usb_phy->power_on_count++;
+ if (usb_phy->power_on_count != 1)
+ return 0;
+
+ if (usb_phy->gpio_vbus >= 0)
+ gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_UP);
+
+ return 0;
+}
+
+static int sun4i_usb_phy_power_off(struct phy *phy)
+{
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+
+ usb_phy->power_on_count--;
+ if (usb_phy->power_on_count != 0)
+ return 0;
+
+ if (usb_phy->gpio_vbus >= 0)
+ gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_DISABLE);
+
+ return 0;
+}
+
+static void sun4i_usb_phy0_reroute(struct sun4i_usb_phy_data *data, bool id_det)
+{
+ u32 regval;
+
+ regval = readl(data->base + REG_PHY_OTGCTL);
+ if (!id_det) {
+ /* Host mode. Route phy0 to EHCI/OHCI */
+ regval &= ~OTGCTL_ROUTE_MUSB;
+ } else {
+ /* Peripheral mode. Route phy0 to MUSB */
+ regval |= OTGCTL_ROUTE_MUSB;
+ }
+ writel(regval, data->base + REG_PHY_OTGCTL);
+}
+
+static int sun4i_usb_phy_init(struct phy *phy)
+{
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+ u32 val;
+ int ret;
+
+ ret = clk_enable(&usb_phy->clocks);
+ if (ret) {
+ dev_err(phy->dev, "failed to enable usb_%ldphy clock\n",
+ phy->id);
+ return ret;
+ }
+
+ ret = reset_deassert(&usb_phy->resets);
+ if (ret) {
+ dev_err(phy->dev, "failed to deassert usb_%ldreset reset\n",
+ phy->id);
+ return ret;
+ }
+
+ if (data->cfg->type == sun8i_a83t_phy ||
+ data->cfg->type == sun50i_h6_phy) {
+ if (phy->id == 0) {
+ val = readl(data->base + data->cfg->phyctl_offset);
+ val |= PHY_CTL_VBUSVLDEXT;
+ val &= ~PHY_CTL_SIDDQ;
+ writel(val, data->base + data->cfg->phyctl_offset);
+ }
+ } else {
+ if (usb_phy->pmu && data->cfg->enable_pmu_unk1) {
+ val = readl(usb_phy->pmu + REG_PMU_UNK1);
+ writel(val & ~2, usb_phy->pmu + REG_PMU_UNK1);
+ }
+
+ if (usb_phy->id == 0)
+ sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN,
+ PHY_RES45_CAL_DATA,
+ PHY_RES45_CAL_LEN);
+
+ /* Adjust PHY's magnitude and rate */
+ sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE,
+ PHY_TX_MAGNITUDE | PHY_TX_RATE,
+ PHY_TX_AMPLITUDE_LEN);
+
+ /* Disconnect threshold adjustment */
+ sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
+ data->cfg->disc_thresh, PHY_DISCON_TH_LEN);
+ }
+
+ sun4i_usb_phy_passby(phy, true);
+
+ sun4i_usb_phy0_reroute(data, true);
+
+ return 0;
+}
+
+static int sun4i_usb_phy_exit(struct phy *phy)
+{
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+ int ret;
+
+ if (phy->id == 0) {
+ if (data->cfg->type == sun8i_a83t_phy ||
+ data->cfg->type == sun50i_h6_phy) {
+ void __iomem *phyctl = data->base +
+ data->cfg->phyctl_offset;
+
+ writel(readl(phyctl) | PHY_CTL_SIDDQ, phyctl);
+ }
+ }
+
+ sun4i_usb_phy_passby(phy, false);
+
+ ret = clk_disable(&usb_phy->clocks);
+ if (ret) {
+ dev_err(phy->dev, "failed to disable usb_%ldphy clock\n",
+ phy->id);
+ return ret;
+ }
+
+ ret = reset_assert(&usb_phy->resets);
+ if (ret) {
+ dev_err(phy->dev, "failed to assert usb_%ldreset reset\n",
+ phy->id);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sun4i_usb_phy_xlate(struct phy *phy,
+ struct ofnode_phandle_args *args)
+{
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+
+ if (args->args_count >= data->cfg->num_phys)
+ return -EINVAL;
+
+ if (data->cfg->missing_phys & BIT(args->args[0]))
+ return -ENODEV;
+
+ if (args->args_count)
+ phy->id = args->args[0];
+ else
+ phy->id = 0;
+
+ debug("%s: phy_id = %ld\n", __func__, phy->id);
+ return 0;
+}
+
+int sun4i_usb_phy_vbus_detect(struct phy *phy)
+{
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+ int err, retries = 3;
+
+ debug("%s: id_det = %d\n", __func__, usb_phy->gpio_id_det);
+
+ if (usb_phy->gpio_vbus_det < 0)
+ return usb_phy->gpio_vbus_det;
+
+ err = gpio_get_value(usb_phy->gpio_vbus_det);
+ /*
+ * Vbus may have been provided by the board and just been turned of
+ * some milliseconds ago on reset, what we're measuring then is a
+ * residual charge on Vbus, sleep a bit and try again.
+ */
+ while (err > 0 && retries--) {
+ mdelay(100);
+ err = gpio_get_value(usb_phy->gpio_vbus_det);
+ }
+
+ return err;
+}
+
+int sun4i_usb_phy_id_detect(struct phy *phy)
+{
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+
+ debug("%s: id_det = %d\n", __func__, usb_phy->gpio_id_det);
+
+ if (usb_phy->gpio_id_det < 0)
+ return usb_phy->gpio_id_det;
+
+ return gpio_get_value(usb_phy->gpio_id_det);
+}
+
+void sun4i_usb_phy_set_squelch_detect(struct phy *phy, bool enabled)
+{
+ sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
+}
+
+static struct phy_ops sun4i_usb_phy_ops = {
+ .of_xlate = sun4i_usb_phy_xlate,
+ .init = sun4i_usb_phy_init,
+ .power_on = sun4i_usb_phy_power_on,
+ .power_off = sun4i_usb_phy_power_off,
+ .exit = sun4i_usb_phy_exit,
+};
+
+static int sun4i_usb_phy_probe(struct udevice *dev)
+{
+ struct sun4i_usb_phy_plat *plat = dev_get_plat(dev);
+ struct sun4i_usb_phy_data *data = dev_get_priv(dev);
+ int i, ret;
+
+ data->cfg = (const struct sun4i_usb_phy_cfg *)dev_get_driver_data(dev);
+ if (!data->cfg)
+ return -EINVAL;
+
+ data->base = (void __iomem *)devfdt_get_addr_name(dev, "phy_ctrl");
+ if (IS_ERR(data->base))
+ return PTR_ERR(data->base);
+
+ data->usb_phy = plat;
+ for (i = 0; i < data->cfg->num_phys; i++) {
+ struct sun4i_usb_phy_plat *phy = &plat[i];
+ struct sun4i_usb_phy_info *info = &phy_info[i];
+ char name[16];
+
+ if (data->cfg->missing_phys & BIT(i))
+ continue;
+
+ phy->gpio_vbus = sunxi_name_to_gpio(info->gpio_vbus);
+ if (phy->gpio_vbus >= 0) {
+ ret = gpio_request(phy->gpio_vbus, "usb_vbus");
+ if (ret)
+ return ret;
+ ret = gpio_direction_output(phy->gpio_vbus, 0);
+ if (ret)
+ return ret;
+ }
+
+ phy->gpio_vbus_det = sunxi_name_to_gpio(info->gpio_vbus_det);
+ if (phy->gpio_vbus_det >= 0) {
+ ret = gpio_request(phy->gpio_vbus_det, "usb_vbus_det");
+ if (ret)
+ return ret;
+ ret = gpio_direction_input(phy->gpio_vbus_det);
+ if (ret)
+ return ret;
+ }
+
+ phy->gpio_id_det = sunxi_name_to_gpio(info->gpio_id_det);
+ if (phy->gpio_id_det >= 0) {
+ ret = gpio_request(phy->gpio_id_det, "usb_id_det");
+ if (ret)
+ return ret;
+ ret = gpio_direction_input(phy->gpio_id_det);
+ if (ret)
+ return ret;
+ sunxi_gpio_set_pull(phy->gpio_id_det, SUNXI_GPIO_PULL_UP);
+ }
+
+ if (data->cfg->dedicated_clocks)
+ snprintf(name, sizeof(name), "usb%d_phy", i);
+ else
+ strlcpy(name, "usb_phy", sizeof(name));
+
+ ret = clk_get_by_name(dev, name, &phy->clocks);
+ if (ret) {
+ dev_err(dev, "failed to get usb%d_phy clock phandle\n", i);
+ return ret;
+ }
+
+ snprintf(name, sizeof(name), "usb%d_reset", i);
+ ret = reset_get_by_name(dev, name, &phy->resets);
+ if (ret) {
+ dev_err(dev, "failed to get usb%d_reset reset phandle\n", i);
+ return ret;
+ }
+
+ if (i || data->cfg->phy0_dual_route) {
+ snprintf(name, sizeof(name), "pmu%d", i);
+ phy->pmu = (void __iomem *)devfdt_get_addr_name(dev, name);
+ if (IS_ERR(phy->pmu))
+ return PTR_ERR(phy->pmu);
+ }
+
+ phy->id = i;
+ };
+
+ debug("Allwinner Sun4I USB PHY driver loaded\n");
+ return 0;
+}
+
+static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
+ .num_phys = 3,
+ .type = sun4i_a10_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = false,
+ .enable_pmu_unk1 = false,
+};
+
+static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
+ .num_phys = 2,
+ .type = sun4i_a10_phy,
+ .disc_thresh = 2,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = false,
+ .enable_pmu_unk1 = false,
+};
+
+static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
+ .num_phys = 3,
+ .type = sun6i_a31_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = true,
+ .enable_pmu_unk1 = false,
+};
+
+static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
+ .num_phys = 3,
+ .type = sun4i_a10_phy,
+ .disc_thresh = 2,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = false,
+ .enable_pmu_unk1 = false,
+};
+
+static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
+ .num_phys = 2,
+ .type = sun4i_a10_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = true,
+ .enable_pmu_unk1 = false,
+};
+
+static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
+ .num_phys = 2,
+ .type = sun8i_a33_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
+ .enable_pmu_unk1 = false,
+};
+
+static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = {
+ .num_phys = 3,
+ .type = sun8i_a83t_phy,
+ .phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
+};
+
+static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
+ .num_phys = 4,
+ .type = sun8i_h3_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
+ .enable_pmu_unk1 = true,
+ .phy0_dual_route = true,
+};
+
+static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = {
+ .num_phys = 3,
+ .type = sun8i_r40_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
+ .enable_pmu_unk1 = true,
+ .phy0_dual_route = true,
+};
+
+static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
+ .num_phys = 1,
+ .type = sun8i_v3s_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
+ .enable_pmu_unk1 = true,
+ .phy0_dual_route = true,
+};
+
+static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
+ .num_phys = 2,
+ .type = sun50i_a64_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
+ .enable_pmu_unk1 = true,
+ .phy0_dual_route = true,
+};
+
+static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = {
+ .num_phys = 4,
+ .type = sun50i_h6_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
+ .enable_pmu_unk1 = true,
+ .phy0_dual_route = true,
+ .missing_phys = BIT(1) | BIT(2),
+};
+
+static const struct udevice_id sun4i_usb_phy_ids[] = {
+ { .compatible = "allwinner,sun4i-a10-usb-phy", .data = (ulong)&sun4i_a10_cfg },
+ { .compatible = "allwinner,sun5i-a13-usb-phy", .data = (ulong)&sun5i_a13_cfg },
+ { .compatible = "allwinner,sun6i-a31-usb-phy", .data = (ulong)&sun6i_a31_cfg },
+ { .compatible = "allwinner,sun7i-a20-usb-phy", .data = (ulong)&sun7i_a20_cfg },
+ { .compatible = "allwinner,sun8i-a23-usb-phy", .data = (ulong)&sun8i_a23_cfg },
+ { .compatible = "allwinner,sun8i-a33-usb-phy", .data = (ulong)&sun8i_a33_cfg },
+ { .compatible = "allwinner,sun8i-a83t-usb-phy", .data = (ulong)&sun8i_a83t_cfg },
+ { .compatible = "allwinner,sun8i-h3-usb-phy", .data = (ulong)&sun8i_h3_cfg },
+ { .compatible = "allwinner,sun8i-r40-usb-phy", .data = (ulong)&sun8i_r40_cfg },
+ { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = (ulong)&sun8i_v3s_cfg },
+ { .compatible = "allwinner,sun50i-a64-usb-phy", .data = (ulong)&sun50i_a64_cfg},
+ { .compatible = "allwinner,sun50i-h6-usb-phy", .data = (ulong)&sun50i_h6_cfg},
+ { }
+};
+
+U_BOOT_DRIVER(sun4i_usb_phy) = {
+ .name = "sun4i_usb_phy",
+ .id = UCLASS_PHY,
+ .of_match = sun4i_usb_phy_ids,
+ .ops = &sun4i_usb_phy_ops,
+ .probe = sun4i_usb_phy_probe,
+ .plat_auto = sizeof(struct sun4i_usb_phy_plat[MAX_PHYS]),
+ .priv_auto = sizeof(struct sun4i_usb_phy_data),
+};
diff --git a/roms/u-boot/drivers/phy/bcm6318-usbh-phy.c b/roms/u-boot/drivers/phy/bcm6318-usbh-phy.c
new file mode 100644
index 000000000..60608a55b
--- /dev/null
+++ b/roms/u-boot/drivers/phy/bcm6318-usbh-phy.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/usb-common.c:
+ * Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright 2013 Florian Fainelli <florian@openwrt.org>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+/* USBH Setup register */
+#define USBH_SETUP_REG 0x00
+#define USBH_SETUP_IOC BIT(4)
+
+/* USBH PLL Control register */
+#define USBH_PLL_REG 0x04
+#define USBH_PLL_SUSP_EN BIT(27)
+#define USBH_PLL_IDDQ_PWRDN BIT(31)
+
+/* USBH Swap Control register */
+#define USBH_SWAP_REG 0x0c
+#define USBH_SWAP_OHCI_DATA BIT(0)
+#define USBH_SWAP_OHCI_ENDIAN BIT(1)
+#define USBH_SWAP_EHCI_DATA BIT(3)
+#define USBH_SWAP_EHCI_ENDIAN BIT(4)
+
+/* USBH Sim Control register */
+#define USBH_SIM_REG 0x20
+#define USBH_SIM_LADDR BIT(5)
+
+struct bcm6318_usbh_priv {
+ void __iomem *regs;
+};
+
+static int bcm6318_usbh_init(struct phy *phy)
+{
+ struct bcm6318_usbh_priv *priv = dev_get_priv(phy->dev);
+
+ /* enable pll control susp */
+ setbits_be32(priv->regs + USBH_PLL_REG, USBH_PLL_SUSP_EN);
+
+ /* configure to work in native cpu endian */
+ clrsetbits_be32(priv->regs + USBH_SWAP_REG,
+ USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN,
+ USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA);
+
+ /* setup config */
+ setbits_be32(priv->regs + USBH_SETUP_REG, USBH_SETUP_IOC);
+
+ /* disable pll control pwrdn */
+ clrbits_be32(priv->regs + USBH_PLL_REG, USBH_PLL_IDDQ_PWRDN);
+
+ /* sim control config */
+ setbits_be32(priv->regs + USBH_SIM_REG, USBH_SIM_LADDR);
+
+ return 0;
+}
+
+static struct phy_ops bcm6318_usbh_ops = {
+ .init = bcm6318_usbh_init,
+};
+
+static const struct udevice_id bcm6318_usbh_ids[] = {
+ { .compatible = "brcm,bcm6318-usbh" },
+ { /* sentinel */ }
+};
+
+static int bcm6318_usbh_probe(struct udevice *dev)
+{
+ struct bcm6318_usbh_priv *priv = dev_get_priv(dev);
+ struct power_domain pwr_dom;
+ struct reset_ctl rst_ctl;
+ struct clk clk;
+ int ret;
+
+ priv->regs = dev_remap_addr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ /* enable usbh clock */
+ ret = clk_get_by_name(dev, "usbh", &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_free(&clk);
+ if (ret < 0)
+ return ret;
+
+ /* enable power domain */
+ ret = power_domain_get(dev, &pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_on(&pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_free(&pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ /* perform reset */
+ ret = reset_get_by_index(dev, 0, &rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_deassert(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_free(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ mdelay(100);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bcm6318_usbh) = {
+ .name = "bcm6318-usbh",
+ .id = UCLASS_PHY,
+ .of_match = bcm6318_usbh_ids,
+ .ops = &bcm6318_usbh_ops,
+ .priv_auto = sizeof(struct bcm6318_usbh_priv),
+ .probe = bcm6318_usbh_probe,
+};
diff --git a/roms/u-boot/drivers/phy/bcm6348-usbh-phy.c b/roms/u-boot/drivers/phy/bcm6348-usbh-phy.c
new file mode 100644
index 000000000..1b6b5ad17
--- /dev/null
+++ b/roms/u-boot/drivers/phy/bcm6348-usbh-phy.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/usb-common.c:
+ * Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright 2013 Florian Fainelli <florian@openwrt.org>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device.h>
+#include <linux/bitops.h>
+
+#define USBH_SETUP_PORT1_EN BIT(0)
+
+struct bcm6348_usbh_priv {
+ void __iomem *regs;
+};
+
+static int bcm6348_usbh_init(struct phy *phy)
+{
+ struct bcm6348_usbh_priv *priv = dev_get_priv(phy->dev);
+
+ writel_be(USBH_SETUP_PORT1_EN, priv->regs);
+
+ return 0;
+}
+
+static struct phy_ops bcm6348_usbh_ops = {
+ .init = bcm6348_usbh_init,
+};
+
+static const struct udevice_id bcm6348_usbh_ids[] = {
+ { .compatible = "brcm,bcm6348-usbh" },
+ { /* sentinel */ }
+};
+
+static int bcm6348_usbh_probe(struct udevice *dev)
+{
+ struct bcm6348_usbh_priv *priv = dev_get_priv(dev);
+ struct reset_ctl rst_ctl;
+ struct clk clk;
+ int ret;
+
+ priv->regs = dev_remap_addr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ /* enable usbh clock */
+ ret = clk_get_by_name(dev, "usbh", &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_free(&clk);
+ if (ret < 0)
+ return ret;
+
+ /* perform reset */
+ ret = reset_get_by_index(dev, 0, &rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_deassert(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_free(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_usbh) = {
+ .name = "bcm6348-usbh",
+ .id = UCLASS_PHY,
+ .of_match = bcm6348_usbh_ids,
+ .ops = &bcm6348_usbh_ops,
+ .priv_auto = sizeof(struct bcm6348_usbh_priv),
+ .probe = bcm6348_usbh_probe,
+};
diff --git a/roms/u-boot/drivers/phy/bcm6358-usbh-phy.c b/roms/u-boot/drivers/phy/bcm6358-usbh-phy.c
new file mode 100644
index 000000000..bfdcfb0d2
--- /dev/null
+++ b/roms/u-boot/drivers/phy/bcm6358-usbh-phy.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/usb-common.c:
+ * Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright 2013 Florian Fainelli <florian@openwrt.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device.h>
+#include <linux/bitops.h>
+
+/* USBH Swap Control register */
+#define USBH_SWAP_REG 0x00
+#define USBH_SWAP_OHCI_DATA BIT(0)
+#define USBH_SWAP_OHCI_ENDIAN BIT(1)
+#define USBH_SWAP_EHCI_DATA BIT(3)
+#define USBH_SWAP_EHCI_ENDIAN BIT(4)
+
+/* USBH Test register */
+#define USBH_TEST_REG 0x24
+#define USBH_TEST_PORT_CTL 0x1c0020
+
+struct bcm6358_usbh_priv {
+ void __iomem *regs;
+};
+
+static int bcm6358_usbh_init(struct phy *phy)
+{
+ struct bcm6358_usbh_priv *priv = dev_get_priv(phy->dev);
+
+ /* configure to work in native cpu endian */
+ clrsetbits_be32(priv->regs + USBH_SWAP_REG,
+ USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN,
+ USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA);
+
+ /* test port control */
+ writel_be(USBH_TEST_PORT_CTL, priv->regs + USBH_TEST_REG);
+
+ return 0;
+}
+
+static struct phy_ops bcm6358_usbh_ops = {
+ .init = bcm6358_usbh_init,
+};
+
+static const struct udevice_id bcm6358_usbh_ids[] = {
+ { .compatible = "brcm,bcm6358-usbh" },
+ { /* sentinel */ }
+};
+
+static int bcm6358_usbh_probe(struct udevice *dev)
+{
+ struct bcm6358_usbh_priv *priv = dev_get_priv(dev);
+ struct reset_ctl rst_ctl;
+ int ret;
+
+ priv->regs = dev_remap_addr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ /* perform reset */
+ ret = reset_get_by_index(dev, 0, &rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_deassert(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_free(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bcm6358_usbh) = {
+ .name = "bcm6358-usbh",
+ .id = UCLASS_PHY,
+ .of_match = bcm6358_usbh_ids,
+ .ops = &bcm6358_usbh_ops,
+ .priv_auto = sizeof(struct bcm6358_usbh_priv),
+ .probe = bcm6358_usbh_probe,
+};
diff --git a/roms/u-boot/drivers/phy/bcm6368-usbh-phy.c b/roms/u-boot/drivers/phy/bcm6368-usbh-phy.c
new file mode 100644
index 000000000..4d3a63faa
--- /dev/null
+++ b/roms/u-boot/drivers/phy/bcm6368-usbh-phy.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/usb-common.c:
+ * Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright 2013 Florian Fainelli <florian@openwrt.org>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+/* USBH PLL Control register */
+#define USBH_PLL_REG 0x18
+#define USBH_PLL_IDDQ_PWRDN BIT(9)
+#define USBH_PLL_PWRDN_DELAY BIT(10)
+
+/* USBH Swap Control register */
+#define USBH_SWAP_REG 0x1c
+#define USBH_SWAP_OHCI_DATA BIT(0)
+#define USBH_SWAP_OHCI_ENDIAN BIT(1)
+#define USBH_SWAP_EHCI_DATA BIT(3)
+#define USBH_SWAP_EHCI_ENDIAN BIT(4)
+
+/* USBH Setup register */
+#define USBH_SETUP_REG 0x28
+#define USBH_SETUP_IOC BIT(4)
+#define USBH_SETUP_IPP BIT(5)
+
+struct bcm6368_usbh_hw {
+ uint32_t setup_clr;
+ uint32_t pll_clr;
+};
+
+struct bcm6368_usbh_priv {
+ const struct bcm6368_usbh_hw *hw;
+ void __iomem *regs;
+};
+
+static int bcm6368_usbh_init(struct phy *phy)
+{
+ struct bcm6368_usbh_priv *priv = dev_get_priv(phy->dev);
+ const struct bcm6368_usbh_hw *hw = priv->hw;
+
+ /* configure to work in native cpu endian */
+ clrsetbits_be32(priv->regs + USBH_SWAP_REG,
+ USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN,
+ USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA);
+
+ /* setup config */
+ if (hw->setup_clr)
+ clrbits_be32(priv->regs + USBH_SETUP_REG, hw->setup_clr);
+
+ setbits_be32(priv->regs + USBH_SETUP_REG, USBH_SETUP_IOC);
+
+ /* enable pll control */
+ if (hw->pll_clr)
+ clrbits_be32(priv->regs + USBH_PLL_REG, hw->pll_clr);
+
+ return 0;
+}
+
+static struct phy_ops bcm6368_usbh_ops = {
+ .init = bcm6368_usbh_init,
+};
+
+static const struct bcm6368_usbh_hw bcm6328_hw = {
+ .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY,
+ .setup_clr = 0,
+};
+
+static const struct bcm6368_usbh_hw bcm6362_hw = {
+ .pll_clr = 0,
+ .setup_clr = 0,
+};
+
+static const struct bcm6368_usbh_hw bcm6368_hw = {
+ .pll_clr = 0,
+ .setup_clr = 0,
+};
+
+static const struct bcm6368_usbh_hw bcm63268_hw = {
+ .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY,
+ .setup_clr = USBH_SETUP_IPP,
+};
+
+static const struct udevice_id bcm6368_usbh_ids[] = {
+ {
+ .compatible = "brcm,bcm6328-usbh",
+ .data = (ulong)&bcm6328_hw,
+ }, {
+ .compatible = "brcm,bcm6362-usbh",
+ .data = (ulong)&bcm6362_hw,
+ }, {
+ .compatible = "brcm,bcm6368-usbh",
+ .data = (ulong)&bcm6368_hw,
+ }, {
+ .compatible = "brcm,bcm63268-usbh",
+ .data = (ulong)&bcm63268_hw,
+ }, { /* sentinel */ }
+};
+
+static int bcm6368_usbh_probe(struct udevice *dev)
+{
+ struct bcm6368_usbh_priv *priv = dev_get_priv(dev);
+ const struct bcm6368_usbh_hw *hw =
+ (const struct bcm6368_usbh_hw *)dev_get_driver_data(dev);
+#if defined(CONFIG_POWER_DOMAIN)
+ struct power_domain pwr_dom;
+#endif
+ struct reset_ctl rst_ctl;
+ struct clk clk;
+ int ret;
+
+ priv->regs = dev_remap_addr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ priv->hw = hw;
+
+ /* enable usbh clock */
+ ret = clk_get_by_name(dev, "usbh", &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_free(&clk);
+ if (ret < 0)
+ return ret;
+
+#if defined(CONFIG_POWER_DOMAIN)
+ /* enable power domain */
+ ret = power_domain_get(dev, &pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_on(&pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_free(&pwr_dom);
+ if (ret < 0)
+ return ret;
+#endif
+
+ /* perform reset */
+ ret = reset_get_by_index(dev, 0, &rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_deassert(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_free(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ /* enable usb_ref clock */
+ ret = clk_get_by_name(dev, "usb_ref", &clk);
+ if (!ret) {
+ ret = clk_enable(&clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_free(&clk);
+ if (ret < 0)
+ return ret;
+ }
+
+ mdelay(100);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bcm6368_usbh) = {
+ .name = "bcm6368-usbh",
+ .id = UCLASS_PHY,
+ .of_match = bcm6368_usbh_ids,
+ .ops = &bcm6368_usbh_ops,
+ .priv_auto = sizeof(struct bcm6368_usbh_priv),
+ .probe = bcm6368_usbh_probe,
+};
diff --git a/roms/u-boot/drivers/phy/keystone-usb-phy.c b/roms/u-boot/drivers/phy/keystone-usb-phy.c
new file mode 100644
index 000000000..12f8a265f
--- /dev/null
+++ b/roms/u-boot/drivers/phy/keystone-usb-phy.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <asm/arch/psc_defs.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+/* USB PHY control register offsets */
+#define USB_PHY_CTL_UTMI 0x0000
+#define USB_PHY_CTL_PIPE 0x0004
+#define USB_PHY_CTL_PARAM_1 0x0008
+#define USB_PHY_CTL_PARAM_2 0x000c
+#define USB_PHY_CTL_CLOCK 0x0010
+#define USB_PHY_CTL_PLL 0x0014
+
+#define PHY_OTG_VBUSVLDECTSEL BIT(16)
+#define PHY_REF_SSP_EN BIT(29)
+
+struct keystone_usb_phy {
+ u32 psc_domain;
+ void __iomem *reg;
+};
+
+static int keystone_usb_init(struct phy *phy)
+{
+ u32 val;
+ int rc;
+ struct udevice *dev = phy->dev;
+ struct keystone_usb_phy *keystone = dev_get_priv(dev);
+
+ /* Release USB from reset */
+ rc = psc_enable_module(keystone->psc_domain);
+ if (rc) {
+ debug("Cannot enable USB module");
+ return -rc;
+ }
+ mdelay(10);
+
+ /*
+ * VBUSVLDEXTSEL has a default value of 1 in BootCfg but shouldn't.
+ * It should always be cleared because our USB PHY has an onchip VBUS
+ * analog comparator.
+ */
+ val = readl(keystone->reg + USB_PHY_CTL_CLOCK);
+ /* quit selecting the vbusvldextsel by default! */
+ val &= ~PHY_OTG_VBUSVLDECTSEL;
+ writel(val, keystone->reg + USB_PHY_CTL_CLOCK);
+
+ return 0;
+}
+
+static int keystone_usb_power_on(struct phy *phy)
+{
+ u32 val;
+ struct udevice *dev = phy->dev;
+ struct keystone_usb_phy *keystone = dev_get_priv(dev);
+
+ val = readl(keystone->reg + USB_PHY_CTL_CLOCK);
+ val |= PHY_REF_SSP_EN;
+ writel(val, keystone->reg + USB_PHY_CTL_CLOCK);
+
+ return 0;
+}
+
+static int keystone_usb_power_off(struct phy *phy)
+{
+ u32 val;
+ struct udevice *dev = phy->dev;
+ struct keystone_usb_phy *keystone = dev_get_priv(dev);
+
+ val = readl(keystone->reg + USB_PHY_CTL_CLOCK);
+ val &= ~PHY_REF_SSP_EN;
+ writel(val, keystone->reg + USB_PHY_CTL_CLOCK);
+
+ return 0;
+}
+
+static int keystone_usb_exit(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct keystone_usb_phy *keystone = dev_get_priv(dev);
+
+ if (psc_disable_module(keystone->psc_domain))
+ debug("failed to disable USB module!\n");
+
+ return 0;
+}
+
+static int keystone_usb_phy_probe(struct udevice *dev)
+{
+ int rc;
+ struct keystone_usb_phy *keystone = dev_get_priv(dev);
+
+ rc = dev_read_u32(dev, "psc-domain", &keystone->psc_domain);
+ if (rc)
+ return rc;
+
+ keystone->reg = dev_remap_addr_index(dev, 0);
+ if (!keystone->reg) {
+ pr_err("unable to remap usb phy\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct udevice_id keystone_usb_phy_ids[] = {
+ { .compatible = "ti,keystone-usbphy" },
+ { }
+};
+
+static struct phy_ops keystone_usb_phy_ops = {
+ .init = keystone_usb_init,
+ .power_on = keystone_usb_power_on,
+ .power_off = keystone_usb_power_off,
+ .exit = keystone_usb_exit,
+};
+
+U_BOOT_DRIVER(keystone_usb_phy) = {
+ .name = "keystone_usb_phy",
+ .id = UCLASS_PHY,
+ .of_match = keystone_usb_phy_ids,
+ .ops = &keystone_usb_phy_ops,
+ .probe = keystone_usb_phy_probe,
+ .priv_auto = sizeof(struct keystone_usb_phy),
+};
diff --git a/roms/u-boot/drivers/phy/marvell/Kconfig b/roms/u-boot/drivers/phy/marvell/Kconfig
new file mode 100644
index 000000000..424002840
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/Kconfig
@@ -0,0 +1,9 @@
+config MVEBU_COMPHY_SUPPORT
+ bool "ComPhy SerDes driver"
+ default n
+ help
+ Choose this option to add support
+ for Comphy driver.
+ This driver passes over the lanes
+ and initialize the lane depends on the
+ type and speed.
diff --git a/roms/u-boot/drivers/phy/marvell/Makefile b/roms/u-boot/drivers/phy/marvell/Makefile
new file mode 100644
index 000000000..51be0399e
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_MVEBU_COMPHY_SUPPORT) += comphy_core.o
+obj-$(CONFIG_MVEBU_COMPHY_SUPPORT) += comphy_mux.o
+obj-$(CONFIG_ARMADA_3700) += comphy_a3700.o
+obj-$(CONFIG_ARMADA_8K) += comphy_cp110.o
diff --git a/roms/u-boot/drivers/phy/marvell/comphy_a3700.c b/roms/u-boot/drivers/phy/marvell/comphy_a3700.c
new file mode 100644
index 000000000..06822d1d1
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/comphy_a3700.c
@@ -0,0 +1,1019 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <linux/delay.h>
+
+#include "comphy_a3700.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct comphy_mux_data a3700_comphy_mux_data[] = {
+ /* Lane 0 */
+ {
+ 4,
+ {
+ { COMPHY_TYPE_UNCONNECTED, 0x0 },
+ { COMPHY_TYPE_SGMII1, 0x0 },
+ { COMPHY_TYPE_USB3_HOST0, 0x1 },
+ { COMPHY_TYPE_USB3_DEVICE, 0x1 }
+ }
+ },
+ /* Lane 1 */
+ {
+ 3,
+ {
+ { COMPHY_TYPE_UNCONNECTED, 0x0},
+ { COMPHY_TYPE_SGMII0, 0x0},
+ { COMPHY_TYPE_PEX0, 0x1}
+ }
+ },
+ /* Lane 2 */
+ {
+ 4,
+ {
+ { COMPHY_TYPE_UNCONNECTED, 0x0},
+ { COMPHY_TYPE_SATA0, 0x0},
+ { COMPHY_TYPE_USB3_HOST0, 0x1},
+ { COMPHY_TYPE_USB3_DEVICE, 0x1}
+ }
+ },
+};
+
+struct sgmii_phy_init_data_fix {
+ u16 addr;
+ u16 value;
+};
+
+/* Changes to 40M1G25 mode data required for running 40M3G125 init mode */
+static struct sgmii_phy_init_data_fix sgmii_phy_init_fix[] = {
+ {0x005, 0x07CC}, {0x015, 0x0000}, {0x01B, 0x0000}, {0x01D, 0x0000},
+ {0x01E, 0x0000}, {0x01F, 0x0000}, {0x020, 0x0000}, {0x021, 0x0030},
+ {0x026, 0x0888}, {0x04D, 0x0152}, {0x04F, 0xA020}, {0x050, 0x07CC},
+ {0x053, 0xE9CA}, {0x055, 0xBD97}, {0x071, 0x3015}, {0x076, 0x03AA},
+ {0x07C, 0x0FDF}, {0x0C2, 0x3030}, {0x0C3, 0x8000}, {0x0E2, 0x5550},
+ {0x0E3, 0x12A4}, {0x0E4, 0x7D00}, {0x0E6, 0x0C83}, {0x101, 0xFCC0},
+ {0x104, 0x0C10}
+};
+
+/* 40M1G25 mode init data */
+static u16 sgmii_phy_init[512] = {
+ /* 0 1 2 3 4 5 6 7 */
+ /*-----------------------------------------------------------*/
+ /* 8 9 A B C D E F */
+ 0x3110, 0xFD83, 0x6430, 0x412F, 0x82C0, 0x06FA, 0x4500, 0x6D26, /* 00 */
+ 0xAFC0, 0x8000, 0xC000, 0x0000, 0x2000, 0x49CC, 0x0BC9, 0x2A52, /* 08 */
+ 0x0BD2, 0x0CDE, 0x13D2, 0x0CE8, 0x1149, 0x10E0, 0x0000, 0x0000, /* 10 */
+ 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x4134, 0x0D2D, 0xFFFF, /* 18 */
+ 0xFFE0, 0x4030, 0x1016, 0x0030, 0x0000, 0x0800, 0x0866, 0x0000, /* 20 */
+ 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, /* 28 */
+ 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */
+ 0x0000, 0x0000, 0x000F, 0x6A62, 0x1988, 0x3100, 0x3100, 0x3100, /* 38 */
+ 0x3100, 0xA708, 0x2430, 0x0830, 0x1030, 0x4610, 0xFF00, 0xFF00, /* 40 */
+ 0x0060, 0x1000, 0x0400, 0x0040, 0x00F0, 0x0155, 0x1100, 0xA02A, /* 48 */
+ 0x06FA, 0x0080, 0xB008, 0xE3ED, 0x5002, 0xB592, 0x7A80, 0x0001, /* 50 */
+ 0x020A, 0x8820, 0x6014, 0x8054, 0xACAA, 0xFC88, 0x2A02, 0x45CF, /* 58 */
+ 0x000F, 0x1817, 0x2860, 0x064F, 0x0000, 0x0204, 0x1800, 0x6000, /* 60 */
+ 0x810F, 0x4F23, 0x4000, 0x4498, 0x0850, 0x0000, 0x000E, 0x1002, /* 68 */
+ 0x9D3A, 0x3009, 0xD066, 0x0491, 0x0001, 0x6AB0, 0x0399, 0x3780, /* 70 */
+ 0x0040, 0x5AC0, 0x4A80, 0x0000, 0x01DF, 0x0000, 0x0007, 0x0000, /* 78 */
+ 0x2D54, 0x00A1, 0x4000, 0x0100, 0xA20A, 0x0000, 0x0000, 0x0000, /* 80 */
+ 0x0000, 0x0000, 0x0000, 0x7400, 0x0E81, 0x1000, 0x1242, 0x0210, /* 88 */
+ 0x80DF, 0x0F1F, 0x2F3F, 0x4F5F, 0x6F7F, 0x0F1F, 0x2F3F, 0x4F5F, /* 90 */
+ 0x6F7F, 0x4BAD, 0x0000, 0x0000, 0x0800, 0x0000, 0x2400, 0xB651, /* 98 */
+ 0xC9E0, 0x4247, 0x0A24, 0x0000, 0xAF19, 0x1004, 0x0000, 0x0000, /* A0 */
+ 0x0000, 0x0013, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* A8 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* B0 */
+ 0x0000, 0x0000, 0x0000, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000, /* B8 */
+ 0x0000, 0x0000, 0x3010, 0xFA00, 0x0000, 0x0000, 0x0000, 0x0003, /* C0 */
+ 0x1618, 0x8200, 0x8000, 0x0400, 0x050F, 0x0000, 0x0000, 0x0000, /* C8 */
+ 0x4C93, 0x0000, 0x1000, 0x1120, 0x0010, 0x1242, 0x1242, 0x1E00, /* D0 */
+ 0x0000, 0x0000, 0x0000, 0x00F8, 0x0000, 0x0041, 0x0800, 0x0000, /* D8 */
+ 0x82A0, 0x572E, 0x2490, 0x14A9, 0x4E00, 0x0000, 0x0803, 0x0541, /* E0 */
+ 0x0C15, 0x0000, 0x0000, 0x0400, 0x2626, 0x0000, 0x0000, 0x4200, /* E8 */
+ 0x0000, 0xAA55, 0x1020, 0x0000, 0x0000, 0x5010, 0x0000, 0x0000, /* F0 */
+ 0x0000, 0x0000, 0x5000, 0x0000, 0x0000, 0x0000, 0x02F2, 0x0000, /* F8 */
+ 0x101F, 0xFDC0, 0x4000, 0x8010, 0x0110, 0x0006, 0x0000, 0x0000, /*100 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*108 */
+ 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04C6, 0x0000, /*110 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*118 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*120 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*128 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*130 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*138 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*140 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*148 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*150 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*158 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*160 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*168 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*170 */
+ 0x0000, 0x0000, 0x0000, 0x00F0, 0x08A2, 0x3112, 0x0A14, 0x0000, /*178 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*180 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*188 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*190 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*198 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A0 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A8 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B0 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B8 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C0 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C8 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D0 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D8 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E0 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E8 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1F0 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 /*1F8 */
+};
+
+/*
+ * comphy_poll_reg
+ *
+ * return: 1 on success, 0 on timeout
+ */
+static u32 comphy_poll_reg(void *addr, u32 val, u32 mask, u8 op_type)
+{
+ u32 rval = 0xDEAD, timeout;
+
+ for (timeout = PLL_LOCK_TIMEOUT; timeout > 0; timeout--) {
+ if (op_type == POLL_16B_REG)
+ rval = readw(addr); /* 16 bit */
+ else
+ rval = readl(addr) ; /* 32 bit */
+
+ if ((rval & mask) == val)
+ return 1;
+
+ udelay(10000);
+ }
+
+ debug("Time out waiting (%p = %#010x)\n", addr, rval);
+ return 0;
+}
+
+/*
+ * comphy_pcie_power_up
+ *
+ * return: 1 if PLL locked (OK), 0 otherwise (FAIL)
+ */
+static int comphy_pcie_power_up(u32 speed, u32 invert)
+{
+ int ret;
+
+ debug_enter();
+
+ /*
+ * 1. Enable max PLL.
+ */
+ reg_set16(phy_addr(PCIE, LANE_CFG1), bf_use_max_pll_rate, 0);
+
+ /*
+ * 2. Select 20 bit SERDES interface.
+ */
+ reg_set16(phy_addr(PCIE, GLOB_CLK_SRC_LO), bf_cfg_sel_20b, 0);
+
+ /*
+ * 3. Force to use reg setting for PCIe mode
+ */
+ reg_set16(phy_addr(PCIE, MISC_REG1), bf_sel_bits_pcie_force, 0);
+
+ /*
+ * 4. Change RX wait
+ */
+ reg_set16(phy_addr(PCIE, PWR_MGM_TIM1), 0x10C, 0xFFFF);
+
+ /*
+ * 5. Enable idle sync
+ */
+ reg_set16(phy_addr(PCIE, UNIT_CTRL), 0x60 | rb_idle_sync_en, 0xFFFF);
+
+ /*
+ * 6. Enable the output of 100M/125M/500M clock
+ */
+ reg_set16(phy_addr(PCIE, MISC_REG0),
+ 0xA00D | rb_clk500m_en | rb_clk100m_125m_en, 0xFFFF);
+
+ /*
+ * 7. Enable TX
+ */
+ reg_set(PCIE_REF_CLK_ADDR, 0x1342, 0xFFFFFFFF);
+
+ /*
+ * 8. Check crystal jumper setting and program the Power and PLL
+ * Control accordingly
+ */
+ if (get_ref_clk() == 40) {
+ /* 40 MHz */
+ reg_set16(phy_addr(PCIE, PWR_PLL_CTRL), 0xFC63, 0xFFFF);
+ } else {
+ /* 25 MHz */
+ reg_set16(phy_addr(PCIE, PWR_PLL_CTRL), 0xFC62, 0xFFFF);
+ }
+
+ /*
+ * 9. Override Speed_PLL value and use MAC PLL
+ */
+ reg_set16(phy_addr(PCIE, KVCO_CAL_CTRL), 0x0040 | rb_use_max_pll_rate,
+ 0xFFFF);
+
+ /*
+ * 10. Check the Polarity invert bit
+ */
+ if (invert & COMPHY_POLARITY_TXD_INVERT)
+ reg_set16(phy_addr(PCIE, SYNC_PATTERN), phy_txd_inv, 0);
+
+ if (invert & COMPHY_POLARITY_RXD_INVERT)
+ reg_set16(phy_addr(PCIE, SYNC_PATTERN), phy_rxd_inv, 0);
+
+ /*
+ * 11. Release SW reset
+ */
+ reg_set16(phy_addr(PCIE, GLOB_PHY_CTRL0),
+ rb_mode_core_clk_freq_sel | rb_mode_pipe_width_32,
+ bf_soft_rst | bf_mode_refdiv);
+
+ /* Wait for > 55 us to allow PCLK be enabled */
+ udelay(PLL_SET_DELAY_US);
+
+ /* Assert PCLK enabled */
+ ret = comphy_poll_reg(phy_addr(PCIE, LANE_STAT1), /* address */
+ rb_txdclk_pclk_en, /* value */
+ rb_txdclk_pclk_en, /* mask */
+ POLL_16B_REG); /* 16bit */
+ if (!ret)
+ printf("Failed to lock PCIe PLL\n");
+
+ debug_exit();
+
+ /* Return the status of the PLL */
+ return ret;
+}
+
+/*
+ * reg_set_indirect
+ *
+ * return: void
+ */
+static void reg_set_indirect(u32 reg, u16 data, u16 mask)
+{
+ reg_set(rh_vsreg_addr, reg, 0xFFFFFFFF);
+ reg_set(rh_vsreg_data, data, mask);
+}
+
+/*
+ * comphy_sata_power_up
+ *
+ * return: 1 if PLL locked (OK), 0 otherwise (FAIL)
+ */
+static int comphy_sata_power_up(u32 invert)
+{
+ int ret;
+ u32 data = 0;
+
+ debug_enter();
+
+ /*
+ * 0. Check the Polarity invert bits
+ */
+ if (invert & COMPHY_POLARITY_TXD_INVERT)
+ data |= bs_txd_inv;
+
+ if (invert & COMPHY_POLARITY_RXD_INVERT)
+ data |= bs_rxd_inv;
+
+ reg_set_indirect(vphy_sync_pattern_reg, data, bs_txd_inv | bs_rxd_inv);
+
+ /*
+ * 1. Select 40-bit data width width
+ */
+ reg_set_indirect(vphy_loopback_reg0, 0x800, bs_phyintf_40bit);
+
+ /*
+ * 2. Select reference clock and PHY mode (SATA)
+ */
+ if (get_ref_clk() == 40) {
+ /* 40 MHz */
+ reg_set_indirect(vphy_power_reg0, 0x3, 0x00FF);
+ } else {
+ /* 20 MHz */
+ reg_set_indirect(vphy_power_reg0, 0x1, 0x00FF);
+ }
+
+ /*
+ * 3. Use maximum PLL rate (no power save)
+ */
+ reg_set_indirect(vphy_calctl_reg, bs_max_pll_rate, bs_max_pll_rate);
+
+ /*
+ * 4. Reset reserved bit (??)
+ */
+ reg_set_indirect(vphy_reserve_reg, 0, bs_phyctrl_frm_pin);
+
+ /*
+ * 5. Set vendor-specific configuration (??)
+ */
+ reg_set(rh_vs0_a, vsata_ctrl_reg, 0xFFFFFFFF);
+ reg_set(rh_vs0_d, bs_phy_pu_pll, bs_phy_pu_pll);
+
+ /* Wait for > 55 us to allow PLL be enabled */
+ udelay(PLL_SET_DELAY_US);
+
+ /* Assert SATA PLL enabled */
+ reg_set(rh_vsreg_addr, vphy_loopback_reg0, 0xFFFFFFFF);
+ ret = comphy_poll_reg(rh_vsreg_data, /* address */
+ bs_pll_ready_tx, /* value */
+ bs_pll_ready_tx, /* mask */
+ POLL_32B_REG); /* 32bit */
+ if (!ret)
+ printf("Failed to lock SATA PLL\n");
+
+ debug_exit();
+
+ return ret;
+}
+
+/*
+ * usb3_reg_set16
+ *
+ * return: void
+ */
+static void usb3_reg_set16(u32 reg, u16 data, u16 mask, u32 lane)
+{
+ /*
+ * When Lane 2 PHY is for USB3, access the PHY registers
+ * through indirect Address and Data registers INDIR_ACC_PHY_ADDR
+ * (RD00E0178h [31:0]) and INDIR_ACC_PHY_DATA (RD00E017Ch [31:0])
+ * within the SATA Host Controller registers, Lane 2 base register
+ * offset is 0x200
+ */
+
+ if (lane == 2)
+ reg_set_indirect(USB3PHY_LANE2_REG_BASE_OFFSET + reg, data,
+ mask);
+ else
+ reg_set16(phy_addr(USB3, reg), data, mask);
+}
+
+/*
+ * comphy_usb3_power_up
+ *
+ * return: 1 if PLL locked (OK), 0 otherwise (FAIL)
+ */
+static int comphy_usb3_power_up(u32 lane, u32 type, u32 speed, u32 invert)
+{
+ int ret;
+
+ debug_enter();
+
+ /*
+ * 1. Power up OTG module
+ */
+ reg_set(USB2_PHY_OTG_CTRL_ADDR, rb_pu_otg, 0);
+
+ /*
+ * 2. Set counter for 100us pulse in USB3 Host and Device
+ * restore default burst size limit (Reference Clock 31:24)
+ */
+ reg_set(USB3_CTRPUL_VAL_REG, 0x8 << 24, rb_usb3_ctr_100ns);
+
+
+ /* 0xd005c300 = 0x1001 */
+ /* set PRD_TXDEEMPH (3.5db de-emph) */
+ usb3_reg_set16(LANE_CFG0, 0x1, 0xFF, lane);
+
+ /*
+ * Set BIT0: enable transmitter in high impedance mode
+ * Set BIT[3:4]: delay 2 clock cycles for HiZ off latency
+ * Set BIT6: Tx detect Rx at HiZ mode
+ * Unset BIT15: set to 0 to set USB3 De-emphasize level to -3.5db
+ * together with bit 0 of COMPHY_REG_LANE_CFG0_ADDR
+ * register
+ */
+ usb3_reg_set16(LANE_CFG1,
+ tx_det_rx_mode | gen2_tx_data_dly_deft
+ | tx_elec_idle_mode_en,
+ prd_txdeemph1_mask | tx_det_rx_mode
+ | gen2_tx_data_dly_mask | tx_elec_idle_mode_en, lane);
+
+ /* 0xd005c310 = 0x93: set Spread Spectrum Clock Enabled */
+ usb3_reg_set16(LANE_CFG4, bf_spread_spectrum_clock_en, 0x80, lane);
+
+ /*
+ * set Override Margining Controls From the MAC: Use margining signals
+ * from lane configuration
+ */
+ usb3_reg_set16(TEST_MODE_CTRL, rb_mode_margin_override, 0xFFFF, lane);
+
+ /* set Lane-to-Lane Bundle Clock Sampling Period = per PCLK cycles */
+ /* set Mode Clock Source = PCLK is generated from REFCLK */
+ usb3_reg_set16(GLOB_CLK_SRC_LO, 0x0, 0xFF, lane);
+
+ /* set G2 Spread Spectrum Clock Amplitude at 4K */
+ usb3_reg_set16(GEN2_SETTINGS_2, g2_tx_ssc_amp, 0xF000, lane);
+
+ /*
+ * unset G3 Spread Spectrum Clock Amplitude & set G3 TX and RX Register
+ * Master Current Select
+ */
+ usb3_reg_set16(GEN2_SETTINGS_3, 0x0, 0xFFFF, lane);
+
+ /*
+ * 3. Check crystal jumper setting and program the Power and PLL
+ * Control accordingly
+ * 4. Change RX wait
+ */
+ if (get_ref_clk() == 40) {
+ /* 40 MHz */
+ usb3_reg_set16(PWR_PLL_CTRL, 0xFCA3, 0xFFFF, lane);
+ usb3_reg_set16(PWR_MGM_TIM1, 0x10C, 0xFFFF, lane);
+ } else {
+ /* 25 MHz */
+ usb3_reg_set16(PWR_PLL_CTRL, 0xFCA2, 0xFFFF, lane);
+ usb3_reg_set16(PWR_MGM_TIM1, 0x107, 0xFFFF, lane);
+ }
+
+ /*
+ * 5. Enable idle sync
+ */
+ usb3_reg_set16(UNIT_CTRL, 0x60 | rb_idle_sync_en, 0xFFFF, lane);
+
+ /*
+ * 6. Enable the output of 500M clock
+ */
+ usb3_reg_set16(MISC_REG0, 0xA00D | rb_clk500m_en, 0xFFFF, lane);
+
+ /*
+ * 7. Set 20-bit data width
+ */
+ usb3_reg_set16(DIG_LB_EN, 0x0400, 0xFFFF, lane);
+
+ /*
+ * 8. Override Speed_PLL value and use MAC PLL
+ */
+ usb3_reg_set16(KVCO_CAL_CTRL, 0x0040 | rb_use_max_pll_rate, 0xFFFF,
+ lane);
+
+ /*
+ * 9. Check the Polarity invert bit
+ */
+ if (invert & COMPHY_POLARITY_TXD_INVERT)
+ usb3_reg_set16(SYNC_PATTERN, phy_txd_inv, 0, lane);
+
+ if (invert & COMPHY_POLARITY_RXD_INVERT)
+ usb3_reg_set16(SYNC_PATTERN, phy_rxd_inv, 0, lane);
+
+ /*
+ * 10. Set max speed generation to USB3.0 5Gbps
+ */
+ usb3_reg_set16(SYNC_MASK_GEN, 0x0400, 0x0C00, lane);
+
+ /*
+ * 11. Set capacitor value for FFE gain peaking to 0xF
+ */
+ usb3_reg_set16(GEN3_SETTINGS_3, 0xF, 0xF, lane);
+
+ /*
+ * 12. Release SW reset
+ */
+ usb3_reg_set16(GLOB_PHY_CTRL0,
+ rb_mode_core_clk_freq_sel | rb_mode_pipe_width_32
+ | 0x20, 0xFFFF, lane);
+
+ /* Wait for > 55 us to allow PCLK be enabled */
+ udelay(PLL_SET_DELAY_US);
+
+ /* Assert PCLK enabled */
+ if (lane == 2) {
+ reg_set(rh_vsreg_addr,
+ LANE_STAT1 + USB3PHY_LANE2_REG_BASE_OFFSET,
+ 0xFFFFFFFF);
+ ret = comphy_poll_reg(rh_vsreg_data, /* address */
+ rb_txdclk_pclk_en, /* value */
+ rb_txdclk_pclk_en, /* mask */
+ POLL_32B_REG); /* 32bit */
+ } else {
+ ret = comphy_poll_reg(phy_addr(USB3, LANE_STAT1), /* address */
+ rb_txdclk_pclk_en, /* value */
+ rb_txdclk_pclk_en, /* mask */
+ POLL_16B_REG); /* 16bit */
+ }
+ if (!ret)
+ printf("Failed to lock USB3 PLL\n");
+
+ /*
+ * Set Soft ID for Host mode (Device mode works with Hard ID
+ * detection)
+ */
+ if (type == COMPHY_TYPE_USB3_HOST0) {
+ /*
+ * set BIT0: set ID_MODE of Host/Device = "Soft ID" (BIT1)
+ * clear BIT1: set SOFT_ID = Host
+ * set BIT4: set INT_MODE = ID. Interrupt Mode: enable
+ * interrupt by ID instead of using both interrupts
+ * of HOST and Device ORed simultaneously
+ * INT_MODE=ID in order to avoid unexpected
+ * behaviour or both interrupts together
+ */
+ reg_set(USB32_CTRL_BASE,
+ usb32_ctrl_id_mode | usb32_ctrl_int_mode,
+ usb32_ctrl_id_mode | usb32_ctrl_soft_id |
+ usb32_ctrl_int_mode);
+ }
+
+ debug_exit();
+
+ return ret;
+}
+
+/*
+ * comphy_usb2_power_up
+ *
+ * return: 1 if PLL locked (OK), 0 otherwise (FAIL)
+ */
+static int comphy_usb2_power_up(u8 usb32)
+{
+ int ret;
+
+ debug_enter();
+
+ if (usb32 != 0 && usb32 != 1) {
+ printf("invalid usb32 value: (%d), should be either 0 or 1\n",
+ usb32);
+ debug_exit();
+ return 0;
+ }
+
+ /*
+ * 0. Setup PLL. 40MHz clock uses defaults.
+ * See "PLL Settings for Typical REFCLK" table
+ */
+ if (get_ref_clk() == 25) {
+ reg_set(USB2_PHY_BASE(usb32), 5 | (96 << 16),
+ 0x3F | (0xFF << 16) | (0x3 << 28));
+ }
+
+ /*
+ * 1. PHY pull up and disable USB2 suspend
+ */
+ reg_set(USB2_PHY_CTRL_ADDR(usb32),
+ RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU(usb32), 0);
+
+ if (usb32 != 0) {
+ /*
+ * 2. Power up OTG module
+ */
+ reg_set(USB2_PHY_OTG_CTRL_ADDR, rb_pu_otg, 0);
+
+ /*
+ * 3. Configure PHY charger detection
+ */
+ reg_set(USB2_PHY_CHRGR_DET_ADDR, 0,
+ rb_cdp_en | rb_dcp_en | rb_pd_en | rb_cdp_dm_auto |
+ rb_enswitch_dp | rb_enswitch_dm | rb_pu_chrg_dtc);
+ }
+
+ /* Assert PLL calibration done */
+ ret = comphy_poll_reg(USB2_PHY_CAL_CTRL_ADDR(usb32),
+ rb_usb2phy_pllcal_done, /* value */
+ rb_usb2phy_pllcal_done, /* mask */
+ POLL_32B_REG); /* 32bit */
+ if (!ret)
+ printf("Failed to end USB2 PLL calibration\n");
+
+ /* Assert impedance calibration done */
+ ret = comphy_poll_reg(USB2_PHY_CAL_CTRL_ADDR(usb32),
+ rb_usb2phy_impcal_done, /* value */
+ rb_usb2phy_impcal_done, /* mask */
+ POLL_32B_REG); /* 32bit */
+ if (!ret)
+ printf("Failed to end USB2 impedance calibration\n");
+
+ /* Assert squetch calibration done */
+ ret = comphy_poll_reg(USB2_PHY_RX_CHAN_CTRL1_ADDR(usb32),
+ rb_usb2phy_sqcal_done, /* value */
+ rb_usb2phy_sqcal_done, /* mask */
+ POLL_32B_REG); /* 32bit */
+ if (!ret)
+ printf("Failed to end USB2 unknown calibration\n");
+
+ /* Assert PLL is ready */
+ ret = comphy_poll_reg(USB2_PHY_PLL_CTRL0_ADDR(usb32),
+ rb_usb2phy_pll_ready, /* value */
+ rb_usb2phy_pll_ready, /* mask */
+ POLL_32B_REG); /* 32bit */
+
+ if (!ret)
+ printf("Failed to lock USB2 PLL\n");
+
+ debug_exit();
+
+ return ret;
+}
+
+/*
+ * comphy_emmc_power_up
+ *
+ * return: 1 if PLL locked (OK), 0 otherwise (FAIL)
+ */
+static int comphy_emmc_power_up(void)
+{
+ debug_enter();
+
+ /*
+ * 1. Bus power ON, Bus voltage 1.8V
+ */
+ reg_set(SDIO_HOST_CTRL1_ADDR, 0xB00, 0xF00);
+
+ /*
+ * 2. Set FIFO parameters
+ */
+ reg_set(SDIO_SDHC_FIFO_ADDR, 0x315, 0xFFFFFFFF);
+
+ /*
+ * 3. Set Capabilities 1_2
+ */
+ reg_set(SDIO_CAP_12_ADDR, 0x25FAC8B2, 0xFFFFFFFF);
+
+ /*
+ * 4. Set Endian
+ */
+ reg_set(SDIO_ENDIAN_ADDR, 0x00c00000, 0);
+
+ /*
+ * 4. Init PHY
+ */
+ reg_set(SDIO_PHY_TIMING_ADDR, 0x80000000, 0x80000000);
+ reg_set(SDIO_PHY_PAD_CTRL0_ADDR, 0x50000000, 0xF0000000);
+
+ /*
+ * 5. DLL reset
+ */
+ reg_set(SDIO_DLL_RST_ADDR, 0xFFFEFFFF, 0);
+ reg_set(SDIO_DLL_RST_ADDR, 0x00010000, 0);
+
+ debug_exit();
+
+ return 1;
+}
+
+/*
+ * comphy_sgmii_power_up
+ *
+ * return:
+ */
+static void comphy_sgmii_phy_init(u32 lane, u32 speed)
+{
+ const int fix_arr_sz = ARRAY_SIZE(sgmii_phy_init_fix);
+ int addr, fix_idx;
+ u16 val;
+
+ fix_idx = 0;
+ for (addr = 0; addr < 512; addr++) {
+ /*
+ * All PHY register values are defined in full for 3.125Gbps
+ * SERDES speed. The values required for 1.25 Gbps are almost
+ * the same and only few registers should be "fixed" in
+ * comparison to 3.125 Gbps values. These register values are
+ * stored in "sgmii_phy_init_fix" array.
+ */
+ if (speed != COMPHY_SPEED_1_25G &&
+ sgmii_phy_init_fix[fix_idx].addr == addr) {
+ /* Use new value */
+ val = sgmii_phy_init_fix[fix_idx].value;
+ if (fix_idx < fix_arr_sz)
+ fix_idx++;
+ } else {
+ val = sgmii_phy_init[addr];
+ }
+
+ reg_set16(sgmiiphy_addr(lane, addr), val, 0xFFFF);
+ }
+}
+
+/*
+ * comphy_sgmii_power_up
+ *
+ * return: 1 if PLL locked (OK), 0 otherwise (FAIL)
+ */
+static int comphy_sgmii_power_up(u32 lane, u32 speed, u32 invert)
+{
+ int ret;
+ u32 saved_selector;
+
+ debug_enter();
+
+ /*
+ * 1. Configure PHY to SATA/SAS mode by setting pin PIN_PIPE_SEL=0
+ */
+ saved_selector = readl(COMPHY_SEL_ADDR);
+ reg_set(COMPHY_SEL_ADDR, 0, 0xFFFFFFFF);
+
+ /*
+ * 2. Reset PHY by setting PHY input port PIN_RESET=1.
+ * 3. Set PHY input port PIN_TX_IDLE=1, PIN_PU_IVREF=1 to keep
+ * PHY TXP/TXN output to idle state during PHY initialization
+ * 4. Set PHY input port PIN_PU_PLL=0, PIN_PU_RX=0, PIN_PU_TX=0.
+ */
+ reg_set(COMPHY_PHY_CFG1_ADDR(lane),
+ rb_pin_reset_comphy | rb_pin_tx_idle | rb_pin_pu_iveref,
+ rb_pin_reset_core | rb_pin_pu_pll |
+ rb_pin_pu_rx | rb_pin_pu_tx);
+
+ /*
+ * 5. Release reset to the PHY by setting PIN_RESET=0.
+ */
+ reg_set(COMPHY_PHY_CFG1_ADDR(lane), 0, rb_pin_reset_comphy);
+
+ /*
+ * 7. Set PIN_PHY_GEN_TX[3:0] and PIN_PHY_GEN_RX[3:0] to decide
+ * COMPHY bit rate
+ */
+ if (speed == COMPHY_SPEED_3_125G) { /* 3.125 GHz */
+ reg_set(COMPHY_PHY_CFG1_ADDR(lane),
+ (0x8 << rf_gen_rx_sel_shift) |
+ (0x8 << rf_gen_tx_sel_shift),
+ rf_gen_rx_select | rf_gen_tx_select);
+
+ } else if (speed == COMPHY_SPEED_1_25G) { /* 1.25 GHz */
+ reg_set(COMPHY_PHY_CFG1_ADDR(lane),
+ (0x6 << rf_gen_rx_sel_shift) |
+ (0x6 << rf_gen_tx_sel_shift),
+ rf_gen_rx_select | rf_gen_tx_select);
+ } else {
+ printf("Unsupported COMPHY speed!\n");
+ return 0;
+ }
+
+ /*
+ * 8. Wait 1mS for bandgap and reference clocks to stabilize;
+ * then start SW programming.
+ */
+ mdelay(10);
+
+ /* 9. Program COMPHY register PHY_MODE */
+ reg_set16(sgmiiphy_addr(lane, PWR_PLL_CTRL),
+ PHY_MODE_SGMII << rf_phy_mode_shift, rf_phy_mode_mask);
+
+ /*
+ * 10. Set COMPHY register REFCLK_SEL to select the correct REFCLK
+ * source
+ */
+ reg_set16(sgmiiphy_addr(lane, MISC_REG0), 0, rb_ref_clk_sel);
+
+ /*
+ * 11. Set correct reference clock frequency in COMPHY register
+ * REF_FREF_SEL.
+ */
+ if (get_ref_clk() == 40) {
+ reg_set16(sgmiiphy_addr(lane, PWR_PLL_CTRL),
+ 0x4 << rf_ref_freq_sel_shift, rf_ref_freq_sel_mask);
+ } else {
+ /* 25MHz */
+ reg_set16(sgmiiphy_addr(lane, PWR_PLL_CTRL),
+ 0x1 << rf_ref_freq_sel_shift, rf_ref_freq_sel_mask);
+ }
+
+ /* 12. Program COMPHY register PHY_GEN_MAX[1:0] */
+ /*
+ * This step is mentioned in the flow received from verification team.
+ * However the PHY_GEN_MAX value is only meaningful for other
+ * interfaces (not SGMII). For instance, it selects SATA speed
+ * 1.5/3/6 Gbps or PCIe speed 2.5/5 Gbps
+ */
+
+ /*
+ * 13. Program COMPHY register SEL_BITS to set correct parallel data
+ * bus width
+ */
+ /* 10bit */
+ reg_set16(sgmiiphy_addr(lane, DIG_LB_EN), 0, rf_data_width_mask);
+
+ /*
+ * 14. As long as DFE function needs to be enabled in any mode,
+ * COMPHY register DFE_UPDATE_EN[5:0] shall be programmed to 0x3F
+ * for real chip during COMPHY power on.
+ */
+ /*
+ * The step 14 exists (and empty) in the original initialization flow
+ * obtained from the verification team. According to the functional
+ * specification DFE_UPDATE_EN already has the default value 0x3F
+ */
+
+ /*
+ * 15. Program COMPHY GEN registers.
+ * These registers should be programmed based on the lab testing
+ * result to achieve optimal performance. Please contact the CEA
+ * group to get the related GEN table during real chip bring-up.
+ * We only requred to run though the entire registers programming
+ * flow defined by "comphy_sgmii_phy_init" when the REF clock is
+ * 40 MHz. For REF clock 25 MHz the default values stored in PHY
+ * registers are OK.
+ */
+ debug("Running C-DPI phy init %s mode\n",
+ speed == COMPHY_SPEED_3_125G ? "2G5" : "1G");
+ if (get_ref_clk() == 40)
+ comphy_sgmii_phy_init(lane, speed);
+
+ /*
+ * 16. [Simulation Only] should not be used for real chip.
+ * By pass power up calibration by programming EXT_FORCE_CAL_DONE
+ * (R02h[9]) to 1 to shorten COMPHY simulation time.
+ */
+ /*
+ * 17. [Simulation Only: should not be used for real chip]
+ * Program COMPHY register FAST_DFE_TIMER_EN=1 to shorten RX
+ * training simulation time.
+ */
+
+ /*
+ * 18. Check the PHY Polarity invert bit
+ */
+ if (invert & COMPHY_POLARITY_TXD_INVERT)
+ reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), phy_txd_inv, 0);
+
+ if (invert & COMPHY_POLARITY_RXD_INVERT)
+ reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), phy_rxd_inv, 0);
+
+ /*
+ * 19. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1
+ * to start PHY power up sequence. All the PHY register
+ * programming should be done before PIN_PU_PLL=1. There should be
+ * no register programming for normal PHY operation from this point.
+ */
+ reg_set(COMPHY_PHY_CFG1_ADDR(lane),
+ rb_pin_pu_pll | rb_pin_pu_rx | rb_pin_pu_tx,
+ rb_pin_pu_pll | rb_pin_pu_rx | rb_pin_pu_tx);
+
+ /*
+ * 20. Wait for PHY power up sequence to finish by checking output ports
+ * PIN_PLL_READY_TX=1 and PIN_PLL_READY_RX=1.
+ */
+ ret = comphy_poll_reg(COMPHY_PHY_STAT1_ADDR(lane), /* address */
+ rb_pll_ready_tx | rb_pll_ready_rx, /* value */
+ rb_pll_ready_tx | rb_pll_ready_rx, /* mask */
+ POLL_32B_REG); /* 32bit */
+ if (!ret)
+ printf("Failed to lock PLL for SGMII PHY %d\n", lane);
+
+ /*
+ * 21. Set COMPHY input port PIN_TX_IDLE=0
+ */
+ reg_set(COMPHY_PHY_CFG1_ADDR(lane), 0x0, rb_pin_tx_idle);
+
+ /*
+ * 22. After valid data appear on PIN_RXDATA bus, set PIN_RX_INIT=1.
+ * to start RX initialization. PIN_RX_INIT_DONE will be cleared to
+ * 0 by the PHY. After RX initialization is done, PIN_RX_INIT_DONE
+ * will be set to 1 by COMPHY. Set PIN_RX_INIT=0 after
+ * PIN_RX_INIT_DONE= 1.
+ * Please refer to RX initialization part for details.
+ */
+ reg_set(COMPHY_PHY_CFG1_ADDR(lane), rb_phy_rx_init, 0x0);
+
+ ret = comphy_poll_reg(COMPHY_PHY_STAT1_ADDR(lane), /* address */
+ rb_rx_init_done, /* value */
+ rb_rx_init_done, /* mask */
+ POLL_32B_REG); /* 32bit */
+ if (!ret)
+ printf("Failed to init RX of SGMII PHY %d\n", lane);
+
+ /*
+ * Restore saved selector.
+ */
+ reg_set(COMPHY_SEL_ADDR, saved_selector, 0xFFFFFFFF);
+
+ debug_exit();
+
+ return ret;
+}
+
+void comphy_dedicated_phys_init(void)
+{
+ int node, usb32, ret = 1;
+ const void *blob = gd->fdt_blob;
+
+ debug_enter();
+
+ for (usb32 = 0; usb32 <= 1; usb32++) {
+ /*
+ * There are 2 UTMI PHYs in this SOC.
+ * One is independendent and one is paired with USB3 port (OTG)
+ */
+ if (usb32 == 0) {
+ node = fdt_node_offset_by_compatible(
+ blob, -1, "marvell,armada3700-ehci");
+ } else {
+ node = fdt_node_offset_by_compatible(
+ blob, -1, "marvell,armada3700-xhci");
+ }
+
+ if (node > 0) {
+ if (fdtdec_get_is_enabled(blob, node)) {
+ ret = comphy_usb2_power_up(usb32);
+ if (!ret)
+ printf("Failed to initialize UTMI PHY\n");
+ else
+ debug("UTMI PHY init succeed\n");
+ } else {
+ debug("USB%d node is disabled\n",
+ usb32 == 0 ? 2 : 3);
+ }
+ } else {
+ debug("No USB%d node in DT\n", usb32 == 0 ? 2 : 3);
+ }
+ }
+
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "marvell,armada-8k-sdhci");
+ if (node <= 0) {
+ node = fdt_node_offset_by_compatible(
+ blob, -1, "marvell,armada-3700-sdhci");
+ }
+
+ if (node > 0) {
+ if (fdtdec_get_is_enabled(blob, node)) {
+ ret = comphy_emmc_power_up();
+ if (!ret)
+ printf("Failed to initialize SDIO/eMMC PHY\n");
+ else
+ debug("SDIO/eMMC PHY init succeed\n");
+ } else {
+ debug("SDIO/eMMC node is disabled\n");
+ }
+ } else {
+ debug("No SDIO/eMMC node in DT\n");
+ }
+
+ debug_exit();
+}
+
+int comphy_a3700_init(struct chip_serdes_phy_config *chip_cfg,
+ struct comphy_map *serdes_map)
+{
+ struct comphy_map *comphy_map;
+ u32 comphy_max_count = chip_cfg->comphy_lanes_count;
+ u32 lane, ret = 0;
+
+ debug_enter();
+
+ /* Initialize PHY mux */
+ chip_cfg->mux_data = a3700_comphy_mux_data;
+ comphy_mux_init(chip_cfg, serdes_map, COMPHY_SEL_ADDR);
+
+ for (lane = 0, comphy_map = serdes_map; lane < comphy_max_count;
+ lane++, comphy_map++) {
+ debug("Initialize serdes number %d\n", lane);
+ debug("Serdes type = 0x%x invert=%d\n",
+ comphy_map->type, comphy_map->invert);
+
+ switch (comphy_map->type) {
+ case COMPHY_TYPE_UNCONNECTED:
+ continue;
+ break;
+
+ case COMPHY_TYPE_PEX0:
+ ret = comphy_pcie_power_up(comphy_map->speed,
+ comphy_map->invert);
+ break;
+
+ case COMPHY_TYPE_USB3_HOST0:
+ case COMPHY_TYPE_USB3_DEVICE:
+ ret = comphy_usb3_power_up(lane,
+ comphy_map->type,
+ comphy_map->speed,
+ comphy_map->invert);
+ break;
+
+ case COMPHY_TYPE_SGMII0:
+ case COMPHY_TYPE_SGMII1:
+ ret = comphy_sgmii_power_up(lane, comphy_map->speed,
+ comphy_map->invert);
+ break;
+
+ case COMPHY_TYPE_SATA0:
+ ret = comphy_sata_power_up(comphy_map->invert);
+ break;
+
+ default:
+ debug("Unknown SerDes type, skip initialize SerDes %d\n",
+ lane);
+ ret = 1;
+ break;
+ }
+ if (!ret)
+ printf("PLL is not locked - Failed to initialize lane %d\n",
+ lane);
+ }
+
+ debug_exit();
+ return ret;
+}
diff --git a/roms/u-boot/drivers/phy/marvell/comphy_a3700.h b/roms/u-boot/drivers/phy/marvell/comphy_a3700.h
new file mode 100644
index 000000000..8748c6c84
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/comphy_a3700.h
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+ */
+
+#ifndef _COMPHY_A3700_H_
+#define _COMPHY_A3700_H_
+
+#include "comphy_core.h"
+
+#define MVEBU_REG(offs) \
+ ((void __iomem *)(ulong)MVEBU_REGISTER(offs))
+
+#define DEFAULT_REFCLK_MHZ 25
+#define PLL_SET_DELAY_US 600
+#define PLL_LOCK_TIMEOUT 1000
+#define POLL_16B_REG 1
+#define POLL_32B_REG 0
+
+/*
+ * COMPHY SB definitions
+ */
+#define COMPHY_SEL_ADDR MVEBU_REG(0x0183FC)
+
+#define COMPHY_PHY_CFG1_ADDR(lane) MVEBU_REG(0x018300 + (1 - lane) * 0x28)
+#define rb_pin_pu_iveref BIT(1)
+#define rb_pin_reset_core BIT(11)
+#define rb_pin_reset_comphy BIT(12)
+#define rb_pin_pu_pll BIT(16)
+#define rb_pin_pu_rx BIT(17)
+#define rb_pin_pu_tx BIT(18)
+#define rb_pin_tx_idle BIT(19)
+#define rf_gen_rx_sel_shift 22
+#define rf_gen_rx_select (0x0F << rf_gen_rx_sel_shift)
+#define rf_gen_tx_sel_shift 26
+#define rf_gen_tx_select (0x0F << rf_gen_tx_sel_shift)
+#define rb_phy_rx_init BIT(30)
+
+#define COMPHY_PHY_STAT1_ADDR(lane) MVEBU_REG(0x018318 + (1 - lane) * 0x28)
+#define rb_rx_init_done BIT(0)
+#define rb_pll_ready_rx BIT(2)
+#define rb_pll_ready_tx BIT(3)
+
+/*
+ * PCIe/USB/SGMII definitions
+ */
+#define PCIE_BASE MVEBU_REG(0x070000)
+#define PCIETOP_BASE MVEBU_REG(0x080000)
+#define PCIE_RAMBASE MVEBU_REG(0x08C000)
+#define PCIEPHY_BASE MVEBU_REG(0x01F000)
+#define PCIEPHY_SHFT 2
+
+#define USB32_BASE MVEBU_REG(0x050000) /* usb3 device */
+#define USB32H_BASE MVEBU_REG(0x058000) /* usb3 host */
+#define USB3PHY_BASE MVEBU_REG(0x05C000)
+#define USB2PHY_BASE MVEBU_REG(0x05D000)
+#define USB2PHY2_BASE MVEBU_REG(0x05F000)
+#define USB32_CTRL_BASE MVEBU_REG(0x05D800)
+#define USB3PHY_SHFT 2
+#define USB3PHY_LANE2_REG_BASE_OFFSET 0x200
+
+static inline void __iomem *sgmiiphy_addr(u32 lane, u32 addr)
+{
+ addr = (addr & 0x00007FF) * 2;
+ if (lane == 1)
+ return PCIEPHY_BASE + addr;
+ else
+ return USB3PHY_BASE + addr;
+}
+
+/* units */
+enum phy_unit {
+ PCIE = 1,
+ USB3 = 2,
+};
+
+static inline void __iomem *phy_addr(enum phy_unit unit, u32 addr)
+{
+ if (unit == PCIE)
+ return PCIEPHY_BASE + addr * PCIEPHY_SHFT;
+ else
+ return USB3PHY_BASE + addr * USB3PHY_SHFT;
+}
+
+/* bit definition for USB32_CTRL_BASE (USB32 Control Mode) */
+#define usb32_ctrl_id_mode BIT(0)
+#define usb32_ctrl_soft_id BIT(1)
+#define usb32_ctrl_int_mode BIT(4)
+
+#define PWR_PLL_CTRL 0x01
+#define rf_phy_mode_shift 5
+#define rf_phy_mode_mask (0x7 << rf_phy_mode_shift)
+#define rf_ref_freq_sel_shift 0
+#define rf_ref_freq_sel_mask (0x1F << rf_ref_freq_sel_shift)
+#define PHY_MODE_SGMII 0x4
+
+#define KVCO_CAL_CTRL 0x02
+#define rb_use_max_pll_rate BIT(12)
+#define rb_force_calibration_done BIT(9)
+
+#define DIG_LB_EN 0x23
+#define rf_data_width_shift 10
+#define rf_data_width_mask (0x3 << rf_data_width_shift)
+
+#define SYNC_PATTERN 0x24
+#define phy_txd_inv BIT(10)
+#define phy_rxd_inv BIT(11)
+
+#define SYNC_MASK_GEN 0x25
+#define rb_idle_sync_en BIT(12)
+
+#define UNIT_CTRL 0x48
+
+#define GEN2_SETTINGS_2 0x3e
+#define g2_tx_ssc_amp BIT(14)
+
+#define GEN2_SETTINGS_3 0x3f
+
+#define GEN3_SETTINGS_3 0x112
+
+#define MISC_REG0 0x4f
+#define rb_clk100m_125m_en BIT(4)
+#define rb_clk500m_en BIT(7)
+#define rb_ref_clk_sel BIT(10)
+
+#define UNIT_IFACE_REF_CLK_CTRL 0x51
+#define rb_ref1m_gen_div_force BIT(8)
+#define rf_ref1m_gen_div_value_shift 0
+#define rf_ref1m_gen_div_value_mask (0xFF << rf_ref1m_gen_div_value_shift)
+
+#define UNIT_ERR_CNT_CONST_CTRL 0x6a
+#define rb_fast_dfe_enable BIT(13)
+
+#define MISC_REG1 0x73
+#define bf_sel_bits_pcie_force BIT(15)
+
+#define LANE_CFG0 0x180
+#define bf_use_max_pll_rate BIT(9)
+
+#define LANE_CFG1 0x181
+#define bf_use_max_pll_rate BIT(9)
+#define prd_txdeemph1_mask BIT(15)
+#define tx_det_rx_mode BIT(6)
+#define gen2_tx_data_dly_deft (2 << 3)
+#define gen2_tx_data_dly_mask (BIT(3) | BIT(4))
+#define tx_elec_idle_mode_en BIT(0)
+
+#define LANE_CFG4 0x188
+#define bf_spread_spectrum_clock_en BIT(7)
+
+#define LANE_STAT1 0x183
+#define rb_txdclk_pclk_en BIT(0)
+
+#define GLOB_PHY_CTRL0 0x1c1
+#define bf_soft_rst BIT(0)
+#define bf_mode_refdiv 0x30
+#define rb_mode_core_clk_freq_sel BIT(9)
+#define rb_mode_pipe_width_32 BIT(3)
+
+#define TEST_MODE_CTRL 0x1c2
+#define rb_mode_margin_override BIT(2)
+
+#define GLOB_CLK_SRC_LO 0x1c3
+#define bf_cfg_sel_20b BIT(15)
+
+#define PWR_MGM_TIM1 0x1d0
+
+#define PCIE_REF_CLK_ADDR (PCIE_BASE + 0x4814)
+
+#define USB3_CTRPUL_VAL_REG (0x20 + USB32_BASE)
+#define USB3H_CTRPUL_VAL_REG (0x3454 + USB32H_BASE)
+#define rb_usb3_ctr_100ns 0xff000000
+
+#define USB2_OTG_PHY_CTRL_ADDR (0x820 + USB2PHY_BASE)
+#define rb_usb2phy_suspm BIT(14)
+#define rb_usb2phy_pu BIT(0)
+
+#define USB2_PHY_OTG_CTRL_ADDR (0x34 + USB2PHY_BASE)
+#define rb_pu_otg BIT(4)
+
+#define USB2_PHY_CHRGR_DET_ADDR (0x38 + USB2PHY_BASE)
+#define rb_cdp_en BIT(2)
+#define rb_dcp_en BIT(3)
+#define rb_pd_en BIT(4)
+#define rb_pu_chrg_dtc BIT(5)
+#define rb_cdp_dm_auto BIT(7)
+#define rb_enswitch_dp BIT(12)
+#define rb_enswitch_dm BIT(13)
+
+#define USB2_CAL_CTRL_ADDR (0x8 + USB2PHY_BASE)
+#define rb_usb2phy_pllcal_done BIT(31)
+#define rb_usb2phy_impcal_done BIT(23)
+
+#define USB2_PLL_CTRL0_ADDR (0x0 + USB2PHY_BASE)
+#define rb_usb2phy_pll_ready BIT(31)
+
+#define USB2_RX_CHAN_CTRL1_ADDR (0x18 + USB2PHY_BASE)
+#define rb_usb2phy_sqcal_done BIT(31)
+
+#define USB2_PHY2_CTRL_ADDR (0x804 + USB2PHY2_BASE)
+#define rb_usb2phy2_suspm BIT(7)
+#define rb_usb2phy2_pu BIT(0)
+#define USB2_PHY2_CAL_CTRL_ADDR (0x8 + USB2PHY2_BASE)
+#define USB2_PHY2_PLL_CTRL0_ADDR (0x0 + USB2PHY2_BASE)
+#define USB2_PHY2_RX_CHAN_CTRL1_ADDR (0x18 + USB2PHY2_BASE)
+
+#define USB2_PHY_BASE(usb32) (usb32 == 0 ? USB2PHY2_BASE : USB2PHY_BASE)
+#define USB2_PHY_CTRL_ADDR(usb32) \
+ (usb32 == 0 ? USB2_PHY2_CTRL_ADDR : USB2_OTG_PHY_CTRL_ADDR)
+#define RB_USB2PHY_SUSPM(usb32) \
+ (usb32 == 0 ? rb_usb2phy2_suspm : rb_usb2phy_suspm)
+#define RB_USB2PHY_PU(usb32) \
+ (usb32 == 0 ? rb_usb2phy2_pu : rb_usb2phy_pu)
+#define USB2_PHY_CAL_CTRL_ADDR(usb32) \
+ (usb32 == 0 ? USB2_PHY2_CAL_CTRL_ADDR : USB2_CAL_CTRL_ADDR)
+#define USB2_PHY_RX_CHAN_CTRL1_ADDR(usb32) \
+ (usb32 == 0 ? USB2_PHY2_RX_CHAN_CTRL1_ADDR : USB2_RX_CHAN_CTRL1_ADDR)
+#define USB2_PHY_PLL_CTRL0_ADDR(usb32) \
+ (usb32 == 0 ? USB2_PHY2_PLL_CTRL0_ADDR : USB2_PLL_CTRL0_ADDR)
+
+/*
+ * SATA definitions
+ */
+#define AHCI_BASE MVEBU_REG(0xE0000)
+
+#define rh_vsreg_addr (AHCI_BASE + 0x178)
+#define rh_vsreg_data (AHCI_BASE + 0x17C)
+#define rh_vs0_a (AHCI_BASE + 0xA0)
+#define rh_vs0_d (AHCI_BASE + 0xA4)
+
+#define vphy_sync_pattern_reg 0x224
+#define bs_txd_inv BIT(10)
+#define bs_rxd_inv BIT(11)
+
+#define vphy_loopback_reg0 0x223
+#define bs_phyintf_40bit 0x0C00
+#define bs_pll_ready_tx 0x10
+
+#define vphy_power_reg0 0x201
+
+#define vphy_calctl_reg 0x202
+#define bs_max_pll_rate BIT(12)
+
+#define vphy_reserve_reg 0x0e
+#define bs_phyctrl_frm_pin BIT(13)
+
+#define vsata_ctrl_reg 0x00
+#define bs_phy_pu_pll BIT(6)
+
+/*
+ * SDIO/eMMC definitions
+ */
+#define SDIO_BASE MVEBU_REG(0xD8000)
+
+#define SDIO_HOST_CTRL1_ADDR (SDIO_BASE + 0x28)
+#define SDIO_SDHC_FIFO_ADDR (SDIO_BASE + 0x12C)
+#define SDIO_CAP_12_ADDR (SDIO_BASE + 0x40)
+#define SDIO_ENDIAN_ADDR (SDIO_BASE + 0x1A4)
+#define SDIO_PHY_TIMING_ADDR (SDIO_BASE + 0x170)
+#define SDIO_PHY_PAD_CTRL0_ADDR (SDIO_BASE + 0x178)
+#define SDIO_DLL_RST_ADDR (SDIO_BASE + 0x148)
+
+#endif /* _COMPHY_A3700_H_ */
diff --git a/roms/u-boot/drivers/phy/marvell/comphy_core.c b/roms/u-boot/drivers/phy/marvell/comphy_core.c
new file mode 100644
index 000000000..2c9d7b228
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/comphy_core.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+ *
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/libfdt.h>
+
+#include "comphy_core.h"
+
+#define COMPHY_MAX_CHIP 4
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *get_speed_string(u32 speed)
+{
+ static const char * const speed_strings[] = {
+ "1.25 Gbps", "2.5 Gbps", "3.125 Gbps",
+ "5 Gbps", "5.125 Gpbs", "6 Gbps",
+ "10.3125 Gbps"
+ };
+
+ if (speed < 0 || speed > COMPHY_SPEED_MAX)
+ return "invalid";
+
+ return speed_strings[speed];
+}
+
+static const char *get_type_string(u32 type)
+{
+ static const char * const type_strings[] = {
+ "UNCONNECTED", "PEX0", "PEX1", "PEX2", "PEX3",
+ "SATA0", "SATA1", "SGMII0", "SGMII1", "SGMII2",
+ "USB3", "USB3_HOST0", "USB3_HOST1",
+ "USB3_DEVICE", "RXAUI0", "RXAUI1", "SFI0", "SFI1", "AP",
+ "IGNORE"
+ };
+
+ if (type < 0 || type > COMPHY_TYPE_MAX)
+ return "invalid";
+
+ return type_strings[type];
+}
+
+void comphy_print(struct chip_serdes_phy_config *chip_cfg,
+ struct comphy_map *comphy_map_data)
+{
+ u32 lane;
+
+ for (lane = 0; lane < chip_cfg->comphy_lanes_count;
+ lane++, comphy_map_data++) {
+ if (comphy_map_data->speed == COMPHY_SPEED_INVALID) {
+ printf("Comphy-%d: %-13s\n", lane,
+ get_type_string(comphy_map_data->type));
+ } else {
+ printf("Comphy-%d: %-13s %-10s\n", lane,
+ get_type_string(comphy_map_data->type),
+ get_speed_string(comphy_map_data->speed));
+ }
+ }
+}
+
+int comphy_rx_training(struct udevice *dev, u32 lane)
+{
+ struct chip_serdes_phy_config *chip_cfg = dev_get_priv(dev);
+
+ if (chip_cfg->rx_training)
+ return chip_cfg->rx_training(chip_cfg, lane);
+
+ return 0;
+}
+
+__weak int comphy_update_map(struct comphy_map *serdes_map, int count)
+{
+ return 0;
+}
+
+static int comphy_probe(struct udevice *dev)
+{
+ const void *blob = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+ struct chip_serdes_phy_config *chip_cfg = dev_get_priv(dev);
+ int subnode;
+ int lane;
+ int last_idx = 0;
+ static int current_idx;
+ int res;
+
+ /* Save base addresses for later use */
+ chip_cfg->comphy_base_addr = (void *)devfdt_get_addr_index(dev, 0);
+ if (IS_ERR(chip_cfg->comphy_base_addr))
+ return PTR_ERR(chip_cfg->comphy_base_addr);
+
+ chip_cfg->hpipe3_base_addr = (void *)devfdt_get_addr_index(dev, 1);
+ if (IS_ERR(chip_cfg->hpipe3_base_addr))
+ return PTR_ERR(chip_cfg->hpipe3_base_addr);
+
+ chip_cfg->comphy_lanes_count = fdtdec_get_int(blob, node,
+ "max-lanes", 0);
+ if (chip_cfg->comphy_lanes_count <= 0) {
+ dev_err(dev, "comphy max lanes is wrong\n");
+ return -EINVAL;
+ }
+
+ chip_cfg->comphy_mux_bitcount = fdtdec_get_int(blob, node,
+ "mux-bitcount", 0);
+ if (chip_cfg->comphy_mux_bitcount <= 0) {
+ dev_err(dev, "comphy mux bit count is wrong\n");
+ return -EINVAL;
+ }
+
+ chip_cfg->comphy_mux_lane_order =
+ fdtdec_locate_array(blob, node, "mux-lane-order",
+ chip_cfg->comphy_lanes_count);
+
+ if (device_is_compatible(dev, "marvell,comphy-armada-3700")) {
+ chip_cfg->ptr_comphy_chip_init = comphy_a3700_init;
+ chip_cfg->rx_training = NULL;
+ }
+
+ if (device_is_compatible(dev, "marvell,comphy-cp110")) {
+ chip_cfg->ptr_comphy_chip_init = comphy_cp110_init;
+ chip_cfg->rx_training = comphy_cp110_sfi_rx_training;
+ }
+
+ /*
+ * Bail out if no chip_init function is defined, e.g. no
+ * compatible node is found
+ */
+ if (!chip_cfg->ptr_comphy_chip_init) {
+ dev_err(dev, "comphy: No compatible DT node found\n");
+ return -ENODEV;
+ }
+
+ lane = 0;
+ fdt_for_each_subnode(subnode, blob, node) {
+ /* Skip disabled ports */
+ if (!fdtdec_get_is_enabled(blob, subnode))
+ continue;
+
+ chip_cfg->comphy_map_data[lane].type =
+ fdtdec_get_int(blob, subnode, "phy-type",
+ COMPHY_TYPE_INVALID);
+
+ if (chip_cfg->comphy_map_data[lane].type ==
+ COMPHY_TYPE_INVALID) {
+ printf("no phy type for lane %d, setting lane as unconnected\n",
+ lane + 1);
+ continue;
+ }
+
+ chip_cfg->comphy_map_data[lane].speed =
+ fdtdec_get_int(blob, subnode, "phy-speed",
+ COMPHY_SPEED_INVALID);
+
+ chip_cfg->comphy_map_data[lane].invert =
+ fdtdec_get_int(blob, subnode, "phy-invert",
+ COMPHY_POLARITY_NO_INVERT);
+
+ chip_cfg->comphy_map_data[lane].clk_src =
+ fdtdec_get_bool(blob, subnode, "clk-src");
+
+ chip_cfg->comphy_map_data[lane].end_point =
+ fdtdec_get_bool(blob, subnode, "end_point");
+
+ lane++;
+ }
+
+ res = comphy_update_map(chip_cfg->comphy_map_data, chip_cfg->comphy_lanes_count);
+ if (res < 0)
+ return res;
+
+ /* Save CP index for MultiCP devices (A8K) */
+ chip_cfg->cp_index = current_idx++;
+ /* PHY power UP sequence */
+ chip_cfg->ptr_comphy_chip_init(chip_cfg, chip_cfg->comphy_map_data);
+ /* PHY print SerDes status */
+ printf("Comphy chip #%d:\n", chip_cfg->cp_index);
+ comphy_print(chip_cfg, chip_cfg->comphy_map_data);
+
+ /*
+ * Only run the dedicated PHY init code once, in the last PHY init call
+ */
+ if (of_machine_is_compatible("marvell,armada8040"))
+ last_idx = 1;
+
+ if (chip_cfg->cp_index == last_idx) {
+ /* Initialize dedicated PHYs (not muxed SerDes lanes) */
+ comphy_dedicated_phys_init();
+ }
+
+ return 0;
+}
+
+static const struct udevice_id comphy_ids[] = {
+ { .compatible = "marvell,mvebu-comphy" },
+ { }
+};
+
+U_BOOT_DRIVER(mvebu_comphy) = {
+ .name = "mvebu_comphy",
+ .id = UCLASS_MISC,
+ .of_match = comphy_ids,
+ .probe = comphy_probe,
+ .priv_auto = sizeof(struct chip_serdes_phy_config),
+};
diff --git a/roms/u-boot/drivers/phy/marvell/comphy_core.h b/roms/u-boot/drivers/phy/marvell/comphy_core.h
new file mode 100644
index 000000000..ba64491df
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/comphy_core.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+ */
+
+#ifndef _COMPHY_CORE_H_
+#define _COMPHY_CORE_H_
+
+#include <fdtdec.h>
+#include <mvebu/comphy.h>
+
+#if defined(DEBUG)
+#define debug_enter() printf("----> Enter %s\n", __func__);
+#define debug_exit() printf("<---- Exit %s\n", __func__);
+#else
+#define debug_enter()
+#define debug_exit()
+#endif
+
+#define MAX_LANE_OPTIONS 10
+#define MAX_UTMI_PHY_COUNT 6
+
+struct comphy_mux_options {
+ u32 type;
+ u32 mux_value;
+};
+
+struct comphy_mux_data {
+ u32 max_lane_values;
+ struct comphy_mux_options mux_values[MAX_LANE_OPTIONS];
+};
+
+struct chip_serdes_phy_config {
+ struct comphy_mux_data *mux_data;
+ int (*ptr_comphy_chip_init)(struct chip_serdes_phy_config *,
+ struct comphy_map *);
+ int (*rx_training)(struct chip_serdes_phy_config *, u32);
+ void __iomem *comphy_base_addr;
+ void __iomem *hpipe3_base_addr;
+ u32 comphy_lanes_count;
+ u32 comphy_mux_bitcount;
+ const fdt32_t *comphy_mux_lane_order;
+ u32 cp_index;
+ struct comphy_map comphy_map_data[MAX_LANE_OPTIONS];
+};
+
+/* Register helper functions */
+static inline void reg_set_silent(void __iomem *addr, u32 data, u32 mask)
+{
+ u32 reg_data;
+
+ reg_data = readl(addr);
+ reg_data &= ~mask;
+ reg_data |= data;
+ writel(reg_data, addr);
+}
+
+static inline void reg_set(void __iomem *addr, u32 data, u32 mask)
+{
+ debug("Write to address = %#010lx, data = %#010x (mask = %#010x) - ",
+ (unsigned long)addr, data, mask);
+ debug("old value = %#010x ==> ", readl(addr));
+ reg_set_silent(addr, data, mask);
+ debug("new value %#010x\n", readl(addr));
+}
+
+static inline void reg_set_silent16(void __iomem *addr, u16 data, u16 mask)
+{
+ u16 reg_data;
+
+ reg_data = readw(addr);
+ reg_data &= ~mask;
+ reg_data |= data;
+ writew(reg_data, addr);
+}
+
+static inline void reg_set16(void __iomem *addr, u16 data, u16 mask)
+{
+ debug("Write to address = %#010lx, data = %#06x (mask = %#06x) - ",
+ (unsigned long)addr, data, mask);
+ debug("old value = %#06x ==> ", readw(addr));
+ reg_set_silent16(addr, data, mask);
+ debug("new value %#06x\n", readw(addr));
+}
+
+/* SoC specific init functions */
+#ifdef CONFIG_ARMADA_3700
+int comphy_a3700_init(struct chip_serdes_phy_config *ptr_chip_cfg,
+ struct comphy_map *serdes_map);
+#else
+static inline int comphy_a3700_init(struct chip_serdes_phy_config *ptr_chip_cfg,
+ struct comphy_map *serdes_map)
+{
+ /*
+ * This function should never be called in this configuration, so
+ * lets return an error here.
+ */
+ return -1;
+}
+#endif
+
+#ifdef CONFIG_ARMADA_8K
+int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
+ struct comphy_map *serdes_map);
+int comphy_cp110_sfi_rx_training(struct chip_serdes_phy_config *ptr_chip_cfg,
+ u32 lane);
+#else
+static inline int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
+ struct comphy_map *serdes_map)
+{
+ /*
+ * This function should never be called in this configuration, so
+ * lets return an error here.
+ */
+ return -1;
+}
+
+static inline int comphy_cp110_sfi_rx_training(
+ struct chip_serdes_phy_config *ptr_chip_cfg,
+ u32 lane)
+{
+ /*
+ * This function should never be called in this configuration, so
+ * lets return an error here.
+ */
+ return -1;
+}
+#endif
+
+void comphy_dedicated_phys_init(void);
+
+/* MUX function */
+void comphy_mux_init(struct chip_serdes_phy_config *ptr_chip_cfg,
+ struct comphy_map *comphy_map_data,
+ void __iomem *selector_base);
+
+void comphy_pcie_config_set(u32 comphy_max_count,
+ struct comphy_map *serdes_map);
+void comphy_pcie_config_detect(u32 comphy_max_count,
+ struct comphy_map *serdes_map);
+void comphy_pcie_unit_general_config(u32 pex_index);
+
+#endif /* _COMPHY_CORE_H_ */
+
diff --git a/roms/u-boot/drivers/phy/marvell/comphy_cp110.c b/roms/u-boot/drivers/phy/marvell/comphy_cp110.c
new file mode 100644
index 000000000..418318d12
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/comphy_cp110.c
@@ -0,0 +1,681 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <linux/delay.h>
+
+#include "comphy_core.h"
+#include "sata.h"
+#include "utmi_phy.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Firmware related definitions used for SMC calls */
+#define MV_SIP_COMPHY_POWER_ON 0x82000001
+#define MV_SIP_COMPHY_POWER_OFF 0x82000002
+#define MV_SIP_COMPHY_PLL_LOCK 0x82000003
+#define MV_SIP_COMPHY_XFI_TRAIN 0x82000004
+
+/* Used to distinguish between different possible callers (U-boot/Linux) */
+#define COMPHY_CALLER_UBOOT (0x1 << 21)
+
+#define COMPHY_FW_MODE_FORMAT(mode) ((mode) << 12)
+#define COMPHY_FW_FORMAT(mode, idx, speeds) \
+ (((mode) << 12) | ((idx) << 8) | ((speeds) << 2))
+
+#define COMPHY_FW_PCIE_FORMAT(pcie_width, clk_src, mode, speeds) \
+ (COMPHY_CALLER_UBOOT | ((pcie_width) << 18) | \
+ ((clk_src) << 17) | COMPHY_FW_FORMAT(mode, 0, speeds))
+
+#define COMPHY_SATA_MODE 0x1
+#define COMPHY_SGMII_MODE 0x2 /* SGMII 1G */
+#define COMPHY_HS_SGMII_MODE 0x3 /* SGMII 2.5G */
+#define COMPHY_USB3H_MODE 0x4
+#define COMPHY_USB3D_MODE 0x5
+#define COMPHY_PCIE_MODE 0x6
+#define COMPHY_RXAUI_MODE 0x7
+#define COMPHY_XFI_MODE 0x8
+#define COMPHY_SFI_MODE 0x9
+#define COMPHY_USB3_MODE 0xa
+#define COMPHY_AP_MODE 0xb
+
+/* Comphy unit index macro */
+#define COMPHY_UNIT_ID0 0
+#define COMPHY_UNIT_ID1 1
+#define COMPHY_UNIT_ID2 2
+#define COMPHY_UNIT_ID3 3
+
+struct utmi_phy_data {
+ void __iomem *utmi_pll_addr;
+ void __iomem *utmi_base_addr;
+ void __iomem *usb_cfg_addr;
+ void __iomem *utmi_cfg_addr;
+ u32 utmi_phy_port;
+};
+
+static u32 polling_with_timeout(void __iomem *addr, u32 val,
+ u32 mask, unsigned long usec_timout)
+{
+ u32 data;
+
+ do {
+ udelay(1);
+ data = readl(addr) & mask;
+ } while (data != val && --usec_timout > 0);
+
+ if (usec_timout == 0)
+ return data;
+
+ return 0;
+}
+
+static int comphy_smc(u32 function_id, void __iomem *comphy_base_addr,
+ u32 lane, u32 mode)
+{
+ struct pt_regs pregs = {0};
+
+ pregs.regs[0] = function_id;
+ pregs.regs[1] = (unsigned long)comphy_base_addr;
+ pregs.regs[2] = lane;
+ pregs.regs[3] = mode;
+
+ smc_call(&pregs);
+
+ /*
+ * TODO: Firmware return 0 on success, temporary map it to u-boot
+ * convention, but after all comphy will be reworked the convention in
+ * u-boot should be change and this conversion removed
+ */
+ return pregs.regs[0] ? 0 : 1;
+}
+
+/* This function performs RX training for all FFE possible values.
+ * We get the result for each FFE and eventually the best FFE will
+ * be used and set to the HW.
+ *
+ * Return '1' on succsess.
+ * Return '0' on failure.
+ */
+int comphy_cp110_sfi_rx_training(struct chip_serdes_phy_config *ptr_chip_cfg,
+ u32 lane)
+{
+ int ret;
+ u32 type = ptr_chip_cfg->comphy_map_data[lane].type;
+
+ debug_enter();
+
+ if (type != COMPHY_TYPE_SFI0 && type != COMPHY_TYPE_SFI1) {
+ pr_err("Comphy %d isn't configured to SFI\n", lane);
+ return 0;
+ }
+
+ /* Mode is not relevant for xfi training */
+ ret = comphy_smc(MV_SIP_COMPHY_XFI_TRAIN,
+ ptr_chip_cfg->comphy_base_addr, lane, 0);
+
+ debug_exit();
+
+ return ret;
+}
+
+static int comphy_sata_power_up(u32 lane, void __iomem *hpipe_base,
+ void __iomem *comphy_base_addr, int cp_index,
+ u32 type)
+{
+ u32 mask, data, i, ret = 1;
+ void __iomem *sata_base = NULL;
+ int sata_node = -1; /* Set to -1 in order to read the first sata node */
+
+ debug_enter();
+
+ /*
+ * Assumption - each CP has only one SATA controller
+ * Calling fdt_node_offset_by_compatible first time (with sata_node = -1
+ * will return the first node always.
+ * In order to parse each CPs SATA node, fdt_node_offset_by_compatible
+ * must be called again (according to the CP id)
+ */
+ for (i = 0; i < (cp_index + 1); i++)
+ sata_node = fdt_node_offset_by_compatible(
+ gd->fdt_blob, sata_node, "marvell,armada-8k-ahci");
+
+ if (sata_node == 0) {
+ pr_err("SATA node not found in FDT\n");
+ return 0;
+ }
+
+ sata_base = (void __iomem *)fdtdec_get_addr_size_auto_noparent(
+ gd->fdt_blob, sata_node, "reg", 0, NULL, true);
+ if (sata_base == NULL) {
+ pr_err("SATA address not found in FDT\n");
+ return 0;
+ }
+
+ debug("SATA address found in FDT %p\n", sata_base);
+
+ debug("stage: MAC configuration - power down comphy\n");
+ /*
+ * MAC configuration powe down comphy use indirect address for
+ * vendor spesific SATA control register
+ */
+ reg_set(sata_base + SATA3_VENDOR_ADDRESS,
+ SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET,
+ SATA3_VENDOR_ADDR_MASK);
+ /* SATA 0 power down */
+ mask = SATA3_CTRL_SATA0_PD_MASK;
+ data = 0x1 << SATA3_CTRL_SATA0_PD_OFFSET;
+ /* SATA 1 power down */
+ mask |= SATA3_CTRL_SATA1_PD_MASK;
+ data |= 0x1 << SATA3_CTRL_SATA1_PD_OFFSET;
+ /* SATA SSU disable */
+ mask |= SATA3_CTRL_SATA1_ENABLE_MASK;
+ data |= 0x0 << SATA3_CTRL_SATA1_ENABLE_OFFSET;
+ /* SATA port 1 disable */
+ mask |= SATA3_CTRL_SATA_SSU_MASK;
+ data |= 0x0 << SATA3_CTRL_SATA_SSU_OFFSET;
+ reg_set(sata_base + SATA3_VENDOR_DATA, data, mask);
+
+ ret = comphy_smc(MV_SIP_COMPHY_POWER_ON, comphy_base_addr, lane, type);
+
+ /*
+ * MAC configuration power up comphy - power up PLL/TX/RX
+ * use indirect address for vendor spesific SATA control register
+ */
+ reg_set(sata_base + SATA3_VENDOR_ADDRESS,
+ SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET,
+ SATA3_VENDOR_ADDR_MASK);
+ /* SATA 0 power up */
+ mask = SATA3_CTRL_SATA0_PD_MASK;
+ data = 0x0 << SATA3_CTRL_SATA0_PD_OFFSET;
+ /* SATA 1 power up */
+ mask |= SATA3_CTRL_SATA1_PD_MASK;
+ data |= 0x0 << SATA3_CTRL_SATA1_PD_OFFSET;
+ /* SATA SSU enable */
+ mask |= SATA3_CTRL_SATA1_ENABLE_MASK;
+ data |= 0x1 << SATA3_CTRL_SATA1_ENABLE_OFFSET;
+ /* SATA port 1 enable */
+ mask |= SATA3_CTRL_SATA_SSU_MASK;
+ data |= 0x1 << SATA3_CTRL_SATA_SSU_OFFSET;
+ reg_set(sata_base + SATA3_VENDOR_DATA, data, mask);
+
+ /* MBUS request size and interface select register */
+ reg_set(sata_base + SATA3_VENDOR_ADDRESS,
+ SATA_MBUS_SIZE_SELECT_REG << SATA3_VENDOR_ADDR_OFSSET,
+ SATA3_VENDOR_ADDR_MASK);
+ /* Mbus regret enable */
+ reg_set(sata_base + SATA3_VENDOR_DATA,
+ 0x1 << SATA_MBUS_REGRET_EN_OFFSET, SATA_MBUS_REGRET_EN_MASK);
+
+ ret = comphy_smc(MV_SIP_COMPHY_PLL_LOCK, comphy_base_addr, lane, type);
+
+ debug_exit();
+ return ret;
+}
+
+static void comphy_utmi_power_down(u32 utmi_index, void __iomem *utmi_base_addr,
+ void __iomem *usb_cfg_addr,
+ void __iomem *utmi_cfg_addr,
+ u32 utmi_phy_port)
+{
+ u32 mask, data;
+
+ debug_enter();
+ debug("stage: UTMI %d - Power down transceiver (power down Phy), Power down PLL, and SuspendDM\n",
+ utmi_index);
+ /* Power down UTMI PHY */
+ reg_set(utmi_cfg_addr, 0x0 << UTMI_PHY_CFG_PU_OFFSET,
+ UTMI_PHY_CFG_PU_MASK);
+
+ /*
+ * If UTMI connected to USB Device, configure mux prior to PHY init
+ * (Device can be connected to UTMI0 or to UTMI1)
+ */
+ if (utmi_phy_port == UTMI_PHY_TO_USB3_DEVICE0) {
+ debug("stage: UTMI %d - Enable Device mode and configure UTMI mux\n",
+ utmi_index);
+ /* USB3 Device UTMI enable */
+ mask = UTMI_USB_CFG_DEVICE_EN_MASK;
+ data = 0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET;
+ /* USB3 Device UTMI MUX */
+ mask |= UTMI_USB_CFG_DEVICE_MUX_MASK;
+ data |= utmi_index << UTMI_USB_CFG_DEVICE_MUX_OFFSET;
+ reg_set(usb_cfg_addr, data, mask);
+ }
+
+ /* Set Test suspendm mode */
+ mask = UTMI_CTRL_STATUS0_SUSPENDM_MASK;
+ data = 0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET;
+ /* Enable Test UTMI select */
+ mask |= UTMI_CTRL_STATUS0_TEST_SEL_MASK;
+ data |= 0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET;
+ reg_set(utmi_base_addr + UTMI_CTRL_STATUS0_REG, data, mask);
+
+ /* Wait for UTMI power down */
+ mdelay(1);
+
+ debug_exit();
+ return;
+}
+
+static void comphy_utmi_phy_config(u32 utmi_index, void __iomem *utmi_pll_addr,
+ void __iomem *utmi_base_addr,
+ void __iomem *usb_cfg_addr,
+ void __iomem *utmi_cfg_addr,
+ u32 utmi_phy_port)
+{
+ u32 mask, data;
+
+ debug_exit();
+ debug("stage: Configure UTMI PHY %d registers\n", utmi_index);
+ /* Reference Clock Divider Select */
+ mask = UTMI_PLL_CTRL_REFDIV_MASK;
+ data = 0x5 << UTMI_PLL_CTRL_REFDIV_OFFSET;
+ /* Feedback Clock Divider Select - 90 for 25Mhz*/
+ mask |= UTMI_PLL_CTRL_FBDIV_MASK;
+ data |= 0x60 << UTMI_PLL_CTRL_FBDIV_OFFSET;
+ /* Select LPFR - 0x0 for 25Mhz/5=5Mhz*/
+ mask |= UTMI_PLL_CTRL_SEL_LPFR_MASK;
+ data |= 0x0 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET;
+ reg_set(utmi_pll_addr + UTMI_PLL_CTRL_REG, data, mask);
+
+ /* Impedance Calibration Threshold Setting */
+ mask = UTMI_CALIB_CTRL_IMPCAL_VTH_MASK;
+ data = 0x7 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET;
+ reg_set(utmi_pll_addr + UTMI_CALIB_CTRL_REG, data, mask);
+
+ /* Start Impedance and PLL Calibration */
+ mask = UTMI_CALIB_CTRL_PLLCAL_START_MASK;
+ data = (0x1 << UTMI_CALIB_CTRL_PLLCAL_START_OFFSET);
+ mask |= UTMI_CALIB_CTRL_IMPCAL_START_MASK;
+ data |= (0x1 << UTMI_CALIB_CTRL_IMPCAL_START_OFFSET);
+ reg_set(utmi_pll_addr + UTMI_CALIB_CTRL_REG, data, mask);
+
+ /* Set LS TX driver strength coarse control */
+ mask = UTMI_TX_CH_CTRL_AMP_MASK;
+ data = 0x4 << UTMI_TX_CH_CTRL_AMP_OFFSET;
+ mask |= UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK;
+ data |= 0x3 << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET;
+ mask |= UTMI_TX_CH_CTRL_DRV_EN_LS_MASK;
+ data |= 0x3 << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET;
+ reg_set(utmi_base_addr + UTMI_TX_CH_CTRL_REG, data, mask);
+
+ /* Enable SQ */
+ mask = UTMI_RX_CH_CTRL0_SQ_DET_MASK;
+ data = 0x1 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET;
+ /* Enable analog squelch detect */
+ mask |= UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK;
+ data |= 0x0 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET;
+ mask |= UTMI_RX_CH_CTRL0_DISCON_THRESH_MASK;
+ data |= 0x0 << UTMI_RX_CH_CTRL0_DISCON_THRESH_OFFSET;
+ reg_set(utmi_base_addr + UTMI_RX_CH_CTRL0_REG, data, mask);
+
+ /* Set External squelch calibration number */
+ mask = UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK;
+ data = 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET;
+ /* Enable the External squelch calibration */
+ mask |= UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK;
+ data |= 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET;
+ reg_set(utmi_base_addr + UTMI_RX_CH_CTRL1_REG, data, mask);
+
+ /* Set Control VDAT Reference Voltage - 0.325V */
+ mask = UTMI_CHGDTC_CTRL_VDAT_MASK;
+ data = 0x1 << UTMI_CHGDTC_CTRL_VDAT_OFFSET;
+ /* Set Control VSRC Reference Voltage - 0.6V */
+ mask |= UTMI_CHGDTC_CTRL_VSRC_MASK;
+ data |= 0x1 << UTMI_CHGDTC_CTRL_VSRC_OFFSET;
+ reg_set(utmi_base_addr + UTMI_CHGDTC_CTRL_REG, data, mask);
+
+ debug_exit();
+ return;
+}
+
+static int comphy_utmi_power_up(u32 utmi_index, void __iomem *utmi_pll_addr,
+ void __iomem *utmi_base_addr,
+ void __iomem *usb_cfg_addr,
+ void __iomem *utmi_cfg_addr, u32 utmi_phy_port)
+{
+ u32 data, mask, ret = 1;
+ void __iomem *addr;
+
+ debug_enter();
+ debug("stage: UTMI %d - Power up transceiver(Power up Phy), and exit SuspendDM\n",
+ utmi_index);
+ /* Power UP UTMI PHY */
+ reg_set(utmi_cfg_addr, 0x1 << UTMI_PHY_CFG_PU_OFFSET,
+ UTMI_PHY_CFG_PU_MASK);
+ /* Disable Test UTMI select */
+ reg_set(utmi_base_addr + UTMI_CTRL_STATUS0_REG,
+ 0x0 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET,
+ UTMI_CTRL_STATUS0_TEST_SEL_MASK);
+
+ debug("stage: Polling for PLL and impedance calibration done, and PLL ready done\n");
+ addr = utmi_pll_addr + UTMI_CALIB_CTRL_REG;
+ data = UTMI_CALIB_CTRL_IMPCAL_DONE_MASK;
+ mask = data;
+ data = polling_with_timeout(addr, data, mask, 100);
+ if (data != 0) {
+ pr_err("Impedance calibration is not done\n");
+ debug("Read from reg = %p - value = 0x%x\n", addr, data);
+ ret = 0;
+ }
+
+ data = UTMI_CALIB_CTRL_PLLCAL_DONE_MASK;
+ mask = data;
+ data = polling_with_timeout(addr, data, mask, 100);
+ if (data != 0) {
+ pr_err("PLL calibration is not done\n");
+ debug("Read from reg = %p - value = 0x%x\n", addr, data);
+ ret = 0;
+ }
+
+ addr = utmi_pll_addr + UTMI_PLL_CTRL_REG;
+ data = UTMI_PLL_CTRL_PLL_RDY_MASK;
+ mask = data;
+ data = polling_with_timeout(addr, data, mask, 100);
+ if (data != 0) {
+ pr_err("PLL is not ready\n");
+ debug("Read from reg = %p - value = 0x%x\n", addr, data);
+ ret = 0;
+ }
+
+ if (ret)
+ debug("Passed\n");
+ else
+ debug("\n");
+
+ debug_exit();
+ return ret;
+}
+
+/*
+ * comphy_utmi_phy_init initialize the UTMI PHY
+ * the init split in 3 parts:
+ * 1. Power down transceiver and PLL
+ * 2. UTMI PHY configure
+ * 3. Power up transceiver and PLL
+ * Note: - Power down/up should be once for both UTMI PHYs
+ * - comphy_dedicated_phys_init call this function if at least there is
+ * one UTMI PHY exists in FDT blob. access to cp110_utmi_data[0] is
+ * legal
+ */
+static void comphy_utmi_phy_init(u32 utmi_phy_count,
+ struct utmi_phy_data *cp110_utmi_data)
+{
+ u32 i;
+
+ debug_enter();
+ /* UTMI Power down */
+ for (i = 0; i < utmi_phy_count; i++) {
+ comphy_utmi_power_down(i, cp110_utmi_data[i].utmi_base_addr,
+ cp110_utmi_data[i].usb_cfg_addr,
+ cp110_utmi_data[i].utmi_cfg_addr,
+ cp110_utmi_data[i].utmi_phy_port);
+ }
+ /* PLL Power down */
+ debug("stage: UTMI PHY power down PLL\n");
+ for (i = 0; i < utmi_phy_count; i++) {
+ reg_set(cp110_utmi_data[i].usb_cfg_addr,
+ 0x0 << UTMI_USB_CFG_PLL_OFFSET, UTMI_USB_CFG_PLL_MASK);
+ }
+ /* UTMI configure */
+ for (i = 0; i < utmi_phy_count; i++) {
+ comphy_utmi_phy_config(i, cp110_utmi_data[i].utmi_pll_addr,
+ cp110_utmi_data[i].utmi_base_addr,
+ cp110_utmi_data[i].usb_cfg_addr,
+ cp110_utmi_data[i].utmi_cfg_addr,
+ cp110_utmi_data[i].utmi_phy_port);
+ }
+ /* UTMI Power up */
+ for (i = 0; i < utmi_phy_count; i++) {
+ if (!comphy_utmi_power_up(i, cp110_utmi_data[i].utmi_pll_addr,
+ cp110_utmi_data[i].utmi_base_addr,
+ cp110_utmi_data[i].usb_cfg_addr,
+ cp110_utmi_data[i].utmi_cfg_addr,
+ cp110_utmi_data[i].utmi_phy_port)) {
+ pr_err("Failed to initialize UTMI PHY %d\n", i);
+ continue;
+ }
+ printf("UTMI PHY %d initialized to ", i);
+ if (cp110_utmi_data[i].utmi_phy_port ==
+ UTMI_PHY_TO_USB3_DEVICE0)
+ printf("USB Device\n");
+ else
+ printf("USB Host%d\n",
+ cp110_utmi_data[i].utmi_phy_port);
+ }
+ /* PLL Power up */
+ debug("stage: UTMI PHY power up PLL\n");
+ for (i = 0; i < utmi_phy_count; i++) {
+ reg_set(cp110_utmi_data[i].usb_cfg_addr,
+ 0x1 << UTMI_USB_CFG_PLL_OFFSET, UTMI_USB_CFG_PLL_MASK);
+ }
+
+ debug_exit();
+ return;
+}
+
+/*
+ * comphy_dedicated_phys_init initialize the dedicated PHYs
+ * - not muxed SerDes lanes e.g. UTMI PHY
+ */
+void comphy_dedicated_phys_init(void)
+{
+ struct utmi_phy_data cp110_utmi_data[MAX_UTMI_PHY_COUNT];
+ int node = -1;
+ int node_idx;
+ int parent = -1;
+
+ debug_enter();
+ debug("Initialize USB UTMI PHYs\n");
+
+ for (node_idx = 0; node_idx < MAX_UTMI_PHY_COUNT;) {
+ /* Find the UTMI phy node in device tree */
+ node = fdt_node_offset_by_compatible(gd->fdt_blob, node,
+ "marvell,mvebu-utmi-2.6.0");
+ if (node <= 0)
+ break;
+
+ /* check if node is enabled */
+ if (!fdtdec_get_is_enabled(gd->fdt_blob, node))
+ continue;
+
+ parent = fdt_parent_offset(gd->fdt_blob, node);
+ if (parent <= 0)
+ break;
+
+ /* get base address of UTMI PLL */
+ cp110_utmi_data[node_idx].utmi_pll_addr =
+ (void __iomem *)fdtdec_get_addr_size_auto_noparent(
+ gd->fdt_blob, parent, "reg", 0, NULL, true);
+ if (!cp110_utmi_data[node_idx].utmi_pll_addr) {
+ pr_err("UTMI PHY PLL address is invalid\n");
+ continue;
+ }
+
+ /* get base address of UTMI phy */
+ cp110_utmi_data[node_idx].utmi_base_addr =
+ (void __iomem *)fdtdec_get_addr_size_auto_noparent(
+ gd->fdt_blob, node, "reg", 0, NULL, true);
+ if (!cp110_utmi_data[node_idx].utmi_base_addr) {
+ pr_err("UTMI PHY base address is invalid\n");
+ continue;
+ }
+
+ /* get usb config address */
+ cp110_utmi_data[node_idx].usb_cfg_addr =
+ (void __iomem *)fdtdec_get_addr_size_auto_noparent(
+ gd->fdt_blob, node, "reg", 1, NULL, true);
+ if (!cp110_utmi_data[node_idx].usb_cfg_addr) {
+ pr_err("UTMI PHY base address is invalid\n");
+ continue;
+ }
+
+ /* get UTMI config address */
+ cp110_utmi_data[node_idx].utmi_cfg_addr =
+ (void __iomem *)fdtdec_get_addr_size_auto_noparent(
+ gd->fdt_blob, node, "reg", 2, NULL, true);
+ if (!cp110_utmi_data[node_idx].utmi_cfg_addr) {
+ pr_err("UTMI PHY base address is invalid\n");
+ continue;
+ }
+
+ /*
+ * get the port number (to check if the utmi connected to
+ * host/device)
+ */
+ cp110_utmi_data[node_idx].utmi_phy_port = fdtdec_get_int(
+ gd->fdt_blob, node, "utmi-port", UTMI_PHY_INVALID);
+ if (cp110_utmi_data[node_idx].utmi_phy_port ==
+ UTMI_PHY_INVALID) {
+ pr_err("UTMI PHY port type is invalid\n");
+ continue;
+ }
+
+ /* count valid UTMI unit */
+ node_idx++;
+ }
+
+ if (node_idx > 0)
+ comphy_utmi_phy_init(node_idx, cp110_utmi_data);
+
+ debug_exit();
+}
+
+int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
+ struct comphy_map *serdes_map)
+{
+ struct comphy_map *ptr_comphy_map;
+ void __iomem *comphy_base_addr, *hpipe_base_addr;
+ u32 comphy_max_count, lane, id, ret = 0;
+ u32 pcie_width = 0;
+ u32 mode;
+
+ debug_enter();
+
+ comphy_max_count = ptr_chip_cfg->comphy_lanes_count;
+ comphy_base_addr = ptr_chip_cfg->comphy_base_addr;
+ hpipe_base_addr = ptr_chip_cfg->hpipe3_base_addr;
+
+ /* Check if the first 4 lanes configured as By-4 */
+ for (lane = 0, ptr_comphy_map = serdes_map; lane < 4;
+ lane++, ptr_comphy_map++) {
+ if (ptr_comphy_map->type != COMPHY_TYPE_PEX0)
+ break;
+ pcie_width++;
+ }
+
+ for (lane = 0, ptr_comphy_map = serdes_map; lane < comphy_max_count;
+ lane++, ptr_comphy_map++) {
+ debug("Initialize serdes number %d\n", lane);
+ debug("Serdes type = 0x%x\n", ptr_comphy_map->type);
+ if (lane == 4) {
+ /*
+ * PCIe lanes above the first 4 lanes, can be only
+ * by1
+ */
+ pcie_width = 1;
+ }
+ switch (ptr_comphy_map->type) {
+ case COMPHY_TYPE_UNCONNECTED:
+ mode = COMPHY_TYPE_UNCONNECTED | COMPHY_CALLER_UBOOT;
+ ret = comphy_smc(MV_SIP_COMPHY_POWER_OFF,
+ ptr_chip_cfg->comphy_base_addr,
+ lane, mode);
+ case COMPHY_TYPE_IGNORE:
+ continue;
+ break;
+ case COMPHY_TYPE_PEX0:
+ case COMPHY_TYPE_PEX1:
+ case COMPHY_TYPE_PEX2:
+ case COMPHY_TYPE_PEX3:
+ mode = COMPHY_FW_PCIE_FORMAT(pcie_width,
+ ptr_comphy_map->clk_src,
+ COMPHY_PCIE_MODE,
+ ptr_comphy_map->speed);
+ ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
+ ptr_chip_cfg->comphy_base_addr, lane,
+ mode);
+ break;
+ case COMPHY_TYPE_SATA0:
+ case COMPHY_TYPE_SATA1:
+ mode = COMPHY_FW_MODE_FORMAT(COMPHY_SATA_MODE);
+ ret = comphy_sata_power_up(lane, hpipe_base_addr,
+ comphy_base_addr,
+ ptr_chip_cfg->cp_index,
+ mode);
+ break;
+ case COMPHY_TYPE_USB3_HOST0:
+ case COMPHY_TYPE_USB3_HOST1:
+ mode = COMPHY_FW_MODE_FORMAT(COMPHY_USB3H_MODE);
+ ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
+ ptr_chip_cfg->comphy_base_addr, lane,
+ mode);
+ break;
+ case COMPHY_TYPE_USB3_DEVICE:
+ mode = COMPHY_FW_MODE_FORMAT(COMPHY_USB3D_MODE);
+ ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
+ ptr_chip_cfg->comphy_base_addr, lane,
+ mode);
+ break;
+ case COMPHY_TYPE_SGMII0:
+ case COMPHY_TYPE_SGMII1:
+ case COMPHY_TYPE_SGMII2:
+ /* Calculate SGMII ID */
+ id = ptr_comphy_map->type - COMPHY_TYPE_SGMII0;
+
+ if (ptr_comphy_map->speed == COMPHY_SPEED_INVALID) {
+ debug("Warning: SGMII PHY speed in lane %d is invalid, set PHY speed to 1.25G\n",
+ lane);
+ ptr_comphy_map->speed = COMPHY_SPEED_1_25G;
+ }
+
+ mode = COMPHY_FW_FORMAT(COMPHY_SGMII_MODE, id,
+ ptr_comphy_map->speed);
+ ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
+ ptr_chip_cfg->comphy_base_addr, lane,
+ mode);
+ break;
+ case COMPHY_TYPE_SFI0:
+ case COMPHY_TYPE_SFI1:
+ /* Calculate SFI id */
+ id = ptr_comphy_map->type - COMPHY_TYPE_SFI0;
+ mode = COMPHY_FW_FORMAT(COMPHY_SFI_MODE, id,
+ ptr_comphy_map->speed);
+ ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
+ ptr_chip_cfg->comphy_base_addr, lane, mode);
+ break;
+ case COMPHY_TYPE_RXAUI0:
+ case COMPHY_TYPE_RXAUI1:
+ mode = COMPHY_FW_MODE_FORMAT(COMPHY_RXAUI_MODE);
+ ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
+ ptr_chip_cfg->comphy_base_addr, lane,
+ mode);
+ break;
+ default:
+ debug("Unknown SerDes type, skip initialize SerDes %d\n",
+ lane);
+ break;
+ }
+ if (ret == 0) {
+ /*
+ * If interface wans't initialized, set the lane to
+ * COMPHY_TYPE_UNCONNECTED state.
+ */
+ ptr_comphy_map->type = COMPHY_TYPE_UNCONNECTED;
+ pr_err("PLL is not locked - Failed to initialize lane %d\n",
+ lane);
+ }
+ }
+
+ debug_exit();
+ return 0;
+}
diff --git a/roms/u-boot/drivers/phy/marvell/comphy_mux.c b/roms/u-boot/drivers/phy/marvell/comphy_mux.c
new file mode 100644
index 000000000..10981d25e
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/comphy_mux.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+
+#include "comphy_core.h"
+
+/*
+ * comphy_mux_check_config()
+ * description: this function passes over the COMPHY lanes and check if the type
+ * is valid for specific lane. If the type is not valid,
+ * the function update the struct and set the type of the lane as
+ * COMPHY_TYPE_UNCONNECTED
+ */
+static void comphy_mux_check_config(struct comphy_mux_data *mux_data,
+ struct comphy_map *comphy_map_data, int comphy_max_lanes)
+{
+ struct comphy_mux_options *mux_opt;
+ int lane, opt, valid;
+
+ debug_enter();
+
+ for (lane = 0; lane < comphy_max_lanes;
+ lane++, comphy_map_data++, mux_data++) {
+ /* Don't check ignored COMPHYs */
+ if (comphy_map_data->type == COMPHY_TYPE_IGNORE)
+ continue;
+
+ mux_opt = mux_data->mux_values;
+ for (opt = 0, valid = 0; opt < mux_data->max_lane_values;
+ opt++, mux_opt++) {
+ if (mux_opt->type == comphy_map_data->type) {
+ valid = 1;
+ break;
+ }
+ }
+ if (valid == 0) {
+ debug("lane number %d, had invalid type %d\n",
+ lane, comphy_map_data->type);
+ debug("set lane %d as type %d\n", lane,
+ COMPHY_TYPE_UNCONNECTED);
+ comphy_map_data->type = COMPHY_TYPE_UNCONNECTED;
+ } else {
+ debug("lane number %d, has type %d\n",
+ lane, comphy_map_data->type);
+ }
+ }
+
+ debug_exit();
+}
+
+static u32 comphy_mux_get_mux_value(struct comphy_mux_data *mux_data,
+ u32 type, int lane)
+{
+ struct comphy_mux_options *mux_opt;
+ int opt;
+ u32 value = 0;
+
+ debug_enter();
+
+ mux_opt = mux_data->mux_values;
+ for (opt = 0 ; opt < mux_data->max_lane_values; opt++, mux_opt++) {
+ if (mux_opt->type == type) {
+ value = mux_opt->mux_value;
+ break;
+ }
+ }
+
+ debug_exit();
+
+ return value;
+}
+
+static void comphy_mux_reg_write(struct comphy_mux_data *mux_data,
+ struct comphy_map *comphy_map_data,
+ int comphy_max_lanes,
+ void __iomem *selector_base,
+ const fdt32_t *mux_lane_order, u32 bitcount)
+{
+ u32 lane, value, offset, mask;
+
+ debug_enter();
+
+ for (lane = 0; lane < comphy_max_lanes;
+ lane++, comphy_map_data++, mux_data++) {
+ if (comphy_map_data->type == COMPHY_TYPE_IGNORE)
+ continue;
+
+ /*
+ * if the order of nodes in selector base register is
+ * nontrivial, use mapping from mux_lane_order
+ */
+ if (mux_lane_order)
+ offset = fdt32_to_cpu(mux_lane_order[lane]) * bitcount;
+ else
+ offset = lane * bitcount;
+
+ mask = (((1 << bitcount) - 1) << offset);
+ value = (comphy_mux_get_mux_value(mux_data,
+ comphy_map_data->type,
+ lane) << offset);
+ reg_set(selector_base, value, mask);
+ }
+
+ debug_exit();
+}
+
+void comphy_mux_init(struct chip_serdes_phy_config *chip_cfg,
+ struct comphy_map *comphy_map_data,
+ void __iomem *selector_base)
+{
+ struct comphy_mux_data *mux_data;
+ const fdt32_t *mux_lane_order;
+ u32 mux_bitcount;
+ u32 comphy_max_lanes;
+
+ debug_enter();
+
+ comphy_max_lanes = chip_cfg->comphy_lanes_count;
+ mux_data = chip_cfg->mux_data;
+ mux_lane_order = chip_cfg->comphy_mux_lane_order;
+ mux_bitcount = chip_cfg->comphy_mux_bitcount;
+
+ /* check if the configuration is valid */
+ comphy_mux_check_config(mux_data, comphy_map_data, comphy_max_lanes);
+ /* Init COMPHY selectors */
+ comphy_mux_reg_write(mux_data, comphy_map_data, comphy_max_lanes,
+ selector_base, mux_lane_order, mux_bitcount);
+
+ debug_exit();
+}
diff --git a/roms/u-boot/drivers/phy/marvell/sata.h b/roms/u-boot/drivers/phy/marvell/sata.h
new file mode 100644
index 000000000..41db7aa8b
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/sata.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+ */
+
+#ifndef _SATA_H_
+#define _SATA_H_
+
+/* SATA3 Unit address */
+#define SATA3_VENDOR_ADDRESS 0xA0
+#define SATA3_VENDOR_ADDR_OFSSET 0
+#define SATA3_VENDOR_ADDR_MASK (0xFFFFFFFF << SATA3_VENDOR_ADDR_OFSSET)
+#define SATA3_VENDOR_DATA 0xA4
+
+#define SATA_CONTROL_REG 0x0
+#define SATA3_CTRL_SATA0_PD_OFFSET 6
+#define SATA3_CTRL_SATA0_PD_MASK (1 << SATA3_CTRL_SATA0_PD_OFFSET)
+#define SATA3_CTRL_SATA1_PD_OFFSET 14
+#define SATA3_CTRL_SATA1_PD_MASK (1 << SATA3_CTRL_SATA1_PD_OFFSET)
+#define SATA3_CTRL_SATA1_ENABLE_OFFSET 22
+#define SATA3_CTRL_SATA1_ENABLE_MASK (1 << SATA3_CTRL_SATA1_ENABLE_OFFSET)
+#define SATA3_CTRL_SATA_SSU_OFFSET 23
+#define SATA3_CTRL_SATA_SSU_MASK (1 << SATA3_CTRL_SATA_SSU_OFFSET)
+
+#define SATA_MBUS_SIZE_SELECT_REG 0x4
+#define SATA_MBUS_REGRET_EN_OFFSET 7
+#define SATA_MBUS_REGRET_EN_MASK (0x1 << SATA_MBUS_REGRET_EN_OFFSET)
+
+#endif /* _SATA_H_ */
diff --git a/roms/u-boot/drivers/phy/marvell/utmi_phy.h b/roms/u-boot/drivers/phy/marvell/utmi_phy.h
new file mode 100644
index 000000000..8a570bae7
--- /dev/null
+++ b/roms/u-boot/drivers/phy/marvell/utmi_phy.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+ */
+
+#ifndef _UTMI_PHY_H_
+#define _UTMI_PHY_H_
+
+#define UTMI_USB_CFG_DEVICE_EN_OFFSET 0
+#define UTMI_USB_CFG_DEVICE_EN_MASK \
+ (0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET)
+#define UTMI_USB_CFG_DEVICE_MUX_OFFSET 1
+#define UTMI_USB_CFG_DEVICE_MUX_MASK \
+ (0x1 << UTMI_USB_CFG_DEVICE_MUX_OFFSET)
+#define UTMI_USB_CFG_PLL_OFFSET 25
+#define UTMI_USB_CFG_PLL_MASK \
+ (0x1 << UTMI_USB_CFG_PLL_OFFSET)
+
+#define UTMI_PHY_CFG_PU_OFFSET 5
+#define UTMI_PHY_CFG_PU_MASK \
+ (0x1 << UTMI_PHY_CFG_PU_OFFSET)
+
+#define UTMI_PLL_CTRL_REG 0x0
+#define UTMI_PLL_CTRL_REFDIV_OFFSET 0
+#define UTMI_PLL_CTRL_REFDIV_MASK \
+ (0x7f << UTMI_PLL_CTRL_REFDIV_OFFSET)
+#define UTMI_PLL_CTRL_FBDIV_OFFSET 16
+#define UTMI_PLL_CTRL_FBDIV_MASK \
+ (0x1FF << UTMI_PLL_CTRL_FBDIV_OFFSET)
+#define UTMI_PLL_CTRL_SEL_LPFR_OFFSET 28
+#define UTMI_PLL_CTRL_SEL_LPFR_MASK \
+ (0x3 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET)
+#define UTMI_PLL_CTRL_PLL_RDY_OFFSET 31
+#define UTMI_PLL_CTRL_PLL_RDY_MASK \
+ (0x1 << UTMI_PLL_CTRL_PLL_RDY_OFFSET)
+
+#define UTMI_CALIB_CTRL_REG 0x8
+#define UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET 8
+#define UTMI_CALIB_CTRL_IMPCAL_VTH_MASK \
+ (0x7 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET)
+#define UTMI_CALIB_CTRL_IMPCAL_START_OFFSET 13
+#define UTMI_CALIB_CTRL_IMPCAL_START_MASK \
+ (0x1 << UTMI_CALIB_CTRL_IMPCAL_START_OFFSET)
+#define UTMI_CALIB_CTRL_PLLCAL_START_OFFSET 22
+#define UTMI_CALIB_CTRL_PLLCAL_START_MASK \
+ (0x1 << UTMI_CALIB_CTRL_PLLCAL_START_OFFSET)
+#define UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET 23
+#define UTMI_CALIB_CTRL_IMPCAL_DONE_MASK \
+ (0x1 << UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET)
+#define UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET 31
+#define UTMI_CALIB_CTRL_PLLCAL_DONE_MASK \
+ (0x1 << UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET)
+
+#define UTMI_TX_CH_CTRL_REG 0x0
+#define UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET 12
+#define UTMI_TX_CH_CTRL_DRV_EN_LS_MASK \
+ (0xf << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET)
+#define UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET 16
+#define UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK \
+ (0xf << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET)
+#define UTMI_TX_CH_CTRL_AMP_OFFSET 20
+#define UTMI_TX_CH_CTRL_AMP_MASK \
+ (0x7 << UTMI_TX_CH_CTRL_AMP_OFFSET)
+
+#define UTMI_RX_CH_CTRL0_REG 0x8
+#define UTMI_RX_CH_CTRL0_DISCON_THRESH_OFFSET 8
+#define UTMI_RX_CH_CTRL0_DISCON_THRESH_MASK \
+ (0x3 << UTMI_RX_CH_CTRL0_DISCON_THRESH_OFFSET)
+#define UTMI_RX_CH_CTRL0_SQ_DET_OFFSET 15
+#define UTMI_RX_CH_CTRL0_SQ_DET_MASK \
+ (0x1 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET)
+#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET 28
+#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK \
+ (0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET)
+
+#define UTMI_RX_CH_CTRL1_REG 0xc
+#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET 0
+#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK \
+ (0x7 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET)
+#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET 3
+#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK \
+ (0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET)
+
+#define UTMI_CTRL_STATUS0_REG 0x18
+#define UTMI_CTRL_STATUS0_SUSPENDM_OFFSET 22
+#define UTMI_CTRL_STATUS0_SUSPENDM_MASK \
+ (0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET)
+#define UTMI_CTRL_STATUS0_TEST_SEL_OFFSET 25
+#define UTMI_CTRL_STATUS0_TEST_SEL_MASK \
+ (0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET)
+
+#define UTMI_CHGDTC_CTRL_REG 0x2c
+#define UTMI_CHGDTC_CTRL_VDAT_OFFSET 8
+#define UTMI_CHGDTC_CTRL_VDAT_MASK \
+ (0x3 << UTMI_CHGDTC_CTRL_VDAT_OFFSET)
+#define UTMI_CHGDTC_CTRL_VSRC_OFFSET 10
+#define UTMI_CHGDTC_CTRL_VSRC_MASK \
+ (0x3 << UTMI_CHGDTC_CTRL_VSRC_OFFSET)
+
+#endif /* _UTMI_PHY_H_ */
+
diff --git a/roms/u-boot/drivers/phy/meson-axg-mipi-dphy.c b/roms/u-boot/drivers/phy/meson-axg-mipi-dphy.c
new file mode 100644
index 000000000..8b2469793
--- /dev/null
+++ b/roms/u-boot/drivers/phy/meson-axg-mipi-dphy.c
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Meson AXG MIPI DPHY driver
+ *
+ * Copyright (C) 2018 Amlogic, Inc. All rights reserved
+ * Copyright (C) 2020 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <bitfield.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+#include <reset.h>
+#include <clk.h>
+#include <phy-mipi-dphy.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <linux/bitfield.h>
+
+/* [31] soft reset for the phy.
+ * 1: reset. 0: dessert the reset.
+ * [30] clock lane soft reset.
+ * [29] data byte lane 3 soft reset.
+ * [28] data byte lane 2 soft reset.
+ * [27] data byte lane 1 soft reset.
+ * [26] data byte lane 0 soft reset.
+ * [25] mipi dsi pll clock selection.
+ * 1: clock from fixed 850Mhz clock source. 0: from VID2 PLL.
+ * [12] mipi HSbyteclk enable.
+ * [11] mipi divider clk selection.
+ * 1: select the mipi DDRCLKHS from clock divider.
+ * 0: from PLL clock.
+ * [10] mipi clock divider control.
+ * 1: /4. 0: /2.
+ * [9] mipi divider output enable.
+ * [8] mipi divider counter enable.
+ * [7] PLL clock enable.
+ * [5] LPDT data endian.
+ * 1 = transfer the high bit first. 0 : transfer the low bit first.
+ * [4] HS data endian.
+ * [3] force data byte lane in stop mode.
+ * [2] force data byte lane 0 in receiver mode.
+ * [1] write 1 to sync the txclkesc input. the internal logic have to
+ * use txclkesc to decide Txvalid and Txready.
+ * [0] enalbe the MIPI DPHY TxDDRClk.
+ */
+#define MIPI_DSI_PHY_CTRL 0x0
+
+/* [31] clk lane tx_hs_en control selection.
+ * 1: from register. 0: use clk lane state machine.
+ * [30] register bit for clock lane tx_hs_en.
+ * [29] clk lane tx_lp_en contrl selection.
+ * 1: from register. 0: from clk lane state machine.
+ * [28] register bit for clock lane tx_lp_en.
+ * [27] chan0 tx_hs_en control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [26] register bit for chan0 tx_hs_en.
+ * [25] chan0 tx_lp_en control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [24] register bit from chan0 tx_lp_en.
+ * [23] chan0 rx_lp_en control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [22] register bit from chan0 rx_lp_en.
+ * [21] chan0 contention detection enable control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [20] register bit from chan0 contention dectection enable.
+ * [19] chan1 tx_hs_en control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [18] register bit for chan1 tx_hs_en.
+ * [17] chan1 tx_lp_en control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [16] register bit from chan1 tx_lp_en.
+ * [15] chan2 tx_hs_en control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [14] register bit for chan2 tx_hs_en.
+ * [13] chan2 tx_lp_en control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [12] register bit from chan2 tx_lp_en.
+ * [11] chan3 tx_hs_en control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [10] register bit for chan3 tx_hs_en.
+ * [9] chan3 tx_lp_en control selection.
+ * 1: from register. 0: from chan0 state machine.
+ * [8] register bit from chan3 tx_lp_en.
+ * [4] clk chan power down. this bit is also used as the power down
+ * of the whole MIPI_DSI_PHY.
+ * [3] chan3 power down.
+ * [2] chan2 power down.
+ * [1] chan1 power down.
+ * [0] chan0 power down.
+ */
+#define MIPI_DSI_CHAN_CTRL 0x4
+
+/* [24] rx turn watch dog triggered.
+ * [23] rx esc watchdog triggered.
+ * [22] mbias ready.
+ * [21] txclkesc synced and ready.
+ * [20:17] clk lane state. {mbias_ready, tx_stop, tx_ulps, tx_hs_active}
+ * [16:13] chan3 state{0, tx_stop, tx_ulps, tx_hs_active}
+ * [12:9] chan2 state.{0, tx_stop, tx_ulps, tx_hs_active}
+ * [8:5] chan1 state. {0, tx_stop, tx_ulps, tx_hs_active}
+ * [4:0] chan0 state. {TX_STOP, tx_ULPS, hs_active, direction, rxulpsesc}
+ */
+#define MIPI_DSI_CHAN_STS 0x8
+
+/* [31:24] TCLK_PREPARE.
+ * [23:16] TCLK_ZERO.
+ * [15:8] TCLK_POST.
+ * [7:0] TCLK_TRAIL.
+ */
+#define MIPI_DSI_CLK_TIM 0xc
+
+/* [31:24] THS_PREPARE.
+ * [23:16] THS_ZERO.
+ * [15:8] THS_TRAIL.
+ * [7:0] THS_EXIT.
+ */
+#define MIPI_DSI_HS_TIM 0x10
+
+/* [31:24] tTA_GET.
+ * [23:16] tTA_GO.
+ * [15:8] tTA_SURE.
+ * [7:0] tLPX.
+ */
+#define MIPI_DSI_LP_TIM 0x14
+
+/* wait time to MIPI DIS analog ready. */
+#define MIPI_DSI_ANA_UP_TIM 0x18
+
+/* TINIT. */
+#define MIPI_DSI_INIT_TIM 0x1c
+
+/* TWAKEUP. */
+#define MIPI_DSI_WAKEUP_TIM 0x20
+
+/* when in RxULPS check state, after the the logic enable the analog,
+ * how long we should wait to check the lP state .
+ */
+#define MIPI_DSI_LPOK_TIM 0x24
+
+/* Watchdog for RX low power state no finished. */
+#define MIPI_DSI_LP_WCHDOG 0x28
+
+/* tMBIAS, after send power up signals to analog,
+ * how long we should wait for analog powered up.
+ */
+#define MIPI_DSI_ANA_CTRL 0x2c
+
+/* [31:8] reserved for future.
+ * [7:0] tCLK_PRE.
+ */
+#define MIPI_DSI_CLK_TIM1 0x30
+
+/* watchdog for turn around waiting time. */
+#define MIPI_DSI_TURN_WCHDOG 0x34
+
+/* When in RxULPS state, how frequency we should to check
+ * if the TX side out of ULPS state.
+ */
+#define MIPI_DSI_ULPS_CHECK 0x38
+#define MIPI_DSI_TEST_CTRL0 0x3c
+#define MIPI_DSI_TEST_CTRL1 0x40
+
+#define NSEC_PER_MSEC 1000000L
+
+struct phy_meson_axg_mipi_dphy_priv {
+ struct regmap *regmap;
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+#endif
+ struct reset_ctl reset;
+ struct phy analog;
+ struct phy_configure_opts_mipi_dphy config;
+};
+
+static int phy_meson_axg_mipi_dphy_configure(struct phy *phy, void *params)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_axg_mipi_dphy_priv *priv = dev_get_priv(dev);
+ struct phy_configure_opts_mipi_dphy *config = params;
+ int ret;
+
+ ret = phy_mipi_dphy_config_validate(config);
+ if (ret)
+ return ret;
+
+ ret = generic_phy_configure(&priv->analog, config);
+ if (ret)
+ return ret;
+
+ memcpy(&priv->config, config, sizeof(priv->config));
+
+ return 0;
+}
+
+static int phy_meson_axg_mipi_dphy_power_on(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_axg_mipi_dphy_priv *priv = dev_get_priv(dev);
+ unsigned long temp;
+ int ret;
+
+ ret = generic_phy_power_on(&priv->analog);
+ if (ret)
+ return ret;
+
+ /* enable phy clock */
+ regmap_write(priv->regmap, MIPI_DSI_PHY_CTRL, 0x1);
+ regmap_write(priv->regmap, MIPI_DSI_PHY_CTRL,
+ BIT(0) | /* enable the DSI PLL clock . */
+ BIT(7) | /* enable pll clock which connected to DDR clock path */
+ BIT(8)); /* enable the clock divider counter */
+
+ /* enable the divider clock out */
+ regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(9), BIT(9));
+
+ /* enable the byte clock generation. */
+ regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(12), BIT(12));
+ regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(31), BIT(31));
+ regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(31), 0);
+
+ /* Calculate lanebyteclk period in ps */
+ temp = (1000000 * 100) / (priv->config.hs_clk_rate / 1000);
+ temp = temp * 8 * 10;
+
+ regmap_write(priv->regmap, MIPI_DSI_CLK_TIM,
+ DIV_ROUND_UP(priv->config.clk_trail, temp) |
+ (DIV_ROUND_UP(priv->config.clk_post +
+ priv->config.hs_trail, temp) << 8) |
+ (DIV_ROUND_UP(priv->config.clk_zero, temp) << 16) |
+ (DIV_ROUND_UP(priv->config.clk_prepare, temp) << 24));
+ regmap_write(priv->regmap, MIPI_DSI_CLK_TIM1,
+ DIV_ROUND_UP(priv->config.clk_pre, temp));
+
+ regmap_write(priv->regmap, MIPI_DSI_HS_TIM,
+ DIV_ROUND_UP(priv->config.hs_exit, temp) |
+ (DIV_ROUND_UP(priv->config.hs_trail, temp) << 8) |
+ (DIV_ROUND_UP(priv->config.hs_zero, temp) << 16) |
+ (DIV_ROUND_UP(priv->config.hs_prepare, temp) << 24));
+
+ regmap_write(priv->regmap, MIPI_DSI_LP_TIM,
+ DIV_ROUND_UP(priv->config.lpx, temp) |
+ (DIV_ROUND_UP(priv->config.ta_sure, temp) << 8) |
+ (DIV_ROUND_UP(priv->config.ta_go, temp) << 16) |
+ (DIV_ROUND_UP(priv->config.ta_get, temp) << 24));
+
+ regmap_write(priv->regmap, MIPI_DSI_ANA_UP_TIM, 0x0100);
+ regmap_write(priv->regmap, MIPI_DSI_INIT_TIM,
+ DIV_ROUND_UP(priv->config.init * NSEC_PER_MSEC, temp));
+ regmap_write(priv->regmap, MIPI_DSI_WAKEUP_TIM,
+ DIV_ROUND_UP(priv->config.wakeup * NSEC_PER_MSEC, temp));
+ regmap_write(priv->regmap, MIPI_DSI_LPOK_TIM, 0x7C);
+ regmap_write(priv->regmap, MIPI_DSI_ULPS_CHECK, 0x927C);
+ regmap_write(priv->regmap, MIPI_DSI_LP_WCHDOG, 0x1000);
+ regmap_write(priv->regmap, MIPI_DSI_TURN_WCHDOG, 0x1000);
+
+ /* Powerup the analog circuit */
+ switch (priv->config.lanes) {
+ case 1:
+ regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0xe);
+ break;
+ case 2:
+ regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0xc);
+ break;
+ case 3:
+ regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0x8);
+ break;
+ case 4:
+ default:
+ regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0);
+ break;
+ }
+
+ /* Trigger a sync active for esc_clk */
+ regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(1), BIT(1));
+
+ return 0;
+}
+
+static int phy_meson_axg_mipi_dphy_power_off(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_axg_mipi_dphy_priv *priv = dev_get_priv(dev);
+
+ regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0xf);
+ regmap_write(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(31));
+
+ return generic_phy_power_off(&priv->analog);
+}
+
+static int phy_meson_axg_mipi_dphy_init(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_axg_mipi_dphy_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = generic_phy_init(&priv->analog);
+ if (ret)
+ return ret;
+
+ ret = reset_assert(&priv->reset);
+ udelay(1);
+ ret |= reset_deassert(&priv->reset);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int phy_meson_axg_mipi_dphy_exit(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_axg_mipi_dphy_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = generic_phy_exit(&priv->analog);
+ if (ret)
+ return ret;
+
+ return reset_assert(&priv->reset);
+}
+
+struct phy_ops meson_axg_mipi_dphy_ops = {
+ .init = phy_meson_axg_mipi_dphy_init,
+ .exit = phy_meson_axg_mipi_dphy_exit,
+ .power_on = phy_meson_axg_mipi_dphy_power_on,
+ .power_off = phy_meson_axg_mipi_dphy_power_off,
+ .configure = phy_meson_axg_mipi_dphy_configure,
+};
+
+int meson_axg_mipi_dphy_probe(struct udevice *dev)
+{
+ struct phy_meson_axg_mipi_dphy_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+ if (ret)
+ return ret;
+
+ ret = generic_phy_get_by_index(dev, 0, &priv->analog);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_index(dev, 0, &priv->reset);
+ if (ret == -ENOTSUPP)
+ return 0;
+ else if (ret)
+ return ret;
+
+ ret = reset_deassert(&priv->reset);
+ if (ret) {
+ reset_release_all(&priv->reset, 1);
+ return ret;
+ }
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ pr_err("failed to enable PHY clock\n");
+ clk_free(&priv->clk);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id meson_axg_mipi_dphy_ids[] = {
+ { .compatible = "amlogic,axg-mipi-dphy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_axg_mipi_dphy) = {
+ .name = "meson_axg_mipi_dphy",
+ .id = UCLASS_PHY,
+ .of_match = meson_axg_mipi_dphy_ids,
+ .probe = meson_axg_mipi_dphy_probe,
+ .ops = &meson_axg_mipi_dphy_ops,
+ .priv_auto_alloc_size = sizeof(struct phy_meson_axg_mipi_dphy_priv),
+};
diff --git a/roms/u-boot/drivers/phy/meson-axg-mipi-pcie-analog.c b/roms/u-boot/drivers/phy/meson-axg-mipi-pcie-analog.c
new file mode 100644
index 000000000..276e6004e
--- /dev/null
+++ b/roms/u-boot/drivers/phy/meson-axg-mipi-pcie-analog.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Amlogic AXG MIPI + PCIE analog PHY driver
+ *
+ * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
+ * Copyright (C) 2020 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <bitfield.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+#include <reset.h>
+#include <clk.h>
+#include <phy-mipi-dphy.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <linux/bitfield.h>
+
+#define HHI_MIPI_CNTL0 0x00
+#define HHI_MIPI_CNTL0_COMMON_BLOCK GENMASK(31, 28)
+#define HHI_MIPI_CNTL0_ENABLE BIT(29)
+#define HHI_MIPI_CNTL0_BANDGAP BIT(26)
+#define HHI_MIPI_CNTL0_DIF_REF_CTL1 GENMASK(25, 16)
+#define HHI_MIPI_CNTL0_DIF_REF_CTL0 GENMASK(15, 0)
+
+#define HHI_MIPI_CNTL1 0x04
+#define HHI_MIPI_CNTL1_CH0_CML_PDR_EN BIT(12)
+#define HHI_MIPI_CNTL1_LP_ABILITY GENMASK(5, 4)
+#define HHI_MIPI_CNTL1_LP_RESISTER BIT(3)
+#define HHI_MIPI_CNTL1_INPUT_SETTING BIT(2)
+#define HHI_MIPI_CNTL1_INPUT_SEL BIT(1)
+#define HHI_MIPI_CNTL1_PRBS7_EN BIT(0)
+
+#define HHI_MIPI_CNTL2 0x08
+#define HHI_MIPI_CNTL2_CH_PU GENMASK(31, 25)
+#define HHI_MIPI_CNTL2_CH_CTL GENMASK(24, 19)
+#define HHI_MIPI_CNTL2_CH0_DIGDR_EN BIT(18)
+#define HHI_MIPI_CNTL2_CH_DIGDR_EN BIT(17)
+#define HHI_MIPI_CNTL2_LPULPS_EN BIT(16)
+#define HHI_MIPI_CNTL2_CH_EN GENMASK(15, 11)
+#define HHI_MIPI_CNTL2_CH0_LP_CTL GENMASK(10, 1)
+
+#define DSI_LANE_0 (1 << 4)
+#define DSI_LANE_1 (1 << 3)
+#define DSI_LANE_CLK (1 << 2)
+#define DSI_LANE_2 (1 << 1)
+#define DSI_LANE_3 (1 << 0)
+#define DSI_LANE_MASK (0x1F)
+
+struct phy_meson_axg_mipi_pcie_analog_priv {
+ struct regmap *regmap;
+ struct phy_configure_opts_mipi_dphy config;
+ bool dsi_configured;
+ bool dsi_enabled;
+ bool powered;
+};
+
+static void phy_bandgap_enable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
+{
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
+
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
+}
+
+static void phy_bandgap_disable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
+{
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_BANDGAP, 0);
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_ENABLE, 0);
+}
+
+static void phy_dsi_analog_enable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
+{
+ u32 reg;
+
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_DIF_REF_CTL1,
+ FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0x1b8));
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ BIT(31), BIT(31));
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_DIF_REF_CTL0,
+ FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL0, 0x8));
+
+ regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x001e);
+
+ regmap_write(priv->regmap, HHI_MIPI_CNTL2,
+ (0x26e0 << 16) | (0x459 << 0));
+
+ reg = DSI_LANE_CLK;
+ switch (priv->config.lanes) {
+ case 4:
+ reg |= DSI_LANE_3;
+ fallthrough;
+ case 3:
+ reg |= DSI_LANE_2;
+ fallthrough;
+ case 2:
+ reg |= DSI_LANE_1;
+ fallthrough;
+ case 1:
+ reg |= DSI_LANE_0;
+ break;
+ default:
+ reg = 0;
+ }
+
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL2,
+ HHI_MIPI_CNTL2_CH_EN,
+ FIELD_PREP(HHI_MIPI_CNTL2_CH_EN, reg));
+
+ priv->dsi_enabled = true;
+}
+
+static void phy_dsi_analog_disable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
+{
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_DIF_REF_CTL1,
+ FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0));
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, BIT(31), 0);
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_DIF_REF_CTL1, 0);
+
+ regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x6);
+
+ regmap_write(priv->regmap, HHI_MIPI_CNTL2, 0x00200000);
+
+ priv->dsi_enabled = false;
+}
+
+static int phy_meson_axg_mipi_pcie_analog_configure(struct phy *phy, void *params)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
+ struct phy_configure_opts_mipi_dphy *config = params;
+ int ret;
+
+ ret = phy_mipi_dphy_config_validate(config);
+ if (ret)
+ return ret;
+
+ memcpy(&priv->config, config, sizeof(priv->config));
+
+ priv->dsi_configured = true;
+
+ /* If PHY was already powered on, setup the DSI analog part */
+ if (priv->powered) {
+ /* If reconfiguring, disable & reconfigure */
+ if (priv->dsi_enabled)
+ phy_dsi_analog_disable(priv);
+
+ udelay(100);
+
+ phy_dsi_analog_enable(priv);
+ }
+
+ return 0;
+}
+
+static int phy_meson_axg_mipi_pcie_analog_power_on(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
+
+ phy_bandgap_enable(priv);
+
+ if (priv->dsi_configured)
+ phy_dsi_analog_enable(priv);
+
+ priv->powered = true;
+
+ return 0;
+}
+
+static int phy_meson_axg_mipi_pcie_analog_power_off(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
+
+ phy_bandgap_disable(priv);
+
+ if (priv->dsi_enabled)
+ phy_dsi_analog_disable(priv);
+
+ priv->powered = false;
+
+ return 0;
+}
+
+struct phy_ops meson_axg_mipi_pcie_analog_ops = {
+ .power_on = phy_meson_axg_mipi_pcie_analog_power_on,
+ .power_off = phy_meson_axg_mipi_pcie_analog_power_off,
+ .configure = phy_meson_axg_mipi_pcie_analog_configure,
+};
+
+int meson_axg_mipi_pcie_analog_probe(struct udevice *dev)
+{
+ struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
+
+ priv->regmap = syscon_node_to_regmap(dev_get_parent(dev)->node);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ return 0;
+}
+
+static const struct udevice_id meson_axg_mipi_pcie_analog_ids[] = {
+ { .compatible = "amlogic,axg-mipi-pcie-analog-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_axg_mipi_pcie_analog) = {
+ .name = "meson_axg_mipi_pcie_analog",
+ .id = UCLASS_PHY,
+ .of_match = meson_axg_mipi_pcie_analog_ids,
+ .probe = meson_axg_mipi_pcie_analog_probe,
+ .ops = &meson_axg_mipi_pcie_analog_ops,
+ .priv_auto_alloc_size = sizeof(struct phy_meson_axg_mipi_pcie_analog_priv),
+};
diff --git a/roms/u-boot/drivers/phy/meson-g12a-usb2.c b/roms/u-boot/drivers/phy/meson-g12a-usb2.c
new file mode 100644
index 000000000..2fbba7fda
--- /dev/null
+++ b/roms/u-boot/drivers/phy/meson-g12a-usb2.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Meson G12A USB2 PHY driver
+ *
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstron@baylibre.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <bitfield.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+#include <reset.h>
+#include <clk.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+
+#define PHY_CTRL_R0 0x0
+#define PHY_CTRL_R1 0x4
+#define PHY_CTRL_R2 0x8
+#define PHY_CTRL_R3 0xc
+#define PHY_CTRL_R4 0x10
+#define PHY_CTRL_R5 0x14
+#define PHY_CTRL_R6 0x18
+#define PHY_CTRL_R7 0x1c
+#define PHY_CTRL_R8 0x20
+#define PHY_CTRL_R9 0x24
+#define PHY_CTRL_R10 0x28
+#define PHY_CTRL_R11 0x2c
+#define PHY_CTRL_R12 0x30
+#define PHY_CTRL_R13 0x34
+#define PHY_CTRL_R14 0x38
+#define PHY_CTRL_R15 0x3c
+#define PHY_CTRL_R16 0x40
+#define PHY_CTRL_R17 0x44
+#define PHY_CTRL_R18 0x48
+#define PHY_CTRL_R19 0x4c
+#define PHY_CTRL_R20 0x50
+#define PHY_CTRL_R21 0x54
+#define PHY_CTRL_R22 0x58
+#define PHY_CTRL_R23 0x5c
+
+#define RESET_COMPLETE_TIME 1000
+#define PLL_RESET_COMPLETE_TIME 100
+
+struct phy_meson_g12a_usb2_priv {
+ struct regmap *regmap;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ struct udevice *phy_supply;
+#endif
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+#endif
+ struct reset_ctl reset;
+};
+
+
+static int phy_meson_g12a_usb2_power_on(struct phy *phy)
+{
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ struct udevice *dev = phy->dev;
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+
+ if (priv->phy_supply) {
+ int ret = regulator_set_enable(priv->phy_supply, true);
+ if (ret)
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static int phy_meson_g12a_usb2_power_off(struct phy *phy)
+{
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ struct udevice *dev = phy->dev;
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+
+ if (priv->phy_supply) {
+ int ret = regulator_set_enable(priv->phy_supply, false);
+ if (ret) {
+ pr_err("Error disabling PHY supply\n");
+ return ret;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static int phy_meson_g12a_usb2_init(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = reset_assert(&priv->reset);
+ udelay(1);
+ ret |= reset_deassert(&priv->reset);
+ if (ret)
+ return ret;
+
+ udelay(RESET_COMPLETE_TIME);
+
+ /* usb2_otg_aca_en == 0 */
+ regmap_update_bits(priv->regmap, PHY_CTRL_R21, BIT(2), 0);
+
+ /* PLL Setup : 24MHz * 20 / 1 = 480MHz */
+ regmap_write(priv->regmap, PHY_CTRL_R16, 0x39400414);
+ regmap_write(priv->regmap, PHY_CTRL_R17, 0x927e0000);
+ regmap_write(priv->regmap, PHY_CTRL_R18, 0xac5f49e5);
+
+ udelay(PLL_RESET_COMPLETE_TIME);
+
+ /* UnReset PLL */
+ regmap_write(priv->regmap, PHY_CTRL_R16, 0x19400414);
+
+ /* PHY Tuning */
+ regmap_write(priv->regmap, PHY_CTRL_R20, 0xfe18);
+ regmap_write(priv->regmap, PHY_CTRL_R4, 0x8000fff);
+
+ /* Tuning Disconnect Threshold */
+ regmap_write(priv->regmap, PHY_CTRL_R3, 0x34);
+
+ /* Analog Settings */
+ regmap_write(priv->regmap, PHY_CTRL_R14, 0);
+ regmap_write(priv->regmap, PHY_CTRL_R13, 0x78000);
+
+ return 0;
+}
+
+static int phy_meson_g12a_usb2_exit(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = reset_assert(&priv->reset);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct phy_ops meson_g12a_usb2_phy_ops = {
+ .init = phy_meson_g12a_usb2_init,
+ .exit = phy_meson_g12a_usb2_exit,
+ .power_on = phy_meson_g12a_usb2_power_on,
+ .power_off = phy_meson_g12a_usb2_power_off,
+};
+
+int meson_g12a_usb2_phy_probe(struct udevice *dev)
+{
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_index(dev, 0, &priv->reset);
+ if (ret == -ENOTSUPP)
+ return 0;
+ else if (ret)
+ return ret;
+
+ ret = reset_deassert(&priv->reset);
+ if (ret) {
+ reset_release_all(&priv->reset, 1);
+ return ret;
+ }
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ pr_err("failed to enable PHY clock\n");
+ clk_free(&priv->clk);
+ return ret;
+ }
+#endif
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ ret = device_get_supply_regulator(dev, "phy-supply", &priv->phy_supply);
+ if (ret && ret != -ENOENT) {
+ pr_err("Failed to get PHY regulator\n");
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id meson_g12a_usb2_phy_ids[] = {
+ { .compatible = "amlogic,g12a-usb2-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_g12a_usb2_phy) = {
+ .name = "meson_g12a_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = meson_g12a_usb2_phy_ids,
+ .probe = meson_g12a_usb2_phy_probe,
+ .ops = &meson_g12a_usb2_phy_ops,
+ .priv_auto = sizeof(struct phy_meson_g12a_usb2_priv),
+};
diff --git a/roms/u-boot/drivers/phy/meson-g12a-usb3-pcie.c b/roms/u-boot/drivers/phy/meson-g12a-usb3-pcie.c
new file mode 100644
index 000000000..8f72b5a6a
--- /dev/null
+++ b/roms/u-boot/drivers/phy/meson-g12a-usb3-pcie.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Meson G12A USB3+PCIE Combo PHY driver
+ *
+ * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstron@baylibre.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <malloc.h>
+#include <regmap.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <reset.h>
+#include <bitfield.h>
+#include <generic-phy.h>
+#include <linux/delay.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <linux/bitfield.h>
+
+#define PHY_TYPE_PCIE 2
+#define PHY_TYPE_USB3 4
+
+#define PHY_R0 0x00
+ #define PHY_R0_PCIE_POWER_STATE GENMASK(4, 0)
+ #define PHY_R0_PCIE_USB3_SWITCH GENMASK(6, 5)
+
+#define PHY_R1 0x04
+ #define PHY_R1_PHY_TX1_TERM_OFFSET GENMASK(4, 0)
+ #define PHY_R1_PHY_TX0_TERM_OFFSET GENMASK(9, 5)
+ #define PHY_R1_PHY_RX1_EQ GENMASK(12, 10)
+ #define PHY_R1_PHY_RX0_EQ GENMASK(15, 13)
+ #define PHY_R1_PHY_LOS_LEVEL GENMASK(20, 16)
+ #define PHY_R1_PHY_LOS_BIAS GENMASK(23, 21)
+ #define PHY_R1_PHY_REF_CLKDIV2 BIT(24)
+ #define PHY_R1_PHY_MPLL_MULTIPLIER GENMASK(31, 25)
+
+#define PHY_R2 0x08
+ #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB GENMASK(5, 0)
+ #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB GENMASK(11, 6)
+ #define PHY_R2_PCS_TX_DEEMPH_GEN1 GENMASK(17, 12)
+ #define PHY_R2_PHY_TX_VBOOST_LVL GENMASK(20, 18)
+
+#define PHY_R4 0x10
+ #define PHY_R4_PHY_CR_WRITE BIT(0)
+ #define PHY_R4_PHY_CR_READ BIT(1)
+ #define PHY_R4_PHY_CR_DATA_IN GENMASK(17, 2)
+ #define PHY_R4_PHY_CR_CAP_DATA BIT(18)
+ #define PHY_R4_PHY_CR_CAP_ADDR BIT(19)
+
+#define PHY_R5 0x14
+ #define PHY_R5_PHY_CR_DATA_OUT GENMASK(15, 0)
+ #define PHY_R5_PHY_CR_ACK BIT(16)
+ #define PHY_R5_PHY_BS_OUT BIT(17)
+
+#define PCIE_RESET_DELAY 500
+
+struct phy_g12a_usb3_pcie_priv {
+ struct regmap *regmap;
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+#endif
+ struct reset_ctl_bulk resets;
+};
+
+static int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv,
+ unsigned int addr)
+{
+ unsigned int val, reg;
+ int ret;
+
+ reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr);
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_ADDR);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ !(val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+phy_g12a_usb3_pcie_cr_bus_read(struct phy_g12a_usb3_pcie_priv *priv,
+ unsigned int addr, unsigned int *data)
+{
+ unsigned int val;
+ int ret;
+
+ ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, 0);
+ regmap_write(priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val);
+
+ regmap_write(priv->regmap, PHY_R4, 0);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ !(val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+phy_g12a_usb3_pcie_cr_bus_write(struct phy_g12a_usb3_pcie_priv *priv,
+ unsigned int addr, unsigned int data)
+{
+ unsigned int val, reg;
+ int ret;
+
+ ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr);
+ if (ret)
+ return ret;
+
+ reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data);
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_DATA);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK) == 0,
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_WRITE);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK) == 0,
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+phy_g12a_usb3_pcie_cr_bus_update_bits(struct phy_g12a_usb3_pcie_priv *priv,
+ uint offset, uint mask, uint val)
+{
+ uint reg;
+ int ret;
+
+ ret = phy_g12a_usb3_pcie_cr_bus_read(priv, offset, &reg);
+ if (ret)
+ return ret;
+
+ reg &= ~mask;
+
+ return phy_g12a_usb3_pcie_cr_bus_write(priv, offset, reg | val);
+}
+
+static int phy_meson_g12a_usb3_init(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(dev);
+ unsigned int data;
+ int ret;
+
+ ret = reset_assert_bulk(&priv->resets);
+ udelay(1);
+ ret |= reset_deassert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+
+ /* Switch PHY to USB3 */
+ regmap_update_bits(priv->regmap, PHY_R0,
+ PHY_R0_PCIE_USB3_SWITCH,
+ PHY_R0_PCIE_USB3_SWITCH);
+
+ /*
+ * WORKAROUND: There is SSPHY suspend bug due to
+ * which USB enumerates
+ * in HS mode instead of SS mode. Workaround it by asserting
+ * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus
+ * mode
+ */
+ ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x102d,
+ BIT(7), BIT(7));
+ if (ret)
+ return ret;
+
+ ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x1010, 0xff0, 20);
+ if (ret)
+ return ret;
+
+ /*
+ * Fix RX Equalization setting as follows
+ * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
+ * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
+ * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
+ * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
+ */
+ ret = phy_g12a_usb3_pcie_cr_bus_read(priv, 0x1006, &data);
+ if (ret)
+ return ret;
+
+ data &= ~BIT(6);
+ data |= BIT(7);
+ data &= ~(0x7 << 8);
+ data |= (0x3 << 8);
+ data |= (1 << 11);
+ ret = phy_g12a_usb3_pcie_cr_bus_write(priv, 0x1006, data);
+ if (ret)
+ return ret;
+
+ /*
+ * Set EQ and TX launch amplitudes as follows
+ * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
+ * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
+ * LANE0.TX_OVRD_DRV_LO.EN set to 1.
+ */
+ ret = phy_g12a_usb3_pcie_cr_bus_read(priv, 0x1002, &data);
+ if (ret)
+ return ret;
+
+ data &= ~0x3f80;
+ data |= (0x16 << 7);
+ data &= ~0x7f;
+ data |= (0x7f | BIT(14));
+ ret = phy_g12a_usb3_pcie_cr_bus_write(priv, 0x1002, data);
+ if (ret)
+ return ret;
+
+ /*
+ * MPLL_LOOP_CTL.PROP_CNTRL = 8
+ */
+ ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x30,
+ 0xf << 4, 8 << 4);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(priv->regmap, PHY_R2,
+ PHY_R2_PHY_TX_VBOOST_LVL,
+ FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4));
+
+ regmap_update_bits(priv->regmap, PHY_R1,
+ PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL,
+ FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) |
+ FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9));
+
+ return ret;
+}
+
+static int phy_meson_g12a_usb3_exit(struct phy *phy)
+{
+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+
+ return reset_assert_bulk(&priv->resets);
+}
+
+static int phy_meson_g12a_usb3_pcie_init(struct phy *phy)
+{
+ if (phy->id == PHY_TYPE_USB3)
+ return phy_meson_g12a_usb3_init(phy);
+
+ return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_exit(struct phy *phy)
+{
+ if (phy->id == PHY_TYPE_USB3)
+ return phy_meson_g12a_usb3_exit(phy);
+
+ return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_power_on(struct phy *phy)
+{
+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+
+ if (phy->id == PHY_TYPE_USB3)
+ return 0;
+
+ regmap_update_bits(priv->regmap, PHY_R0,
+ PHY_R0_PCIE_POWER_STATE,
+ FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c));
+
+ return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_power_off(struct phy *phy)
+{
+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+
+ if (phy->id == PHY_TYPE_USB3)
+ return 0;
+
+ regmap_update_bits(priv->regmap, PHY_R0,
+ PHY_R0_PCIE_POWER_STATE,
+ FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1d));
+
+ return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_reset(struct phy *phy)
+{
+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+ int ret;
+
+ if (phy->id == PHY_TYPE_USB3)
+ return 0;
+
+ ret = reset_assert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+
+ udelay(PCIE_RESET_DELAY);
+
+ ret = reset_deassert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+
+ udelay(PCIE_RESET_DELAY);
+
+ return 0;
+}
+
+struct phy_ops meson_g12a_usb3_pcie_phy_ops = {
+ .init = phy_meson_g12a_usb3_pcie_init,
+ .exit = phy_meson_g12a_usb3_pcie_exit,
+ .power_on = phy_meson_g12a_usb3_pcie_power_on,
+ .power_off = phy_meson_g12a_usb3_pcie_power_off,
+ .reset = phy_meson_g12a_usb3_pcie_reset,
+};
+
+int meson_g12a_usb3_pcie_phy_probe(struct udevice *dev)
+{
+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+ if (ret)
+ return ret;
+
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (ret == -ENOTSUPP)
+ return 0;
+ else if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret && ret != -ENOENT && ret != -ENOTSUPP) {
+ pr_err("failed to enable PHY clock\n");
+ clk_free(&priv->clk);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id meson_g12a_usb3_pcie_phy_ids[] = {
+ { .compatible = "amlogic,g12a-usb3-pcie-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_g12a_usb3_pcie_phy) = {
+ .name = "meson_g12a_usb3_pcie_phy",
+ .id = UCLASS_PHY,
+ .of_match = meson_g12a_usb3_pcie_phy_ids,
+ .probe = meson_g12a_usb3_pcie_phy_probe,
+ .ops = &meson_g12a_usb3_pcie_phy_ops,
+ .priv_auto = sizeof(struct phy_g12a_usb3_pcie_priv),
+};
diff --git a/roms/u-boot/drivers/phy/meson-gxbb-usb2.c b/roms/u-boot/drivers/phy/meson-gxbb-usb2.c
new file mode 100644
index 000000000..7a2e3d273
--- /dev/null
+++ b/roms/u-boot/drivers/phy/meson-gxbb-usb2.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Meson8, Meson8b and GXBB USB2 PHY driver
+ *
+ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ * Copyright (C) 2018 BayLibre, SAS
+ *
+ * Author: Beniamino Galvani <b.galvani@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <power/regulator.h>
+#include <regmap.h>
+#include <reset.h>
+#include <linux/bitops.h>
+
+#define REG_CONFIG 0x00
+ #define REG_CONFIG_CLK_EN BIT(0)
+ #define REG_CONFIG_CLK_SEL_MASK GENMASK(3, 1)
+ #define REG_CONFIG_CLK_DIV_MASK GENMASK(10, 4)
+ #define REG_CONFIG_CLK_32k_ALTSEL BIT(15)
+ #define REG_CONFIG_TEST_TRIG BIT(31)
+
+#define REG_CTRL 0x04
+ #define REG_CTRL_SOFT_PRST BIT(0)
+ #define REG_CTRL_SOFT_HRESET BIT(1)
+ #define REG_CTRL_SS_SCALEDOWN_MODE_MASK GENMASK(3, 2)
+ #define REG_CTRL_CLK_DET_RST BIT(4)
+ #define REG_CTRL_INTR_SEL BIT(5)
+ #define REG_CTRL_CLK_DETECTED BIT(8)
+ #define REG_CTRL_SOF_SENT_RCVD_TGL BIT(9)
+ #define REG_CTRL_SOF_TOGGLE_OUT BIT(10)
+ #define REG_CTRL_POWER_ON_RESET BIT(15)
+ #define REG_CTRL_SLEEPM BIT(16)
+ #define REG_CTRL_TX_BITSTUFF_ENN_H BIT(17)
+ #define REG_CTRL_TX_BITSTUFF_ENN BIT(18)
+ #define REG_CTRL_COMMON_ON BIT(19)
+ #define REG_CTRL_REF_CLK_SEL_MASK GENMASK(21, 20)
+ #define REG_CTRL_REF_CLK_SEL_SHIFT 20
+ #define REG_CTRL_FSEL_MASK GENMASK(24, 22)
+ #define REG_CTRL_FSEL_SHIFT 22
+ #define REG_CTRL_PORT_RESET BIT(25)
+ #define REG_CTRL_THREAD_ID_MASK GENMASK(31, 26)
+
+/* bits [31:26], [24:21] and [15:3] seem to be read-only */
+#define REG_ADP_BC 0x0c
+ #define REG_ADP_BC_VBUS_VLD_EXT_SEL BIT(0)
+ #define REG_ADP_BC_VBUS_VLD_EXT BIT(1)
+ #define REG_ADP_BC_OTG_DISABLE BIT(2)
+ #define REG_ADP_BC_ID_PULLUP BIT(3)
+ #define REG_ADP_BC_DRV_VBUS BIT(4)
+ #define REG_ADP_BC_ADP_PRB_EN BIT(5)
+ #define REG_ADP_BC_ADP_DISCHARGE BIT(6)
+ #define REG_ADP_BC_ADP_CHARGE BIT(7)
+ #define REG_ADP_BC_SESS_END BIT(8)
+ #define REG_ADP_BC_DEVICE_SESS_VLD BIT(9)
+ #define REG_ADP_BC_B_VALID BIT(10)
+ #define REG_ADP_BC_A_VALID BIT(11)
+ #define REG_ADP_BC_ID_DIG BIT(12)
+ #define REG_ADP_BC_VBUS_VALID BIT(13)
+ #define REG_ADP_BC_ADP_PROBE BIT(14)
+ #define REG_ADP_BC_ADP_SENSE BIT(15)
+ #define REG_ADP_BC_ACA_ENABLE BIT(16)
+ #define REG_ADP_BC_DCD_ENABLE BIT(17)
+ #define REG_ADP_BC_VDAT_DET_EN_B BIT(18)
+ #define REG_ADP_BC_VDAT_SRC_EN_B BIT(19)
+ #define REG_ADP_BC_CHARGE_SEL BIT(20)
+ #define REG_ADP_BC_CHARGE_DETECT BIT(21)
+ #define REG_ADP_BC_ACA_PIN_RANGE_C BIT(22)
+ #define REG_ADP_BC_ACA_PIN_RANGE_B BIT(23)
+ #define REG_ADP_BC_ACA_PIN_RANGE_A BIT(24)
+ #define REG_ADP_BC_ACA_PIN_GND BIT(25)
+ #define REG_ADP_BC_ACA_PIN_FLOAT BIT(26)
+
+#define RESET_COMPLETE_TIME 500
+#define ACA_ENABLE_COMPLETE_TIME 50
+
+struct phy_meson_gxbb_usb2_priv {
+ struct regmap *regmap;
+ struct reset_ctl_bulk resets;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ struct udevice *phy_supply;
+#endif
+};
+
+static int phy_meson_gxbb_usb2_power_on(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxbb_usb2_priv *priv = dev_get_priv(dev);
+ uint val;
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ if (priv->phy_supply) {
+ int ret = regulator_set_enable(priv->phy_supply, true);
+
+ if (ret)
+ return ret;
+ }
+#endif
+
+ regmap_update_bits(priv->regmap, REG_CONFIG,
+ REG_CONFIG_CLK_32k_ALTSEL,
+ REG_CONFIG_CLK_32k_ALTSEL);
+ regmap_update_bits(priv->regmap, REG_CTRL,
+ REG_CTRL_REF_CLK_SEL_MASK,
+ 0x2 << REG_CTRL_REF_CLK_SEL_SHIFT);
+ regmap_update_bits(priv->regmap, REG_CTRL,
+ REG_CTRL_FSEL_MASK,
+ 0x5 << REG_CTRL_FSEL_SHIFT);
+
+ /* reset the PHY */
+ regmap_update_bits(priv->regmap, REG_CTRL,
+ REG_CTRL_POWER_ON_RESET,
+ REG_CTRL_POWER_ON_RESET);
+ udelay(RESET_COMPLETE_TIME);
+ regmap_update_bits(priv->regmap, REG_CTRL,
+ REG_CTRL_POWER_ON_RESET,
+ 0);
+ udelay(RESET_COMPLETE_TIME);
+
+ regmap_update_bits(priv->regmap, REG_CTRL,
+ REG_CTRL_SOF_TOGGLE_OUT,
+ REG_CTRL_SOF_TOGGLE_OUT);
+
+ /* Set host mode */
+ regmap_update_bits(priv->regmap, REG_ADP_BC,
+ REG_ADP_BC_ACA_ENABLE,
+ REG_ADP_BC_ACA_ENABLE);
+ udelay(ACA_ENABLE_COMPLETE_TIME);
+
+ regmap_read(priv->regmap, REG_ADP_BC, &val);
+ if (val & REG_ADP_BC_ACA_PIN_FLOAT) {
+ pr_err("Error powering on GXBB USB PHY\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int phy_meson_gxbb_usb2_power_off(struct phy *phy)
+{
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxbb_usb2_priv *priv = dev_get_priv(dev);
+
+ if (priv->phy_supply) {
+ int ret = regulator_set_enable(priv->phy_supply, false);
+
+ if (ret)
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static struct phy_ops meson_gxbb_usb2_phy_ops = {
+ .power_on = phy_meson_gxbb_usb2_power_on,
+ .power_off = phy_meson_gxbb_usb2_power_off,
+};
+
+static int meson_gxbb_usb2_phy_probe(struct udevice *dev)
+{
+ struct phy_meson_gxbb_usb2_priv *priv = dev_get_priv(dev);
+ struct clk clk_usb_general, clk_usb;
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+ if (ret)
+ return ret;
+
+ ret = clk_get_by_name(dev, "usb_general", &clk_usb_general);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk_usb_general);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ pr_err("Failed to enable PHY general clock\n");
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "usb", &clk_usb);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk_usb);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ pr_err("Failed to enable PHY clock\n");
+ return ret;
+ }
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ ret = device_get_supply_regulator(dev, "phy-supply", &priv->phy_supply);
+ if (ret && ret != -ENOENT) {
+ pr_err("Failed to get PHY regulator\n");
+ return ret;
+ }
+#endif
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (!ret) {
+ ret = reset_deassert_bulk(&priv->resets);
+ if (ret) {
+ pr_err("Failed to deassert reset\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int meson_gxbb_usb2_phy_remove(struct udevice *dev)
+{
+ struct phy_meson_gxbb_usb2_priv *priv = dev_get_priv(dev);
+
+ return reset_release_bulk(&priv->resets);
+}
+
+static const struct udevice_id meson_gxbb_usb2_phy_ids[] = {
+ { .compatible = "amlogic,meson8-usb2-phy" },
+ { .compatible = "amlogic,meson8b-usb2-phy" },
+ { .compatible = "amlogic,meson-gxbb-usb2-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_gxbb_usb2_phy) = {
+ .name = "meson_gxbb_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = meson_gxbb_usb2_phy_ids,
+ .probe = meson_gxbb_usb2_phy_probe,
+ .remove = meson_gxbb_usb2_phy_remove,
+ .ops = &meson_gxbb_usb2_phy_ops,
+ .priv_auto = sizeof(struct phy_meson_gxbb_usb2_priv),
+};
diff --git a/roms/u-boot/drivers/phy/meson-gxl-usb2.c b/roms/u-boot/drivers/phy/meson-gxl-usb2.c
new file mode 100644
index 000000000..9fb376cec
--- /dev/null
+++ b/roms/u-boot/drivers/phy/meson-gxl-usb2.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Meson GXL and GXM USB2 PHY driver
+ *
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstron@baylibre.com>
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <bitfield.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+#include <clk.h>
+#include <linux/usb/otg.h>
+
+#include <asm/arch/usb-gx.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+
+/* bits [31:27] are read-only */
+#define U2P_R0 0x0
+ #define U2P_R0_BYPASS_SEL BIT(0)
+ #define U2P_R0_BYPASS_DM_EN BIT(1)
+ #define U2P_R0_BYPASS_DP_EN BIT(2)
+ #define U2P_R0_TXBITSTUFF_ENH BIT(3)
+ #define U2P_R0_TXBITSTUFF_EN BIT(4)
+ #define U2P_R0_DM_PULLDOWN BIT(5)
+ #define U2P_R0_DP_PULLDOWN BIT(6)
+ #define U2P_R0_DP_VBUS_VLD_EXT_SEL BIT(7)
+ #define U2P_R0_DP_VBUS_VLD_EXT BIT(8)
+ #define U2P_R0_ADP_PRB_EN BIT(9)
+ #define U2P_R0_ADP_DISCHARGE BIT(10)
+ #define U2P_R0_ADP_CHARGE BIT(11)
+ #define U2P_R0_DRV_VBUS BIT(12)
+ #define U2P_R0_ID_PULLUP BIT(13)
+ #define U2P_R0_LOOPBACK_EN_B BIT(14)
+ #define U2P_R0_OTG_DISABLE BIT(15)
+ #define U2P_R0_COMMON_ONN BIT(16)
+ #define U2P_R0_FSEL_MASK GENMASK(19, 17)
+ #define U2P_R0_REF_CLK_SEL_MASK GENMASK(21, 20)
+ #define U2P_R0_POWER_ON_RESET BIT(22)
+ #define U2P_R0_V_ATE_TEST_EN_B_MASK GENMASK(24, 23)
+ #define U2P_R0_ID_SET_ID_DQ BIT(25)
+ #define U2P_R0_ATE_RESET BIT(26)
+ #define U2P_R0_FSV_MINUS BIT(27)
+ #define U2P_R0_FSV_PLUS BIT(28)
+ #define U2P_R0_BYPASS_DM_DATA BIT(29)
+ #define U2P_R0_BYPASS_DP_DATA BIT(30)
+
+#define U2P_R1 0x4
+ #define U2P_R1_BURN_IN_TEST BIT(0)
+ #define U2P_R1_ACA_ENABLE BIT(1)
+ #define U2P_R1_DCD_ENABLE BIT(2)
+ #define U2P_R1_VDAT_SRC_EN_B BIT(3)
+ #define U2P_R1_VDAT_DET_EN_B BIT(4)
+ #define U2P_R1_CHARGES_SEL BIT(5)
+ #define U2P_R1_TX_PREEMP_PULSE_TUNE BIT(6)
+ #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK GENMASK(8, 7)
+ #define U2P_R1_TX_RES_TUNE_MASK GENMASK(10, 9)
+ #define U2P_R1_TX_RISE_TUNE_MASK GENMASK(12, 11)
+ #define U2P_R1_TX_VREF_TUNE_MASK GENMASK(16, 13)
+ #define U2P_R1_TX_FSLS_TUNE_MASK GENMASK(20, 17)
+ #define U2P_R1_TX_HSXV_TUNE_MASK GENMASK(22, 21)
+ #define U2P_R1_OTG_TUNE_MASK GENMASK(25, 23)
+ #define U2P_R1_SQRX_TUNE_MASK GENMASK(28, 26)
+ #define U2P_R1_COMP_DIS_TUNE_MASK GENMASK(31, 29)
+
+/* bits [31:14] are read-only */
+#define U2P_R2 0x8
+ #define U2P_R2_TESTDATA_IN_MASK GENMASK(7, 0)
+ #define U2P_R2_TESTADDR_MASK GENMASK(11, 8)
+ #define U2P_R2_TESTDATA_OUT_SEL BIT(12)
+ #define U2P_R2_TESTCLK BIT(13)
+ #define U2P_R2_TESTDATA_OUT_MASK GENMASK(17, 14)
+ #define U2P_R2_ACA_PIN_RANGE_C BIT(18)
+ #define U2P_R2_ACA_PIN_RANGE_B BIT(19)
+ #define U2P_R2_ACA_PIN_RANGE_A BIT(20)
+ #define U2P_R2_ACA_PIN_GND BIT(21)
+ #define U2P_R2_ACA_PIN_FLOAT BIT(22)
+ #define U2P_R2_CHARGE_DETECT BIT(23)
+ #define U2P_R2_DEVICE_SESSION_VALID BIT(24)
+ #define U2P_R2_ADP_PROBE BIT(25)
+ #define U2P_R2_ADP_SENSE BIT(26)
+ #define U2P_R2_SESSION_END BIT(27)
+ #define U2P_R2_VBUS_VALID BIT(28)
+ #define U2P_R2_B_VALID BIT(29)
+ #define U2P_R2_A_VALID BIT(30)
+ #define U2P_R2_ID_DIG BIT(31)
+
+#define U2P_R3 0xc
+
+#define RESET_COMPLETE_TIME 500
+
+struct phy_meson_gxl_usb2_priv {
+ struct regmap *regmap;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ struct udevice *phy_supply;
+#endif
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+#endif
+};
+
+static void phy_meson_gxl_usb2_reset(struct phy_meson_gxl_usb2_priv *priv)
+{
+ uint val;
+
+ regmap_read(priv->regmap, U2P_R0, &val);
+
+ /* reset the PHY and wait until settings are stabilized */
+ val |= U2P_R0_POWER_ON_RESET;
+ regmap_write(priv->regmap, U2P_R0, val);
+ udelay(RESET_COMPLETE_TIME);
+
+ val &= ~U2P_R0_POWER_ON_RESET;
+ regmap_write(priv->regmap, U2P_R0, val);
+ udelay(RESET_COMPLETE_TIME);
+}
+
+void phy_meson_gxl_usb2_set_mode(struct phy *phy, enum usb_dr_mode mode)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev);
+ uint val;
+
+ regmap_read(priv->regmap, U2P_R0, &val);
+
+ switch (mode) {
+ case USB_DR_MODE_UNKNOWN:
+ case USB_DR_MODE_HOST:
+ case USB_DR_MODE_OTG:
+ val |= U2P_R0_DM_PULLDOWN;
+ val |= U2P_R0_DP_PULLDOWN;
+ val &= ~U2P_R0_ID_PULLUP;
+ break;
+
+ case USB_DR_MODE_PERIPHERAL:
+ val &= ~U2P_R0_DM_PULLDOWN;
+ val &= ~U2P_R0_DP_PULLDOWN;
+ val |= U2P_R0_ID_PULLUP;
+ break;
+ }
+
+ regmap_write(priv->regmap, U2P_R0, val);
+
+ phy_meson_gxl_usb2_reset(priv);
+}
+
+static int phy_meson_gxl_usb2_power_on(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev);
+ uint val;
+
+ regmap_read(priv->regmap, U2P_R0, &val);
+ /* power on the PHY by taking it out of reset mode */
+ val &= ~U2P_R0_POWER_ON_RESET;
+ regmap_write(priv->regmap, U2P_R0, val);
+
+ phy_meson_gxl_usb2_set_mode(phy, USB_DR_MODE_HOST);
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ if (priv->phy_supply) {
+ int ret = regulator_set_enable(priv->phy_supply, true);
+ if (ret)
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb2_power_off(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev);
+ uint val;
+
+ regmap_read(priv->regmap, U2P_R0, &val);
+ /* power off the PHY by putting it into reset mode */
+ val |= U2P_R0_POWER_ON_RESET;
+ regmap_write(priv->regmap, U2P_R0, val);
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ if (priv->phy_supply) {
+ int ret = regulator_set_enable(priv->phy_supply, false);
+ if (ret) {
+ pr_err("Error disabling PHY supply\n");
+ return ret;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+struct phy_ops meson_gxl_usb2_phy_ops = {
+ .power_on = phy_meson_gxl_usb2_power_on,
+ .power_off = phy_meson_gxl_usb2_power_off,
+};
+
+int meson_gxl_usb2_phy_probe(struct udevice *dev)
+{
+ struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+ if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ pr_err("failed to enable PHY clock\n");
+ clk_free(&priv->clk);
+ return ret;
+ }
+#endif
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ ret = device_get_supply_regulator(dev, "phy-supply", &priv->phy_supply);
+ if (ret && ret != -ENOENT) {
+ pr_err("Failed to get PHY regulator\n");
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id meson_gxl_usb2_phy_ids[] = {
+ { .compatible = "amlogic,meson-gxl-usb2-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_gxl_usb2_phy) = {
+ .name = "meson_gxl_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = meson_gxl_usb2_phy_ids,
+ .probe = meson_gxl_usb2_phy_probe,
+ .ops = &meson_gxl_usb2_phy_ops,
+ .priv_auto = sizeof(struct phy_meson_gxl_usb2_priv),
+};
diff --git a/roms/u-boot/drivers/phy/msm8916-usbh-phy.c b/roms/u-boot/drivers/phy/msm8916-usbh-phy.c
new file mode 100644
index 000000000..7c9d030a4
--- /dev/null
+++ b/roms/u-boot/drivers/phy/msm8916-usbh-phy.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Ramon Fried <ramon.fried@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <linux/bitops.h>
+#include <usb/ehci-ci.h>
+#include <usb/ulpi.h>
+#include <asm/io.h>
+
+/* PHY viewport regs */
+#define ULPI_MISC_A_READ 0x96
+#define ULPI_MISC_A_SET 0x97
+#define ULPI_MISC_A_CLEAR 0x98
+#define ULPI_MISC_A_VBUSVLDEXT BIT(0)
+#define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1)
+#define GEN2_SESS_VLD_CTRL_EN BIT(7)
+#define SESS_VLD_CTRL BIT(25)
+
+struct msm_phy_priv {
+ void __iomem *regs;
+ struct usb_ehci *ehci; /* Start of IP core*/
+ struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
+};
+
+static int msm_phy_power_on(struct phy *phy)
+{
+ struct msm_phy_priv *priv = dev_get_priv(phy->dev);
+
+ /* Select and enable external configuration with USB PHY */
+ ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_SET,
+ ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT);
+
+ return 0;
+}
+
+static int msm_phy_power_off(struct phy *phy)
+{
+ struct msm_phy_priv *priv = dev_get_priv(phy->dev);
+
+ /* Disable VBUS mimicing in the controller. */
+ ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR,
+ ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT);
+ return 0;
+}
+
+static int msm_phy_reset(struct phy *phy)
+{
+ struct msm_phy_priv *p = dev_get_priv(phy->dev);
+
+ /* select ULPI phy */
+ writel(PORT_PTS_ULPI, &p->ehci->portsc);
+
+ /* Enable sess_vld */
+ setbits_le32(&p->ehci->genconfig2, GEN2_SESS_VLD_CTRL_EN);
+
+ /* Enable external vbus configuration in the LINK */
+ setbits_le32(&p->ehci->usbcmd, SESS_VLD_CTRL);
+
+ /* USB_OTG_HS_AHB_BURST */
+ writel(0x0, &p->ehci->sbuscfg);
+
+ /* USB_OTG_HS_AHB_MODE: HPROT_MODE */
+ /* Bus access related config. */
+ writel(0x08, &p->ehci->sbusmode);
+
+ return 0;
+}
+
+static int msm_phy_probe(struct udevice *dev)
+{
+ struct msm_phy_priv *priv = dev_get_priv(dev);
+
+ priv->regs = dev_remap_addr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ priv->ehci = (struct usb_ehci *)priv->regs;
+ priv->ulpi_vp.port_num = 0;
+
+ /* Warning: this will not work if viewport address is > 64 bit due to
+ * ULPI design.
+ */
+ priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
+
+ return 0;
+}
+
+static struct phy_ops msm_phy_ops = {
+ .power_on = msm_phy_power_on,
+ .power_off = msm_phy_power_off,
+ .reset = msm_phy_reset,
+};
+
+static const struct udevice_id msm_phy_ids[] = {
+ { .compatible = "qcom,apq8016-usbphy" },
+ { }
+};
+
+U_BOOT_DRIVER(msm8916_usbphy) = {
+ .name = "msm8916_usbphy",
+ .id = UCLASS_PHY,
+ .of_match = msm_phy_ids,
+ .ops = &msm_phy_ops,
+ .probe = msm_phy_probe,
+ .priv_auto = sizeof(struct msm_phy_priv),
+};
diff --git a/roms/u-boot/drivers/phy/mt7620-usb-phy.c b/roms/u-boot/drivers/phy/mt7620-usb-phy.c
new file mode 100644
index 000000000..5045c3f3f
--- /dev/null
+++ b/roms/u-boot/drivers/phy/mt7620-usb-phy.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <misc.h>
+#include <reset.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <mach/mt7620-sysc.h>
+
+struct mt7620_usb_phy {
+ struct udevice *sysc;
+ struct clk_bulk clocks;
+ struct reset_ctl_bulk resets;
+};
+
+static int mt7620_usb_phy_power_on(struct phy *_phy)
+{
+ struct mt7620_usb_phy *phy = dev_get_priv(_phy->dev);
+ u32 mode = MT7620_SYSC_USB_HOST_MODE;
+ int ret;
+
+ reset_deassert_bulk(&phy->resets);
+
+ clk_enable_bulk(&phy->clocks);
+
+ mdelay(10);
+
+ ret = misc_ioctl(phy->sysc, MT7620_SYSC_IOCTL_SET_USB_MODE, &mode);
+ if (ret) {
+ dev_err(_phy->dev,
+ "mt7620_usbphy: failed to set USB host mode\n");
+ return ret;
+ }
+
+ mdelay(10);
+
+ return 0;
+}
+
+static int mt7620_usb_phy_power_off(struct phy *_phy)
+{
+ struct mt7620_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ clk_disable_bulk(&phy->clocks);
+
+ reset_assert_bulk(&phy->resets);
+
+ return 0;
+}
+
+static int mt7620_usb_phy_probe(struct udevice *dev)
+{
+ struct mt7620_usb_phy *phy = dev_get_priv(dev);
+ struct ofnode_phandle_args sysc_args;
+ int ret;
+
+ ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "mediatek,sysc", NULL,
+ 0, 0, &sysc_args);
+ if (ret) {
+ dev_err(dev, "mt7620_usbphy: sysc property not found\n");
+ return ret;
+ }
+
+ ret = uclass_get_device_by_ofnode(UCLASS_MISC, sysc_args.node,
+ &phy->sysc);
+ if (ret) {
+ dev_err(dev, "mt7620_usbphy: failed to sysc device\n");
+ return ret;
+ }
+
+ ret = clk_get_bulk(dev, &phy->clocks);
+ if (ret) {
+ dev_err(dev, "mt7620_usbphy: failed to get clocks\n");
+ return ret;
+ }
+
+ ret = reset_get_bulk(dev, &phy->resets);
+ if (ret) {
+ dev_err(dev, "mt7620_usbphy: failed to get reset control\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct phy_ops mt7620_usb_phy_ops = {
+ .power_on = mt7620_usb_phy_power_on,
+ .power_off = mt7620_usb_phy_power_off,
+};
+
+static const struct udevice_id mt7620_usb_phy_ids[] = {
+ { .compatible = "mediatek,mt7620-usbphy" },
+ { }
+};
+
+U_BOOT_DRIVER(mt7620_usb_phy) = {
+ .name = "mt7620_usb_phy",
+ .id = UCLASS_PHY,
+ .of_match = mt7620_usb_phy_ids,
+ .ops = &mt7620_usb_phy_ops,
+ .probe = mt7620_usb_phy_probe,
+ .priv_auto = sizeof(struct mt7620_usb_phy),
+};
diff --git a/roms/u-boot/drivers/phy/mt76x8-usb-phy.c b/roms/u-boot/drivers/phy/mt76x8-usb-phy.c
new file mode 100644
index 000000000..4069208b6
--- /dev/null
+++ b/roms/u-boot/drivers/phy/mt76x8-usb-phy.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Stefan Roese <sr@denx.de>
+ *
+ * Derived from linux/drivers/phy/ralink/phy-ralink-usb.c
+ * Copyright (C) 2017 John Crispin <john@phrozen.org>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#define OFS_U2_PHY_AC0 0x800
+#define USBPLL_FBDIV_S 16
+#define USBPLL_FBDIV_M GENMASK(22, 16)
+#define BG_TRIM_S 8
+#define BG_TRIM_M GENMASK(11, 8)
+#define BG_RBSEL_S 6
+#define BG_RBSEL_M GENMASK(7, 6)
+#define BG_RASEL_S 4
+#define BG_RASEL_M GENMASK(5, 4)
+#define BGR_DIV_S 2
+#define BGR_DIV_M GENMASK(3, 2)
+#define CHP_EN BIT(1)
+
+#define OFS_U2_PHY_AC1 0x804
+#define VRT_VREF_SEL_S 28
+#define VRT_VREF_SEL_M GENMASK(30, 28)
+#define TERM_VREF_SEL_S 24
+#define TERM_VREF_SEL_M GENMASK(26, 24)
+#define USBPLL_RSVD BIT(4)
+#define USBPLL_ACCEN BIT(3)
+#define USBPLL_LF BIT(2)
+
+#define OFS_U2_PHY_AC2 0x808
+
+#define OFS_U2_PHY_ACR0 0x810
+#define HSTX_SRCAL_EN BIT(23)
+#define HSTX_SRCTRL_S 16
+#define HSTX_SRCTRL_M GENMASK(18, 16)
+
+#define OFS_U2_PHY_ACR3 0x81C
+#define HSTX_DBIST_S 28
+#define HSTX_DBIST_M GENMASK(31, 28)
+#define HSRX_BIAS_EN_SEL_S 20
+#define HSRX_BIAS_EN_SEL_M GENMASK(21, 20)
+
+#define OFS_U2_PHY_DCR0 0x860
+#define PHYD_RESERVE_S 8
+#define PHYD_RESERVE_M GENMASK(23, 8)
+#define CDR_FILT_S 0
+#define CDR_FILT_M GENMASK(3, 0)
+
+#define OFS_U2_PHY_DTM0 0x868
+#define FORCE_USB_CLKEN BIT(25)
+
+#define OFS_FM_CR0 0xf00
+#define FREQDET_EN BIT(24)
+#define CYCLECNT_S 0
+#define CYCLECNT_M GENMASK(23, 0)
+
+#define OFS_FM_MONR0 0xf0c
+
+#define OFS_FM_MONR1 0xf10
+#define FRCK_EN BIT(8)
+
+#define U2_SR_COEF_7628 32
+
+struct mt76x8_usb_phy {
+ void __iomem *base;
+ struct clk cg; /* for clock gating */
+ struct reset_ctl rst_phy;
+};
+
+static void phy_w32(struct mt76x8_usb_phy *phy, u32 reg, u32 val)
+{
+ writel(val, phy->base + reg);
+}
+
+static u32 phy_r32(struct mt76x8_usb_phy *phy, u32 reg)
+{
+ return readl(phy->base + reg);
+}
+
+static void phy_rmw32(struct mt76x8_usb_phy *phy, u32 reg, u32 clr, u32 set)
+{
+ clrsetbits_32(phy->base + reg, clr, set);
+}
+
+static void mt76x8_usb_phy_init(struct mt76x8_usb_phy *phy)
+{
+ phy_r32(phy, OFS_U2_PHY_AC2);
+ phy_r32(phy, OFS_U2_PHY_ACR0);
+ phy_r32(phy, OFS_U2_PHY_DCR0);
+
+ phy_w32(phy, OFS_U2_PHY_DCR0,
+ (0xffff << PHYD_RESERVE_S) | (2 << CDR_FILT_S));
+ phy_r32(phy, OFS_U2_PHY_DCR0);
+
+ phy_w32(phy, OFS_U2_PHY_DCR0,
+ (0x5555 << PHYD_RESERVE_S) | (2 << CDR_FILT_S));
+ phy_r32(phy, OFS_U2_PHY_DCR0);
+
+ phy_w32(phy, OFS_U2_PHY_DCR0,
+ (0xaaaa << PHYD_RESERVE_S) | (2 << CDR_FILT_S));
+ phy_r32(phy, OFS_U2_PHY_DCR0);
+
+ phy_w32(phy, OFS_U2_PHY_DCR0,
+ (4 << PHYD_RESERVE_S) | (2 << CDR_FILT_S));
+ phy_r32(phy, OFS_U2_PHY_DCR0);
+
+ phy_w32(phy, OFS_U2_PHY_AC0,
+ (0x48 << USBPLL_FBDIV_S) | (8 << BG_TRIM_S) |
+ (1 << BG_RBSEL_S) | (2 << BG_RASEL_S) | (2 << BGR_DIV_S) |
+ CHP_EN);
+
+ phy_w32(phy, OFS_U2_PHY_AC1,
+ (4 << VRT_VREF_SEL_S) | (4 << TERM_VREF_SEL_S) | USBPLL_RSVD |
+ USBPLL_ACCEN | USBPLL_LF);
+
+ phy_w32(phy, OFS_U2_PHY_ACR3,
+ (12 << HSTX_DBIST_S) | (2 << HSRX_BIAS_EN_SEL_S));
+
+ phy_w32(phy, OFS_U2_PHY_DTM0, FORCE_USB_CLKEN);
+}
+
+static void mt76x8_usb_phy_sr_calibrate(struct mt76x8_usb_phy *phy)
+{
+ u32 fmout, tmp = 4;
+ int i;
+
+ /* Enable HS TX SR calibration */
+ phy_rmw32(phy, OFS_U2_PHY_ACR0, 0, HSTX_SRCAL_EN);
+ mdelay(1);
+
+ /* Enable free run clock */
+ phy_rmw32(phy, OFS_FM_MONR1, 0, FRCK_EN);
+
+ /* Set cycle count = 0x400 */
+ phy_rmw32(phy, OFS_FM_CR0, CYCLECNT_M, 0x400 << CYCLECNT_S);
+
+ /* Enable frequency meter */
+ phy_rmw32(phy, OFS_FM_CR0, 0, FREQDET_EN);
+
+ /* Wait for FM detection done, set timeout to 10ms */
+ for (i = 0; i < 10; i++) {
+ fmout = phy_r32(phy, OFS_FM_MONR0);
+
+ if (fmout)
+ break;
+
+ mdelay(1);
+ }
+
+ /* Disable frequency meter */
+ phy_rmw32(phy, OFS_FM_CR0, FREQDET_EN, 0);
+
+ /* Disable free run clock */
+ phy_rmw32(phy, OFS_FM_MONR1, FRCK_EN, 0);
+
+ /* Disable HS TX SR calibration */
+ phy_rmw32(phy, OFS_U2_PHY_ACR0, HSTX_SRCAL_EN, 0);
+ mdelay(1);
+
+ if (fmout) {
+ /*
+ * set reg = (1024 / FM_OUT) * 25 * 0.028
+ * (round to the nearest digits)
+ */
+ tmp = (((1024 * 25 * U2_SR_COEF_7628) / fmout) + 500) / 1000;
+ }
+
+ phy_rmw32(phy, OFS_U2_PHY_ACR0, HSTX_SRCTRL_M,
+ (tmp << HSTX_SRCTRL_S) & HSTX_SRCTRL_M);
+}
+
+static int mt76x8_usb_phy_power_on(struct phy *_phy)
+{
+ struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ clk_enable(&phy->cg);
+
+ reset_deassert(&phy->rst_phy);
+
+ /*
+ * The SDK kernel had a delay of 100ms. however on device
+ * testing showed that 10ms is enough
+ */
+ mdelay(10);
+
+ mt76x8_usb_phy_init(phy);
+ mt76x8_usb_phy_sr_calibrate(phy);
+
+ return 0;
+}
+
+static int mt76x8_usb_phy_power_off(struct phy *_phy)
+{
+ struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ clk_disable(&phy->cg);
+
+ reset_assert(&phy->rst_phy);
+
+ return 0;
+}
+
+static int mt76x8_usb_phy_probe(struct udevice *dev)
+{
+ struct mt76x8_usb_phy *phy = dev_get_priv(dev);
+ int ret;
+
+ phy->base = dev_read_addr_ptr(dev);
+ if (!phy->base)
+ return -EINVAL;
+
+ /* clock gate */
+ ret = clk_get_by_name(dev, "cg", &phy->cg);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_name(dev, "phy", &phy->rst_phy);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct phy_ops mt76x8_usb_phy_ops = {
+ .power_on = mt76x8_usb_phy_power_on,
+ .power_off = mt76x8_usb_phy_power_off,
+};
+
+static const struct udevice_id mt76x8_usb_phy_ids[] = {
+ { .compatible = "mediatek,mt7628-usbphy" },
+ { }
+};
+
+U_BOOT_DRIVER(mt76x8_usb_phy) = {
+ .name = "mt76x8_usb_phy",
+ .id = UCLASS_PHY,
+ .of_match = mt76x8_usb_phy_ids,
+ .ops = &mt76x8_usb_phy_ops,
+ .probe = mt76x8_usb_phy_probe,
+ .priv_auto = sizeof(struct mt76x8_usb_phy),
+};
diff --git a/roms/u-boot/drivers/phy/nop-phy.c b/roms/u-boot/drivers/phy/nop-phy.c
new file mode 100644
index 000000000..9f12ebc06
--- /dev/null
+++ b/roms/u-boot/drivers/phy/nop-phy.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <generic-phy.h>
+
+struct nop_phy_priv {
+ struct clk_bulk bulk;
+};
+
+static int nop_phy_init(struct phy *phy)
+{
+ struct nop_phy_priv *priv = dev_get_priv(phy->dev);
+
+ if (CONFIG_IS_ENABLED(CLK))
+ return clk_enable_bulk(&priv->bulk);
+
+ return 0;
+}
+
+static int nop_phy_probe(struct udevice *dev)
+{
+ struct nop_phy_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (CONFIG_IS_ENABLED(CLK)) {
+ ret = clk_get_bulk(dev, &priv->bulk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get clk: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct udevice_id nop_phy_ids[] = {
+ { .compatible = "nop-phy" },
+ { .compatible = "usb-nop-xceiv" },
+ { }
+};
+
+static struct phy_ops nop_phy_ops = {
+ .init = nop_phy_init,
+};
+
+U_BOOT_DRIVER(nop_phy) = {
+ .name = "nop_phy",
+ .id = UCLASS_PHY,
+ .of_match = nop_phy_ids,
+ .ops = &nop_phy_ops,
+ .probe = nop_phy_probe,
+ .priv_auto = sizeof(struct nop_phy_priv),
+};
diff --git a/roms/u-boot/drivers/phy/omap-usb2-phy.c b/roms/u-boot/drivers/phy/omap-usb2-phy.c
new file mode 100644
index 000000000..2a9604cdc
--- /dev/null
+++ b/roms/u-boot/drivers/phy/omap-usb2-phy.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OMAP USB2 PHY LAYER
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <soc.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+#define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT BIT(0)
+#define OMAP_USB2_DISABLE_CHG_DET BIT(1)
+
+#define OMAP_DEV_PHY_PD BIT(0)
+#define OMAP_USB2_PHY_PD BIT(28)
+
+#define AM437X_USB2_PHY_PD BIT(0)
+#define AM437X_USB2_OTG_PD BIT(1)
+#define AM437X_USB2_OTGVDET_EN BIT(19)
+#define AM437X_USB2_OTGSESSEND_EN BIT(20)
+
+#define USB2PHY_DISCON_BYP_LATCH BIT(31)
+#define USB2PHY_ANA_CONFIG1 (0x4c)
+
+#define AM654_USB2_OTG_PD BIT(8)
+#define AM654_USB2_VBUS_DET_EN BIT(5)
+#define AM654_USB2_VBUSVALID_DET_EN BIT(4)
+
+#define USB2PHY_CHRG_DET 0x14
+#define USB2PHY_USE_CHG_DET_REG BIT(29)
+#define USB2PHY_DIS_CHG_DET BIT(28)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct omap_usb2_phy {
+ struct regmap *pwr_regmap;
+ ulong flags;
+ void *phy_base;
+ u32 pwr_reg_offset;
+};
+
+struct usb_phy_data {
+ const char *label;
+ u8 flags;
+ u32 mask;
+ u32 power_on;
+ u32 power_off;
+};
+
+static const struct usb_phy_data omap5_usb2_data = {
+ .label = "omap5_usb2",
+ .flags = 0,
+ .mask = OMAP_DEV_PHY_PD,
+ .power_off = OMAP_DEV_PHY_PD,
+};
+
+static const struct usb_phy_data dra7x_usb2_data = {
+ .label = "dra7x_usb2",
+ .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
+ .mask = OMAP_DEV_PHY_PD,
+ .power_off = OMAP_DEV_PHY_PD,
+};
+
+static const struct usb_phy_data dra7x_usb2_phy2_data = {
+ .label = "dra7x_usb2_phy2",
+ .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
+ .mask = OMAP_USB2_PHY_PD,
+ .power_off = OMAP_USB2_PHY_PD,
+};
+
+static const struct usb_phy_data am437x_usb2_data = {
+ .label = "am437x_usb2",
+ .flags = 0,
+ .mask = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD |
+ AM437X_USB2_OTGVDET_EN | AM437X_USB2_OTGSESSEND_EN,
+ .power_on = AM437X_USB2_OTGVDET_EN | AM437X_USB2_OTGSESSEND_EN,
+ .power_off = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD,
+};
+
+static const struct usb_phy_data am654_usb2_data = {
+ .label = "am654_usb2",
+ .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
+ .mask = AM654_USB2_OTG_PD | AM654_USB2_VBUS_DET_EN |
+ AM654_USB2_VBUSVALID_DET_EN,
+ .power_on = AM654_USB2_VBUS_DET_EN | AM654_USB2_VBUSVALID_DET_EN,
+ .power_off = AM654_USB2_OTG_PD,
+};
+
+static const struct udevice_id omap_usb2_id_table[] = {
+ {
+ .compatible = "ti,omap5-usb2",
+ .data = (ulong)&omap5_usb2_data,
+ },
+ {
+ .compatible = "ti,dra7x-usb2",
+ .data = (ulong)&dra7x_usb2_data,
+ },
+ {
+ .compatible = "ti,dra7x-usb2-phy2",
+ .data = (ulong)&dra7x_usb2_phy2_data,
+ },
+ {
+ .compatible = "ti,am437x-usb2",
+ .data = (ulong)&am437x_usb2_data,
+ },
+ {
+ .compatible = "ti,am654-usb2",
+ .data = (ulong)&am654_usb2_data,
+ },
+ {},
+};
+
+static int omap_usb_phy_power(struct phy *usb_phy, bool on)
+{
+ struct udevice *dev = usb_phy->dev;
+ const struct usb_phy_data *data;
+ const struct omap_usb2_phy *phy = dev_get_priv(dev);
+ u32 val;
+ int rc;
+
+ data = (const struct usb_phy_data *)dev_get_driver_data(dev);
+ if (!data)
+ return -EINVAL;
+
+ rc = regmap_read(phy->pwr_regmap, phy->pwr_reg_offset, &val);
+ if (rc)
+ return rc;
+ val &= ~data->mask;
+ if (on)
+ val |= data->power_on;
+ else
+ val |= data->power_off;
+ rc = regmap_write(phy->pwr_regmap, phy->pwr_reg_offset, val);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int omap_usb2_phy_init(struct phy *usb_phy)
+{
+ struct udevice *dev = usb_phy->dev;
+ struct omap_usb2_phy *priv = dev_get_priv(dev);
+ u32 val;
+
+ if (priv->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
+ /*
+ *
+ * Reduce the sensitivity of internal PHY by enabling the
+ * DISCON_BYP_LATCH of the USB2PHY_ANA_CONFIG1 register. This
+ * resolves issues with certain devices which can otherwise
+ * be prone to false disconnects.
+ *
+ */
+ val = readl(priv->phy_base + USB2PHY_ANA_CONFIG1);
+ val |= USB2PHY_DISCON_BYP_LATCH;
+ writel(val, priv->phy_base + USB2PHY_ANA_CONFIG1);
+ }
+
+ if (priv->flags & OMAP_USB2_DISABLE_CHG_DET) {
+ val = readl(priv->phy_base + USB2PHY_CHRG_DET);
+ val |= USB2PHY_USE_CHG_DET_REG | USB2PHY_DIS_CHG_DET;
+ writel(val, priv->phy_base + USB2PHY_CHRG_DET);
+ }
+
+ return 0;
+}
+
+static int omap_usb2_phy_power_on(struct phy *usb_phy)
+{
+ return omap_usb_phy_power(usb_phy, true);
+}
+
+static int omap_usb2_phy_power_off(struct phy *usb_phy)
+{
+ return omap_usb_phy_power(usb_phy, false);
+}
+
+static int omap_usb2_phy_exit(struct phy *usb_phy)
+{
+ return omap_usb_phy_power(usb_phy, false);
+}
+
+struct phy_ops omap_usb2_phy_ops = {
+ .init = omap_usb2_phy_init,
+ .power_on = omap_usb2_phy_power_on,
+ .power_off = omap_usb2_phy_power_off,
+ .exit = omap_usb2_phy_exit,
+};
+
+static const struct soc_attr am65x_sr10_soc_devices[] = {
+ { .family = "AM65X", .revision = "SR1.0" },
+ { /* sentinel */ }
+};
+
+int omap_usb2_phy_probe(struct udevice *dev)
+{
+ int rc;
+ struct regmap *regmap;
+ struct omap_usb2_phy *priv = dev_get_priv(dev);
+ const struct usb_phy_data *data;
+ u32 tmp[2];
+
+ data = (const struct usb_phy_data *)dev_get_driver_data(dev);
+ if (!data)
+ return -EINVAL;
+
+ priv->phy_base = dev_read_addr_ptr(dev);
+
+ if (!priv->phy_base)
+ return -EINVAL;
+
+ if (data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT)
+ priv->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT;
+
+ /*
+ * AM654x PG1.0 has a silicon bug that D+ is pulled high after
+ * POR, which could cause enumeration failure with some USB hubs.
+ * Disabling the USB2_PHY Charger Detect function will put D+
+ * into the normal state.
+ *
+ * Enable this workaround for AM654x PG1.0.
+ */
+ if (soc_device_match(am65x_sr10_soc_devices))
+ priv->flags |= OMAP_USB2_DISABLE_CHG_DET;
+
+ regmap = syscon_regmap_lookup_by_phandle(dev, "syscon-phy-power");
+ if (!IS_ERR(regmap)) {
+ priv->pwr_regmap = regmap;
+ rc = dev_read_u32_array(dev, "syscon-phy-power", tmp, 2);
+ if (rc) {
+ printf("couldn't get power reg. offset (err %d)\n", rc);
+ return rc;
+ }
+ priv->pwr_reg_offset = tmp[1];
+ return 0;
+ }
+ regmap = syscon_regmap_lookup_by_phandle(dev, "ctrl-module");
+ if (!IS_ERR(regmap)) {
+ priv->pwr_regmap = regmap;
+ priv->pwr_reg_offset = 0;
+ return 0;
+ }
+
+ printf("can't get regmap (err %ld)\n", PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+}
+
+U_BOOT_DRIVER(omap_usb2_phy) = {
+ .name = "omap_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = omap_usb2_id_table,
+ .probe = omap_usb2_phy_probe,
+ .ops = &omap_usb2_phy_ops,
+ .priv_auto = sizeof(struct omap_usb2_phy),
+};
diff --git a/roms/u-boot/drivers/phy/phy-bcm-sr-pcie.c b/roms/u-boot/drivers/phy/phy-bcm-sr-pcie.c
new file mode 100644
index 000000000..f0e795333
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-bcm-sr-pcie.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Broadcom
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+/* we have up to 8 PAXB based RC. The 9th one is always PAXC */
+#define SR_NR_PCIE_PHYS 8
+
+#define PCIE_PIPEMUX_CFG_OFFSET 0x10c
+#define PCIE_PIPEMUX_SELECT_STRAP GENMASK(3, 0)
+
+#define CDRU_STRAP_DATA_LSW_OFFSET 0x5c
+#define PCIE_PIPEMUX_SHIFT 19
+#define PCIE_PIPEMUX_MASK GENMASK(3, 0)
+
+/**
+ * struct sr_pcie_phy_core - Stingray PCIe PHY core control
+ *
+ * @dev: pointer to device
+ * @base: base register of PCIe SS
+ * @cdru: CDRU base address
+ * @pipemux: pipemuex strap
+ */
+struct sr_pcie_phy_core {
+ struct udevice *dev;
+ void __iomem *base;
+ void __iomem *cdru;
+ u32 pipemux;
+};
+
+/*
+ * PCIe PIPEMUX lookup table
+ *
+ * Each array index represents a PIPEMUX strap setting
+ * The array element represents a bitmap where a set bit means the PCIe
+ * core and associated serdes has been enabled as RC and is available for use
+ */
+static const u8 pipemux_table[] = {
+ /* PIPEMUX = 0, EP 1x16 */
+ 0x00,
+ /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
+ 0x80,
+ /* PIPEMUX = 2, EP 4x4 */
+ 0x00,
+ /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
+ 0x81,
+ /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
+ 0xc3,
+ /* PIPEMUX = 5, RC 8x2, all 8 cores */
+ 0xff,
+ /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
+ 0xcd,
+ /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
+ 0xfd,
+ /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
+ 0xf0,
+ /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
+ 0xc0,
+ /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
+ 0x42,
+ /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
+ 0x3c,
+ /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
+ 0xfc,
+ /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
+ 0x4c,
+};
+
+/*
+ * Return true if the strap setting is valid
+ */
+static bool pipemux_strap_is_valid(u32 pipemux)
+{
+ return !!(pipemux < ARRAY_SIZE(pipemux_table));
+}
+
+/*
+ * Read the PCIe PIPEMUX from strap
+ */
+static u32 pipemux_strap_read(struct sr_pcie_phy_core *core)
+{
+ u32 pipemux;
+
+ /*
+ * Read PIPEMUX configuration register to determine the pipemux setting
+ *
+ * In the case when the value indicates using HW strap, fall back to
+ * use HW strap
+ */
+ pipemux = readl(core->base + PCIE_PIPEMUX_CFG_OFFSET);
+ pipemux &= PCIE_PIPEMUX_MASK;
+ if (pipemux == PCIE_PIPEMUX_SELECT_STRAP) {
+ pipemux = readl(core->cdru + CDRU_STRAP_DATA_LSW_OFFSET);
+ pipemux >>= PCIE_PIPEMUX_SHIFT;
+ pipemux &= PCIE_PIPEMUX_MASK;
+ }
+
+ return pipemux;
+}
+
+static int sr_pcie_phy_init(struct phy *phy)
+{
+ struct sr_pcie_phy_core *core = dev_get_priv(phy->dev);
+ unsigned int core_idx = phy->id;
+
+ debug("%s %lx\n", __func__, phy->id);
+ /*
+ * Check whether this PHY is for root complex or not. If yes, return
+ * zero so the host driver can proceed to enumeration. If not, return
+ * an error and that will force the host driver to bail out
+ */
+ if (!!((pipemux_table[core->pipemux] >> core_idx) & 0x1))
+ return 0;
+
+ return -ENODEV;
+}
+
+static int sr_pcie_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args)
+{
+ debug("%s %d\n", __func__, args->args[0]);
+ if (args->args_count && args->args[0] < SR_NR_PCIE_PHYS)
+ phy->id = args->args[0];
+ else
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct phy_ops sr_pcie_phy_ops = {
+ .of_xlate = sr_pcie_phy_xlate,
+ .init = sr_pcie_phy_init,
+};
+
+static int sr_pcie_phy_probe(struct udevice *dev)
+{
+ struct sr_pcie_phy_core *core = dev_get_priv(dev);
+
+ core->dev = dev;
+
+ core->base = (void __iomem *)devfdt_get_addr_name(dev, "reg_base");
+ core->cdru = (void __iomem *)devfdt_get_addr_name(dev, "cdru_base");
+ debug("ip base %p\n", core->base);
+ debug("cdru base %p\n", core->cdru);
+
+ /* read the PCIe PIPEMUX strap setting */
+ core->pipemux = pipemux_strap_read(core);
+ if (!pipemux_strap_is_valid(core->pipemux)) {
+ pr_err("invalid PCIe PIPEMUX strap %u\n", core->pipemux);
+ return -EIO;
+ }
+ debug("%s %#x\n", __func__, core->pipemux);
+
+ pr_info("Stingray PCIe PHY driver initialized\n");
+
+ return 0;
+}
+
+static const struct udevice_id sr_pcie_phy_match_table[] = {
+ { .compatible = "brcm,sr-pcie-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(sr_pcie_phy) = {
+ .name = "sr-pcie-phy",
+ .id = UCLASS_PHY,
+ .probe = sr_pcie_phy_probe,
+ .of_match = sr_pcie_phy_match_table,
+ .ops = &sr_pcie_phy_ops,
+ .plat_auto = sizeof(struct sr_pcie_phy_core),
+ .priv_auto = sizeof(struct sr_pcie_phy_core),
+};
diff --git a/roms/u-boot/drivers/phy/phy-core-mipi-dphy.c b/roms/u-boot/drivers/phy/phy-core-mipi-dphy.c
new file mode 100644
index 000000000..ba5f64861
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-core-mipi-dphy.c
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ * Copyright (C) 2018 Cadence Design Systems Inc.
+ */
+
+#include <common.h>
+#include <div64.h>
+
+#include <phy-mipi-dphy.h>
+
+#define PSEC_PER_SEC 1000000000000LL
+
+/*
+ * Minimum D-PHY timings based on MIPI D-PHY specification. Derived
+ * from the valid ranges specified in Section 6.9, Table 14, Page 41
+ * of the D-PHY specification (v2.1).
+ */
+int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
+ unsigned int bpp,
+ unsigned int lanes,
+ struct phy_configure_opts_mipi_dphy *cfg)
+{
+ unsigned long long hs_clk_rate;
+ unsigned long long ui;
+
+ if (!cfg)
+ return -EINVAL;
+
+ hs_clk_rate = pixel_clock * bpp;
+ do_div(hs_clk_rate, lanes);
+
+ ui = ALIGN(PSEC_PER_SEC, hs_clk_rate);
+ do_div(ui, hs_clk_rate);
+
+ cfg->clk_miss = 0;
+ cfg->clk_post = 60000 + 52 * ui;
+ cfg->clk_pre = 8000;
+ cfg->clk_prepare = 38000;
+ cfg->clk_settle = 95000;
+ cfg->clk_term_en = 0;
+ cfg->clk_trail = 60000;
+ cfg->clk_zero = 262000;
+ cfg->d_term_en = 0;
+ cfg->eot = 0;
+ cfg->hs_exit = 100000;
+ cfg->hs_prepare = 40000 + 4 * ui;
+ cfg->hs_zero = 105000 + 6 * ui;
+ cfg->hs_settle = 85000 + 6 * ui;
+ cfg->hs_skip = 40000;
+
+ /*
+ * The MIPI D-PHY specification (Section 6.9, v1.2, Table 14, Page 40)
+ * contains this formula as:
+ *
+ * T_HS-TRAIL = max(n * 8 * ui, 60 + n * 4 * ui)
+ *
+ * where n = 1 for forward-direction HS mode and n = 4 for reverse-
+ * direction HS mode. There's only one setting and this function does
+ * not parameterize on anything other that ui, so this code will
+ * assumes that reverse-direction HS mode is supported and uses n = 4.
+ */
+ cfg->hs_trail = max(4 * 8 * ui, 60000 + 4 * 4 * ui);
+
+ cfg->init = 100;
+ cfg->lpx = 60000;
+ cfg->ta_get = 5 * cfg->lpx;
+ cfg->ta_go = 4 * cfg->lpx;
+ cfg->ta_sure = 2 * cfg->lpx;
+ cfg->wakeup = 1000;
+
+ cfg->hs_clk_rate = hs_clk_rate;
+ cfg->lanes = lanes;
+
+ return 0;
+}
+
+/*
+ * Validate D-PHY configuration according to MIPI D-PHY specification
+ * (v1.2, Section Section 6.9 "Global Operation Timing Parameters").
+ */
+int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy *cfg)
+{
+ unsigned long long ui;
+
+ if (!cfg)
+ return -EINVAL;
+
+ ui = ALIGN(PSEC_PER_SEC, cfg->hs_clk_rate);
+ do_div(ui, cfg->hs_clk_rate);
+
+ if (cfg->clk_miss > 60000)
+ return -EINVAL;
+
+ if (cfg->clk_post < (60000 + 52 * ui))
+ return -EINVAL;
+
+ if (cfg->clk_pre < 8000)
+ return -EINVAL;
+
+ if (cfg->clk_prepare < 38000 || cfg->clk_prepare > 95000)
+ return -EINVAL;
+
+ if (cfg->clk_settle < 95000 || cfg->clk_settle > 300000)
+ return -EINVAL;
+
+ if (cfg->clk_term_en > 38000)
+ return -EINVAL;
+
+ if (cfg->clk_trail < 60000)
+ return -EINVAL;
+
+ if ((cfg->clk_prepare + cfg->clk_zero) < 300000)
+ return -EINVAL;
+
+ if (cfg->d_term_en > (35000 + 4 * ui))
+ return -EINVAL;
+
+ if (cfg->eot > (105000 + 12 * ui))
+ return -EINVAL;
+
+ if (cfg->hs_exit < 100000)
+ return -EINVAL;
+
+ if (cfg->hs_prepare < (40000 + 4 * ui) ||
+ cfg->hs_prepare > (85000 + 6 * ui))
+ return -EINVAL;
+
+ if ((cfg->hs_prepare + cfg->hs_zero) < (145000 + 10 * ui))
+ return -EINVAL;
+
+ if ((cfg->hs_settle < (85000 + 6 * ui)) ||
+ (cfg->hs_settle > (145000 + 10 * ui)))
+ return -EINVAL;
+
+ if (cfg->hs_skip < 40000 || cfg->hs_skip > (55000 + 4 * ui))
+ return -EINVAL;
+
+ if (cfg->hs_trail < max(8 * ui, 60000 + 4 * ui))
+ return -EINVAL;
+
+ if (cfg->init < 100)
+ return -EINVAL;
+
+ if (cfg->lpx < 50000)
+ return -EINVAL;
+
+ if (cfg->ta_get != (5 * cfg->lpx))
+ return -EINVAL;
+
+ if (cfg->ta_go != (4 * cfg->lpx))
+ return -EINVAL;
+
+ if (cfg->ta_sure < cfg->lpx || cfg->ta_sure > (2 * cfg->lpx))
+ return -EINVAL;
+
+ if (cfg->wakeup < 1000)
+ return -EINVAL;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/phy/phy-da8xx-usb.c b/roms/u-boot/drivers/phy/phy-da8xx-usb.c
new file mode 100644
index 000000000..d025188ea
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-da8xx-usb.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Based on the DA8xx "glue layer" code.
+ * Copyright (c) 2008-2019, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * DT support added by: Adam Ford <aford173@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/da8xx-usb.h>
+#include <asm/io.h>
+#include <generic-phy.h>
+
+static int da8xx_usb_phy_power_on(struct phy *phy)
+{
+ unsigned long timeout;
+
+ clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
+ CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN |
+ CFGCHIP2_OTGMODE | CFGCHIP2_REFFREQ,
+ CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN |
+ CFGCHIP2_PHY_PLLON | CFGCHIP2_REFFREQ_24MHZ);
+
+ /* wait until the usb phy pll locks */
+ timeout = get_timer(0);
+ while (get_timer(timeout) < 10) {
+ if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD)
+ return 0;
+ }
+
+ debug("Phy was not turned on\n");
+
+ return -ENODEV;
+}
+
+static int da8xx_usb_phy_power_off(struct phy *phy)
+{
+ clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
+ CFGCHIP2_PHY_PLLON,
+ CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN);
+
+ return 0;
+}
+
+static const struct udevice_id da8xx_phy_ids[] = {
+ { .compatible = "ti,da830-usb-phy" },
+ { }
+};
+
+static struct phy_ops da8xx_phy_ops = {
+ .power_on = da8xx_usb_phy_power_on,
+ .power_off = da8xx_usb_phy_power_off,
+};
+
+U_BOOT_DRIVER(da8xx_phy) = {
+ .name = "da8xx-usb-phy",
+ .id = UCLASS_PHY,
+ .of_match = da8xx_phy_ids,
+ .ops = &da8xx_phy_ops,
+};
diff --git a/roms/u-boot/drivers/phy/phy-mtk-tphy.c b/roms/u-boot/drivers/phy/phy-mtk-tphy.c
new file mode 100644
index 000000000..824244b85
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-mtk-tphy.c
@@ -0,0 +1,753 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015 - 2019 MediaTek Inc.
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ * Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#include <dt-bindings/phy/phy.h>
+
+/* version V1 sub-banks offset base address */
+/* banks shared by multiple phys */
+#define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */
+#define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */
+#define SSUSB_SIFSLV_V1_CHIP 0x300 /* shared by u3 phys */
+/* u2 phy bank */
+#define SSUSB_SIFSLV_V1_U2PHY_COM 0x000
+/* u3/pcie/sata phy banks */
+#define SSUSB_SIFSLV_V1_U3PHYD 0x000
+#define SSUSB_SIFSLV_V1_U3PHYA 0x200
+
+/* version V2 sub-banks offset base address */
+/* u2 phy banks */
+#define SSUSB_SIFSLV_V2_MISC 0x000
+#define SSUSB_SIFSLV_V2_U2FREQ 0x100
+#define SSUSB_SIFSLV_V2_U2PHY_COM 0x300
+/* u3/pcie/sata phy banks */
+#define SSUSB_SIFSLV_V2_SPLLC 0x000
+#define SSUSB_SIFSLV_V2_CHIP 0x100
+#define SSUSB_SIFSLV_V2_U3PHYD 0x200
+#define SSUSB_SIFSLV_V2_U3PHYA 0x400
+
+#define U3P_USBPHYACR0 0x000
+#define PA0_RG_U2PLL_FORCE_ON BIT(15)
+#define PA0_RG_USB20_INTR_EN BIT(5)
+
+#define U3P_USBPHYACR5 0x014
+#define PA5_RG_U2_HSTX_SRCAL_EN BIT(15)
+#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
+#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
+#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
+
+#define U3P_USBPHYACR6 0x018
+#define PA6_RG_U2_BC11_SW_EN BIT(23)
+#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
+#define PA6_RG_U2_SQTH GENMASK(3, 0)
+#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
+
+#define U3P_U2PHYACR4 0x020
+#define P2C_RG_USB20_GPIO_CTL BIT(9)
+#define P2C_USB20_GPIO_MODE BIT(8)
+#define P2C_U2_GPIO_CTR_MSK \
+ (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
+
+#define U3P_U2PHYDTM0 0x068
+#define P2C_FORCE_UART_EN BIT(26)
+#define P2C_FORCE_DATAIN BIT(23)
+#define P2C_FORCE_DM_PULLDOWN BIT(21)
+#define P2C_FORCE_DP_PULLDOWN BIT(20)
+#define P2C_FORCE_XCVRSEL BIT(19)
+#define P2C_FORCE_SUSPENDM BIT(18)
+#define P2C_FORCE_TERMSEL BIT(17)
+#define P2C_RG_DATAIN GENMASK(13, 10)
+#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10)
+#define P2C_RG_DMPULLDOWN BIT(7)
+#define P2C_RG_DPPULLDOWN BIT(6)
+#define P2C_RG_XCVRSEL GENMASK(5, 4)
+#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4)
+#define P2C_RG_SUSPENDM BIT(3)
+#define P2C_RG_TERMSEL BIT(2)
+#define P2C_DTM0_PART_MASK \
+ (P2C_FORCE_DATAIN | P2C_FORCE_DM_PULLDOWN | \
+ P2C_FORCE_DP_PULLDOWN | P2C_FORCE_XCVRSEL | \
+ P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
+ P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
+
+#define U3P_U2PHYDTM1 0x06C
+#define P2C_RG_UART_EN BIT(16)
+#define P2C_FORCE_IDDIG BIT(9)
+#define P2C_RG_VBUSVALID BIT(5)
+#define P2C_RG_SESSEND BIT(4)
+#define P2C_RG_AVALID BIT(2)
+#define P2C_RG_IDDIG BIT(1)
+
+#define U3P_U3_CHIP_GPIO_CTLD 0x0c
+#define P3C_REG_IP_SW_RST BIT(31)
+#define P3C_MCU_BUS_CK_GATE_EN BIT(30)
+#define P3C_FORCE_IP_SW_RST BIT(29)
+
+#define U3P_U3_CHIP_GPIO_CTLE 0x10
+#define P3C_RG_SWRST_U3_PHYD BIT(25)
+#define P3C_RG_SWRST_U3_PHYD_FORCE_EN BIT(24)
+
+#define U3P_U3_PHYA_REG0 0x000
+#define P3A_RG_CLKDRV_OFF GENMASK(3, 2)
+#define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2)
+
+#define U3P_U3_PHYA_REG1 0x004
+#define P3A_RG_CLKDRV_AMP GENMASK(31, 29)
+#define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29)
+
+#define U3P_U3_PHYA_REG6 0x018
+#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
+#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28)
+
+#define U3P_U3_PHYA_REG9 0x024
+#define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
+#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
+
+#define U3P_U3_PHYA_DA_REG0 0x100
+#define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16)
+#define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16)
+#define P3A_RG_XTAL_EXT_PE1H GENMASK(13, 12)
+#define P3A_RG_XTAL_EXT_PE1H_VAL(x) ((0x3 & (x)) << 12)
+#define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10)
+#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10)
+
+#define U3P_U3_PHYA_DA_REG4 0x108
+#define P3A_RG_PLL_DIVEN_PE2H GENMASK(21, 19)
+#define P3A_RG_PLL_BC_PE2H GENMASK(7, 6)
+#define P3A_RG_PLL_BC_PE2H_VAL(x) ((0x3 & (x)) << 6)
+
+#define U3P_U3_PHYA_DA_REG5 0x10c
+#define P3A_RG_PLL_BR_PE2H GENMASK(29, 28)
+#define P3A_RG_PLL_BR_PE2H_VAL(x) ((0x3 & (x)) << 28)
+#define P3A_RG_PLL_IC_PE2H GENMASK(15, 12)
+#define P3A_RG_PLL_IC_PE2H_VAL(x) ((0xf & (x)) << 12)
+
+#define U3P_U3_PHYA_DA_REG6 0x110
+#define P3A_RG_PLL_IR_PE2H GENMASK(19, 16)
+#define P3A_RG_PLL_IR_PE2H_VAL(x) ((0xf & (x)) << 16)
+
+#define U3P_U3_PHYA_DA_REG7 0x114
+#define P3A_RG_PLL_BP_PE2H GENMASK(19, 16)
+#define P3A_RG_PLL_BP_PE2H_VAL(x) ((0xf & (x)) << 16)
+
+#define U3P_U3_PHYA_DA_REG20 0x13c
+#define P3A_RG_PLL_DELTA1_PE2H GENMASK(31, 16)
+#define P3A_RG_PLL_DELTA1_PE2H_VAL(x) ((0xffff & (x)) << 16)
+
+#define U3P_U3_PHYA_DA_REG25 0x148
+#define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0)
+#define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x))
+
+#define U3P_U3_PHYD_LFPS1 0x00c
+#define P3D_RG_FWAKE_TH GENMASK(21, 16)
+#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
+
+#define U3P_U3_PHYD_CDR1 0x05c
+#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
+#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
+#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
+#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
+
+#define U3P_U3_PHYD_RXDET1 0x128
+#define P3D_RG_RXDET_STB2_SET GENMASK(17, 9)
+#define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9)
+
+#define U3P_U3_PHYD_RXDET2 0x12c
+#define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0)
+#define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x))
+
+#define U3P_SPLLC_XTALCTL3 0x018
+#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
+#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
+
+/* SATA register setting */
+#define PHYD_CTRL_SIGNAL_MODE4 0x1c
+/* CDR Charge Pump P-path current adjustment */
+#define RG_CDR_BICLTD1_GEN1_MSK GENMASK(23, 20)
+#define RG_CDR_BICLTD1_GEN1_VAL(x) ((0xf & (x)) << 20)
+#define RG_CDR_BICLTD0_GEN1_MSK GENMASK(11, 8)
+#define RG_CDR_BICLTD0_GEN1_VAL(x) ((0xf & (x)) << 8)
+
+#define PHYD_DESIGN_OPTION2 0x24
+/* Symbol lock count selection */
+#define RG_LOCK_CNT_SEL_MSK GENMASK(5, 4)
+#define RG_LOCK_CNT_SEL_VAL(x) ((0x3 & (x)) << 4)
+
+#define PHYD_DESIGN_OPTION9 0x40
+/* COMWAK GAP width window */
+#define RG_TG_MAX_MSK GENMASK(20, 16)
+#define RG_TG_MAX_VAL(x) ((0x1f & (x)) << 16)
+/* COMINIT GAP width window */
+#define RG_T2_MAX_MSK GENMASK(13, 8)
+#define RG_T2_MAX_VAL(x) ((0x3f & (x)) << 8)
+/* COMWAK GAP width window */
+#define RG_TG_MIN_MSK GENMASK(7, 5)
+#define RG_TG_MIN_VAL(x) ((0x7 & (x)) << 5)
+/* COMINIT GAP width window */
+#define RG_T2_MIN_MSK GENMASK(4, 0)
+#define RG_T2_MIN_VAL(x) (0x1f & (x))
+
+#define ANA_RG_CTRL_SIGNAL1 0x4c
+/* TX driver tail current control for 0dB de-empahsis mdoe for Gen1 speed */
+#define RG_IDRV_0DB_GEN1_MSK GENMASK(13, 8)
+#define RG_IDRV_0DB_GEN1_VAL(x) ((0x3f & (x)) << 8)
+
+#define ANA_RG_CTRL_SIGNAL4 0x58
+#define RG_CDR_BICLTR_GEN1_MSK GENMASK(23, 20)
+#define RG_CDR_BICLTR_GEN1_VAL(x) ((0xf & (x)) << 20)
+/* Loop filter R1 resistance adjustment for Gen1 speed */
+#define RG_CDR_BR_GEN2_MSK GENMASK(10, 8)
+#define RG_CDR_BR_GEN2_VAL(x) ((0x7 & (x)) << 8)
+
+#define ANA_RG_CTRL_SIGNAL6 0x60
+/* I-path capacitance adjustment for Gen1 */
+#define RG_CDR_BC_GEN1_MSK GENMASK(28, 24)
+#define RG_CDR_BC_GEN1_VAL(x) ((0x1f & (x)) << 24)
+#define RG_CDR_BIRLTR_GEN1_MSK GENMASK(4, 0)
+#define RG_CDR_BIRLTR_GEN1_VAL(x) (0x1f & (x))
+
+#define ANA_EQ_EYE_CTRL_SIGNAL1 0x6c
+/* RX Gen1 LEQ tuning step */
+#define RG_EQ_DLEQ_LFI_GEN1_MSK GENMASK(11, 8)
+#define RG_EQ_DLEQ_LFI_GEN1_VAL(x) ((0xf & (x)) << 8)
+
+#define ANA_EQ_EYE_CTRL_SIGNAL4 0xd8
+#define RG_CDR_BIRLTD0_GEN1_MSK GENMASK(20, 16)
+#define RG_CDR_BIRLTD0_GEN1_VAL(x) ((0x1f & (x)) << 16)
+
+#define ANA_EQ_EYE_CTRL_SIGNAL5 0xdc
+#define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0)
+#define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x))
+
+enum mtk_phy_version {
+ MTK_TPHY_V1 = 1,
+ MTK_TPHY_V2,
+};
+
+struct u2phy_banks {
+ void __iomem *misc;
+ void __iomem *fmreg;
+ void __iomem *com;
+};
+
+struct u3phy_banks {
+ void __iomem *spllc;
+ void __iomem *chip;
+ void __iomem *phyd; /* include u3phyd_bank2 */
+ void __iomem *phya; /* include u3phya_da */
+};
+
+struct mtk_phy_instance {
+ void __iomem *port_base;
+ const struct device_node *np;
+ union {
+ struct u2phy_banks u2_banks;
+ struct u3phy_banks u3_banks;
+ };
+
+ struct clk ref_clk; /* reference clock of (digital) phy */
+ struct clk da_ref_clk; /* reference clock of analog phy */
+ u32 index;
+ u32 type;
+};
+
+struct mtk_tphy {
+ struct udevice *dev;
+ void __iomem *sif_base;
+ enum mtk_phy_version version;
+ struct mtk_phy_instance **phys;
+ int nphys;
+};
+
+static void u2_phy_instance_init(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+{
+ struct u2phy_banks *u2_banks = &instance->u2_banks;
+
+ /* switch to USB function, and enable usb pll */
+ clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM0,
+ P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM,
+ P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0));
+
+ clrbits_le32(u2_banks->com + U3P_U2PHYDTM1, P2C_RG_UART_EN);
+ setbits_le32(u2_banks->com + U3P_USBPHYACR0, PA0_RG_USB20_INTR_EN);
+
+ /* disable switch 100uA current to SSUSB */
+ clrbits_le32(u2_banks->com + U3P_USBPHYACR5, PA5_RG_U2_HS_100U_U3_EN);
+
+ clrbits_le32(u2_banks->com + U3P_U2PHYACR4, P2C_U2_GPIO_CTR_MSK);
+
+ /* DP/DM BC1.1 path Disable */
+ clrsetbits_le32(u2_banks->com + U3P_USBPHYACR6,
+ PA6_RG_U2_BC11_SW_EN | PA6_RG_U2_SQTH,
+ PA6_RG_U2_SQTH_VAL(2));
+
+ /* set HS slew rate */
+ clrsetbits_le32(u2_banks->com + U3P_USBPHYACR5,
+ PA5_RG_U2_HSTX_SRCTRL, PA5_RG_U2_HSTX_SRCTRL_VAL(4));
+
+ dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
+}
+
+static void u2_phy_instance_power_on(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+{
+ struct u2phy_banks *u2_banks = &instance->u2_banks;
+
+ clrbits_le32(u2_banks->com + U3P_U2PHYDTM0,
+ P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
+
+ /* OTG Enable */
+ setbits_le32(u2_banks->com + U3P_USBPHYACR6,
+ PA6_RG_U2_OTG_VBUSCMP_EN);
+
+ clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM1,
+ P2C_RG_SESSEND, P2C_RG_VBUSVALID | P2C_RG_AVALID);
+
+ dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
+}
+
+static void u2_phy_instance_power_off(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+{
+ struct u2phy_banks *u2_banks = &instance->u2_banks;
+
+ clrbits_le32(u2_banks->com + U3P_U2PHYDTM0,
+ P2C_RG_XCVRSEL | P2C_RG_DATAIN);
+
+ /* OTG Disable */
+ clrbits_le32(u2_banks->com + U3P_USBPHYACR6,
+ PA6_RG_U2_OTG_VBUSCMP_EN);
+
+ clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM1,
+ P2C_RG_VBUSVALID | P2C_RG_AVALID, P2C_RG_SESSEND);
+
+ dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
+}
+
+static void u3_phy_instance_init(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+{
+ struct u3phy_banks *u3_banks = &instance->u3_banks;
+
+ /* gating PCIe Analog XTAL clock */
+ setbits_le32(u3_banks->spllc + U3P_SPLLC_XTALCTL3,
+ XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD);
+
+ /* gating XSQ */
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG0,
+ P3A_RG_XTAL_EXT_EN_U3, P3A_RG_XTAL_EXT_EN_U3_VAL(2));
+
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG9,
+ P3A_RG_RX_DAC_MUX, P3A_RG_RX_DAC_MUX_VAL(4));
+
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG6,
+ P3A_RG_TX_EIDLE_CM, P3A_RG_TX_EIDLE_CM_VAL(0xe));
+
+ clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_CDR1,
+ P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1,
+ P3D_RG_CDR_BIR_LTD0_VAL(0xc) |
+ P3D_RG_CDR_BIR_LTD1_VAL(0x3));
+
+ clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_LFPS1,
+ P3D_RG_FWAKE_TH, P3D_RG_FWAKE_TH_VAL(0x34));
+
+ clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET1,
+ P3D_RG_RXDET_STB2_SET, P3D_RG_RXDET_STB2_SET_VAL(0x10));
+
+ clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET2,
+ P3D_RG_RXDET_STB2_SET_P3,
+ P3D_RG_RXDET_STB2_SET_P3_VAL(0x10));
+
+ dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
+}
+
+static void pcie_phy_instance_init(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+{
+ struct u3phy_banks *u3_banks = &instance->u3_banks;
+
+ if (tphy->version != MTK_TPHY_V1)
+ return;
+
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG0,
+ P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H,
+ P3A_RG_XTAL_EXT_PE1H_VAL(0x2) |
+ P3A_RG_XTAL_EXT_PE2H_VAL(0x2));
+
+ /* ref clk drive */
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG1, P3A_RG_CLKDRV_AMP,
+ P3A_RG_CLKDRV_AMP_VAL(0x4));
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG0, P3A_RG_CLKDRV_OFF,
+ P3A_RG_CLKDRV_OFF_VAL(0x1));
+
+ /* SSC delta -5000ppm */
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG20,
+ P3A_RG_PLL_DELTA1_PE2H,
+ P3A_RG_PLL_DELTA1_PE2H_VAL(0x3c));
+
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG25,
+ P3A_RG_PLL_DELTA_PE2H,
+ P3A_RG_PLL_DELTA_PE2H_VAL(0x36));
+
+ /* change pll BW 0.6M */
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG5,
+ P3A_RG_PLL_BR_PE2H | P3A_RG_PLL_IC_PE2H,
+ P3A_RG_PLL_BR_PE2H_VAL(0x1) |
+ P3A_RG_PLL_IC_PE2H_VAL(0x1));
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG4,
+ P3A_RG_PLL_DIVEN_PE2H | P3A_RG_PLL_BC_PE2H,
+ P3A_RG_PLL_BC_PE2H_VAL(0x3));
+
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG6,
+ P3A_RG_PLL_IR_PE2H, P3A_RG_PLL_IR_PE2H_VAL(0x2));
+ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG7,
+ P3A_RG_PLL_BP_PE2H, P3A_RG_PLL_BP_PE2H_VAL(0xa));
+
+ /* Tx Detect Rx Timing: 10us -> 5us */
+ clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET1,
+ P3D_RG_RXDET_STB2_SET,
+ P3D_RG_RXDET_STB2_SET_VAL(0x10));
+ clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET2,
+ P3D_RG_RXDET_STB2_SET_P3,
+ P3D_RG_RXDET_STB2_SET_P3_VAL(0x10));
+
+ /* wait for PCIe subsys register to active */
+ udelay(3000);
+}
+
+static void sata_phy_instance_init(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+{
+ struct u3phy_banks *u3_banks = &instance->u3_banks;
+
+ clrsetbits_le32(u3_banks->phyd + ANA_RG_CTRL_SIGNAL6,
+ RG_CDR_BIRLTR_GEN1_MSK | RG_CDR_BC_GEN1_MSK,
+ RG_CDR_BIRLTR_GEN1_VAL(0x6) |
+ RG_CDR_BC_GEN1_VAL(0x1a));
+ clrsetbits_le32(u3_banks->phyd + ANA_EQ_EYE_CTRL_SIGNAL4,
+ RG_CDR_BIRLTD0_GEN1_MSK,
+ RG_CDR_BIRLTD0_GEN1_VAL(0x18));
+ clrsetbits_le32(u3_banks->phyd + ANA_EQ_EYE_CTRL_SIGNAL5,
+ RG_CDR_BIRLTD0_GEN3_MSK,
+ RG_CDR_BIRLTD0_GEN3_VAL(0x06));
+ clrsetbits_le32(u3_banks->phyd + ANA_RG_CTRL_SIGNAL4,
+ RG_CDR_BICLTR_GEN1_MSK | RG_CDR_BR_GEN2_MSK,
+ RG_CDR_BICLTR_GEN1_VAL(0x0c) |
+ RG_CDR_BR_GEN2_VAL(0x07));
+ clrsetbits_le32(u3_banks->phyd + PHYD_CTRL_SIGNAL_MODE4,
+ RG_CDR_BICLTD0_GEN1_MSK | RG_CDR_BICLTD1_GEN1_MSK,
+ RG_CDR_BICLTD0_GEN1_VAL(0x08) |
+ RG_CDR_BICLTD1_GEN1_VAL(0x02));
+ clrsetbits_le32(u3_banks->phyd + PHYD_DESIGN_OPTION2,
+ RG_LOCK_CNT_SEL_MSK,
+ RG_LOCK_CNT_SEL_VAL(0x02));
+ clrsetbits_le32(u3_banks->phyd + PHYD_DESIGN_OPTION9,
+ RG_T2_MIN_MSK | RG_TG_MIN_MSK |
+ RG_T2_MAX_MSK | RG_TG_MAX_MSK,
+ RG_T2_MIN_VAL(0x12) | RG_TG_MIN_VAL(0x04) |
+ RG_T2_MAX_VAL(0x31) | RG_TG_MAX_VAL(0x0e));
+ clrsetbits_le32(u3_banks->phyd + ANA_RG_CTRL_SIGNAL1,
+ RG_IDRV_0DB_GEN1_MSK,
+ RG_IDRV_0DB_GEN1_VAL(0x20));
+ clrsetbits_le32(u3_banks->phyd + ANA_EQ_EYE_CTRL_SIGNAL1,
+ RG_EQ_DLEQ_LFI_GEN1_MSK,
+ RG_EQ_DLEQ_LFI_GEN1_VAL(0x03));
+}
+
+static void pcie_phy_instance_power_on(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+{
+ struct u3phy_banks *bank = &instance->u3_banks;
+
+ clrbits_le32(bank->chip + U3P_U3_CHIP_GPIO_CTLD,
+ P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST);
+ clrbits_le32(bank->chip + U3P_U3_CHIP_GPIO_CTLE,
+ P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD);
+}
+
+static void pcie_phy_instance_power_off(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+
+{
+ struct u3phy_banks *bank = &instance->u3_banks;
+
+ setbits_le32(bank->chip + U3P_U3_CHIP_GPIO_CTLD,
+ P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST);
+ setbits_le32(bank->chip + U3P_U3_CHIP_GPIO_CTLE,
+ P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD);
+}
+
+static void phy_v1_banks_init(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+{
+ struct u2phy_banks *u2_banks = &instance->u2_banks;
+ struct u3phy_banks *u3_banks = &instance->u3_banks;
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ u2_banks->misc = NULL;
+ u2_banks->fmreg = tphy->sif_base + SSUSB_SIFSLV_V1_U2FREQ;
+ u2_banks->com = instance->port_base + SSUSB_SIFSLV_V1_U2PHY_COM;
+ break;
+ case PHY_TYPE_USB3:
+ case PHY_TYPE_PCIE:
+ u3_banks->spllc = tphy->sif_base + SSUSB_SIFSLV_V1_SPLLC;
+ u3_banks->chip = tphy->sif_base + SSUSB_SIFSLV_V1_CHIP;
+ u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;
+ u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA;
+ break;
+ case PHY_TYPE_SATA:
+ u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;
+ break;
+ default:
+ dev_err(tphy->dev, "incompatible PHY type\n");
+ return;
+ }
+}
+
+static void phy_v2_banks_init(struct mtk_tphy *tphy,
+ struct mtk_phy_instance *instance)
+{
+ struct u2phy_banks *u2_banks = &instance->u2_banks;
+ struct u3phy_banks *u3_banks = &instance->u3_banks;
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC;
+ u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ;
+ u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM;
+ break;
+ case PHY_TYPE_USB3:
+ case PHY_TYPE_PCIE:
+ u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC;
+ u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP;
+ u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD;
+ u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA;
+ break;
+ default:
+ dev_err(tphy->dev, "incompatible PHY type\n");
+ return;
+ }
+}
+
+static int mtk_phy_init(struct phy *phy)
+{
+ struct mtk_tphy *tphy = dev_get_priv(phy->dev);
+ struct mtk_phy_instance *instance = tphy->phys[phy->id];
+ int ret;
+
+ ret = clk_enable(&instance->ref_clk);
+ if (ret < 0) {
+ dev_err(tphy->dev, "failed to enable ref_clk\n");
+ return ret;
+ }
+
+ ret = clk_enable(&instance->da_ref_clk);
+ if (ret < 0) {
+ dev_err(tphy->dev, "failed to enable da_ref_clk %d\n", ret);
+ clk_disable(&instance->ref_clk);
+ return ret;
+ }
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ u2_phy_instance_init(tphy, instance);
+ break;
+ case PHY_TYPE_USB3:
+ u3_phy_instance_init(tphy, instance);
+ break;
+ case PHY_TYPE_PCIE:
+ pcie_phy_instance_init(tphy, instance);
+ break;
+ case PHY_TYPE_SATA:
+ sata_phy_instance_init(tphy, instance);
+ break;
+ default:
+ dev_err(tphy->dev, "incompatible PHY type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_phy_power_on(struct phy *phy)
+{
+ struct mtk_tphy *tphy = dev_get_priv(phy->dev);
+ struct mtk_phy_instance *instance = tphy->phys[phy->id];
+
+ if (instance->type == PHY_TYPE_USB2)
+ u2_phy_instance_power_on(tphy, instance);
+ else if (instance->type == PHY_TYPE_PCIE)
+ pcie_phy_instance_power_on(tphy, instance);
+
+ return 0;
+}
+
+static int mtk_phy_power_off(struct phy *phy)
+{
+ struct mtk_tphy *tphy = dev_get_priv(phy->dev);
+ struct mtk_phy_instance *instance = tphy->phys[phy->id];
+
+ if (instance->type == PHY_TYPE_USB2)
+ u2_phy_instance_power_off(tphy, instance);
+ else if (instance->type == PHY_TYPE_PCIE)
+ pcie_phy_instance_power_off(tphy, instance);
+
+ return 0;
+}
+
+static int mtk_phy_exit(struct phy *phy)
+{
+ struct mtk_tphy *tphy = dev_get_priv(phy->dev);
+ struct mtk_phy_instance *instance = tphy->phys[phy->id];
+
+ clk_disable(&instance->da_ref_clk);
+ clk_disable(&instance->ref_clk);
+
+ return 0;
+}
+
+static int mtk_phy_xlate(struct phy *phy,
+ struct ofnode_phandle_args *args)
+{
+ struct mtk_tphy *tphy = dev_get_priv(phy->dev);
+ struct mtk_phy_instance *instance = NULL;
+ const struct device_node *phy_np = ofnode_to_np(args->node);
+ u32 index;
+
+ if (!phy_np) {
+ dev_err(phy->dev, "null pointer phy node\n");
+ return -EINVAL;
+ }
+
+ if (args->args_count < 1) {
+ dev_err(phy->dev, "invalid number of cells in 'phy' property\n");
+ return -EINVAL;
+ }
+
+ for (index = 0; index < tphy->nphys; index++)
+ if (phy_np == tphy->phys[index]->np) {
+ instance = tphy->phys[index];
+ break;
+ }
+
+ if (!instance) {
+ dev_err(phy->dev, "failed to find appropriate phy\n");
+ return -EINVAL;
+ }
+
+ phy->id = index;
+ instance->type = args->args[1];
+ if (!(instance->type == PHY_TYPE_USB2 ||
+ instance->type == PHY_TYPE_USB3 ||
+ instance->type == PHY_TYPE_SATA ||
+ instance->type == PHY_TYPE_PCIE)) {
+ dev_err(phy->dev, "unsupported device type\n");
+ return -EINVAL;
+ }
+
+ if (tphy->version == MTK_TPHY_V1) {
+ phy_v1_banks_init(tphy, instance);
+ } else if (tphy->version == MTK_TPHY_V2) {
+ phy_v2_banks_init(tphy, instance);
+ } else {
+ dev_err(phy->dev, "phy version is not supported\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct phy_ops mtk_tphy_ops = {
+ .init = mtk_phy_init,
+ .exit = mtk_phy_exit,
+ .power_on = mtk_phy_power_on,
+ .power_off = mtk_phy_power_off,
+ .of_xlate = mtk_phy_xlate,
+};
+
+static int mtk_tphy_probe(struct udevice *dev)
+{
+ struct mtk_tphy *tphy = dev_get_priv(dev);
+ ofnode subnode;
+ int index = 0;
+
+ tphy->nphys = dev_get_child_count(dev);
+
+ tphy->phys = devm_kcalloc(dev, tphy->nphys, sizeof(*tphy->phys),
+ GFP_KERNEL);
+ if (!tphy->phys)
+ return -ENOMEM;
+
+ tphy->dev = dev;
+ tphy->version = dev_get_driver_data(dev);
+
+ /* v1 has shared banks for usb/pcie mode, */
+ /* but not for sata mode */
+ if (tphy->version == MTK_TPHY_V1) {
+ tphy->sif_base = dev_read_addr_ptr(dev);
+ }
+
+ dev_for_each_subnode(subnode, dev) {
+ struct mtk_phy_instance *instance;
+ fdt_addr_t addr;
+ int err;
+
+ instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
+ if (!instance)
+ return -ENOMEM;
+
+ addr = ofnode_get_addr(subnode);
+ if (addr == FDT_ADDR_T_NONE)
+ return -ENOMEM;
+
+ instance->port_base = map_sysmem(addr, 0);
+ instance->index = index;
+ instance->np = ofnode_to_np(subnode);
+ tphy->phys[index] = instance;
+ index++;
+
+ err = clk_get_optional_nodev(subnode, "ref",
+ &instance->ref_clk);
+ if (err)
+ return err;
+
+ err = clk_get_optional_nodev(subnode, "da_ref",
+ &instance->da_ref_clk);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id mtk_tphy_id_table[] = {
+ { .compatible = "mediatek,generic-tphy-v1", .data = MTK_TPHY_V1, },
+ { .compatible = "mediatek,generic-tphy-v2", .data = MTK_TPHY_V2, },
+ { }
+};
+
+U_BOOT_DRIVER(mtk_tphy) = {
+ .name = "mtk-tphy",
+ .id = UCLASS_PHY,
+ .of_match = mtk_tphy_id_table,
+ .ops = &mtk_tphy_ops,
+ .probe = mtk_tphy_probe,
+ .priv_auto = sizeof(struct mtk_tphy),
+};
diff --git a/roms/u-boot/drivers/phy/phy-qcom-ipq4019-usb.c b/roms/u-boot/drivers/phy/phy-qcom-ipq4019-usb.c
new file mode 100644
index 000000000..580848924
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-qcom-ipq4019-usb.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ *
+ * Based on Linux driver
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+struct ipq4019_usb_phy {
+ phys_addr_t base;
+ struct reset_ctl por_rst;
+ struct reset_ctl srif_rst;
+};
+
+static int ipq4019_ss_phy_power_off(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ reset_assert(&phy->por_rst);
+ mdelay(10);
+
+ return 0;
+}
+
+static int ipq4019_ss_phy_power_on(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ ipq4019_ss_phy_power_off(_phy);
+
+ reset_deassert(&phy->por_rst);
+
+ return 0;
+}
+
+static struct phy_ops ipq4019_usb_ss_phy_ops = {
+ .power_on = ipq4019_ss_phy_power_on,
+ .power_off = ipq4019_ss_phy_power_off,
+};
+
+static int ipq4019_usb_ss_phy_probe(struct udevice *dev)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(dev);
+ int ret;
+
+ phy->base = dev_read_addr(dev);
+ if (phy->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = reset_get_by_name(dev, "por_rst", &phy->por_rst);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id ipq4019_usb_ss_phy_ids[] = {
+ { .compatible = "qcom,usb-ss-ipq4019-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(ipq4019_usb_ss_phy) = {
+ .name = "ipq4019-usb-ss-phy",
+ .id = UCLASS_PHY,
+ .of_match = ipq4019_usb_ss_phy_ids,
+ .ops = &ipq4019_usb_ss_phy_ops,
+ .probe = ipq4019_usb_ss_phy_probe,
+ .priv_auto = sizeof(struct ipq4019_usb_phy),
+};
+
+static int ipq4019_hs_phy_power_off(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ reset_assert(&phy->por_rst);
+ mdelay(10);
+
+ reset_assert(&phy->srif_rst);
+ mdelay(10);
+
+ return 0;
+}
+
+static int ipq4019_hs_phy_power_on(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ ipq4019_hs_phy_power_off(_phy);
+
+ reset_deassert(&phy->srif_rst);
+ mdelay(10);
+
+ reset_deassert(&phy->por_rst);
+
+ return 0;
+}
+
+static struct phy_ops ipq4019_usb_hs_phy_ops = {
+ .power_on = ipq4019_hs_phy_power_on,
+ .power_off = ipq4019_hs_phy_power_off,
+};
+
+static int ipq4019_usb_hs_phy_probe(struct udevice *dev)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(dev);
+ int ret;
+
+ phy->base = dev_read_addr(dev);
+ if (phy->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = reset_get_by_name(dev, "por_rst", &phy->por_rst);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_name(dev, "srif_rst", &phy->srif_rst);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id ipq4019_usb_hs_phy_ids[] = {
+ { .compatible = "qcom,usb-hs-ipq4019-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(ipq4019_usb_hs_phy) = {
+ .name = "ipq4019-usb-hs-phy",
+ .id = UCLASS_PHY,
+ .of_match = ipq4019_usb_hs_phy_ids,
+ .ops = &ipq4019_usb_hs_phy_ops,
+ .probe = ipq4019_usb_hs_phy_probe,
+ .priv_auto = sizeof(struct ipq4019_usb_phy),
+};
diff --git a/roms/u-boot/drivers/phy/phy-rcar-gen2.c b/roms/u-boot/drivers/phy/phy-rcar-gen2.c
new file mode 100644
index 000000000..179409592
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-rcar-gen2.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RCar Gen2 USB PHY driver
+ *
+ * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <div64.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <generic-phy.h>
+#include <malloc.h>
+#include <reset.h>
+#include <syscon.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+
+#define USBHS_LPSTS 0x02
+#define USBHS_UGCTRL 0x80
+#define USBHS_UGCTRL2 0x84
+#define USBHS_UGSTS 0x88 /* From technical update */
+
+/* Low Power Status register (LPSTS) */
+#define USBHS_LPSTS_SUSPM 0x4000
+
+/* USB General control register (UGCTRL) */
+#define USBHS_UGCTRL_CONNECT BIT(2)
+#define USBHS_UGCTRL_PLLRESET BIT(0)
+
+/* USB General control register 2 (UGCTRL2) */
+#define USBHS_UGCTRL2_USB2SEL 0x80000000
+#define USBHS_UGCTRL2_USB2SEL_PCI 0x00000000
+#define USBHS_UGCTRL2_USB2SEL_USB30 0x80000000
+#define USBHS_UGCTRL2_USB0SEL 0x00000030
+#define USBHS_UGCTRL2_USB0SEL_PCI 0x00000010
+#define USBHS_UGCTRL2_USB0SEL_HS_USB 0x00000030
+
+/* USB General status register (UGSTS) */
+#define USBHS_UGSTS_LOCK 0x00000100 /* From technical update */
+
+#define PHYS_PER_CHANNEL 2
+
+struct rcar_gen2_phy {
+ fdt_addr_t regs;
+ struct clk clk;
+};
+
+static int rcar_gen2_phy_phy_init(struct phy *phy)
+{
+ struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
+ u16 chan = phy->id & 0xffff;
+ u16 mode = (phy->id >> 16) & 0xffff;
+ u32 clrmask, setmask;
+
+ if (chan == 0) {
+ clrmask = USBHS_UGCTRL2_USB0SEL;
+ setmask = mode ? USBHS_UGCTRL2_USB0SEL_HS_USB :
+ USBHS_UGCTRL2_USB0SEL_PCI;
+ } else {
+ clrmask = USBHS_UGCTRL2_USB2SEL;
+ setmask = mode ? USBHS_UGCTRL2_USB2SEL_USB30 :
+ USBHS_UGCTRL2_USB2SEL_PCI;
+ }
+ clrsetbits_le32(priv->regs + USBHS_UGCTRL2, clrmask, setmask);
+
+ return 0;
+}
+
+static int rcar_gen2_phy_phy_power_on(struct phy *phy)
+{
+ struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
+ int i;
+ u32 value;
+
+ /* Power on USBHS PHY */
+ clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET);
+
+ setbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM);
+
+ for (i = 0; i < 20; i++) {
+ value = readl(priv->regs + USBHS_UGSTS);
+ if ((value & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) {
+ setbits_le32(priv->regs + USBHS_UGCTRL,
+ USBHS_UGCTRL_CONNECT);
+ return 0;
+ }
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int rcar_gen2_phy_phy_power_off(struct phy *phy)
+{
+ struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
+
+ /* Power off USBHS PHY */
+ clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_CONNECT);
+
+ clrbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM);
+
+ setbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET);
+
+ return 0;
+}
+
+static int rcar_gen2_phy_of_xlate(struct phy *phy,
+ struct ofnode_phandle_args *args)
+{
+ if (args->args_count != 2) {
+ dev_err(phy->dev, "Invalid DT PHY argument count: %d\n",
+ args->args_count);
+ return -EINVAL;
+ }
+
+ if (args->args[0] != 0 && args->args[0] != 2) {
+ dev_err(phy->dev, "Invalid DT PHY channel: %d\n",
+ args->args[0]);
+ return -EINVAL;
+ }
+
+ if (args->args[1] != 0 && args->args[1] != 1) {
+ dev_err(phy->dev, "Invalid DT PHY mode: %d\n",
+ args->args[1]);
+ return -EINVAL;
+ }
+
+ if (args->args_count)
+ phy->id = args->args[0] | (args->args[1] << 16);
+ else
+ phy->id = 0;
+
+ return 0;
+}
+
+static const struct phy_ops rcar_gen2_phy_phy_ops = {
+ .init = rcar_gen2_phy_phy_init,
+ .power_on = rcar_gen2_phy_phy_power_on,
+ .power_off = rcar_gen2_phy_phy_power_off,
+ .of_xlate = rcar_gen2_phy_of_xlate,
+};
+
+static int rcar_gen2_phy_probe(struct udevice *dev)
+{
+ struct rcar_gen2_phy *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->regs = dev_read_addr(dev);
+ if (priv->regs == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /* Enable clock */
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int rcar_gen2_phy_remove(struct udevice *dev)
+{
+ struct rcar_gen2_phy *priv = dev_get_priv(dev);
+
+ clk_disable(&priv->clk);
+ clk_free(&priv->clk);
+
+ return 0;
+}
+
+static const struct udevice_id rcar_gen2_phy_of_match[] = {
+ { .compatible = "renesas,rcar-gen2-usb-phy", },
+ { },
+};
+
+U_BOOT_DRIVER(rcar_gen2_phy) = {
+ .name = "rcar-gen2-phy",
+ .id = UCLASS_PHY,
+ .of_match = rcar_gen2_phy_of_match,
+ .ops = &rcar_gen2_phy_phy_ops,
+ .probe = rcar_gen2_phy_probe,
+ .remove = rcar_gen2_phy_remove,
+ .priv_auto = sizeof(struct rcar_gen2_phy),
+};
diff --git a/roms/u-boot/drivers/phy/phy-rcar-gen3.c b/roms/u-boot/drivers/phy/phy-rcar-gen3.c
new file mode 100644
index 000000000..8c5963142
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-rcar-gen3.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RCar Gen3 USB PHY driver
+ *
+ * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <div64.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <generic-phy.h>
+#include <malloc.h>
+#include <reset.h>
+#include <syscon.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <power/regulator.h>
+
+/* USB2.0 Host registers (original offset is +0x200) */
+#define USB2_INT_ENABLE 0x000
+#define USB2_USBCTR 0x00c
+#define USB2_SPD_RSM_TIMSET 0x10c
+#define USB2_OC_TIMSET 0x110
+#define USB2_COMMCTRL 0x600
+#define USB2_OBINTSTA 0x604
+#define USB2_OBINTEN 0x608
+#define USB2_VBCTRL 0x60c
+#define USB2_LINECTRL1 0x610
+#define USB2_ADPCTRL 0x630
+
+/* USBCTR */
+#define USB2_USBCTR_PLL_RST BIT(1)
+
+/* SPD_RSM_TIMSET */
+#define USB2_SPD_RSM_TIMSET_INIT 0x014e029b
+
+/* OC_TIMSET */
+#define USB2_OC_TIMSET_INIT 0x000209ab
+
+/* COMMCTRL */
+#define USB2_COMMCTRL_OTG_PERI BIT(31) /* 1 = Peripheral mode */
+
+/* LINECTRL1 */
+#define USB2_LINECTRL1_DP_RPD BIT(18)
+#define USB2_LINECTRL1_DM_RPD BIT(16)
+
+/* ADPCTRL */
+#define USB2_ADPCTRL_DRVVBUS BIT(4)
+
+struct rcar_gen3_phy {
+ fdt_addr_t regs;
+ struct clk clk;
+ struct udevice *vbus_supply;
+};
+
+static int rcar_gen3_phy_phy_init(struct phy *phy)
+{
+ struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
+
+ /* Initialize USB2 part */
+ writel(0, priv->regs + USB2_INT_ENABLE);
+ writel(USB2_SPD_RSM_TIMSET_INIT, priv->regs + USB2_SPD_RSM_TIMSET);
+ writel(USB2_OC_TIMSET_INIT, priv->regs + USB2_OC_TIMSET);
+
+ setbits_le32(priv->regs + USB2_LINECTRL1,
+ USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD);
+
+ clrbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI);
+
+ setbits_le32(priv->regs + USB2_ADPCTRL, USB2_ADPCTRL_DRVVBUS);
+
+ return 0;
+}
+
+static int rcar_gen3_phy_phy_power_on(struct phy *phy)
+{
+ struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
+ int ret;
+
+ if (priv->vbus_supply) {
+ ret = regulator_set_enable(priv->vbus_supply, true);
+ if (ret)
+ return ret;
+ }
+
+ setbits_le32(priv->regs + USB2_USBCTR, USB2_USBCTR_PLL_RST);
+ clrbits_le32(priv->regs + USB2_USBCTR, USB2_USBCTR_PLL_RST);
+
+ return 0;
+}
+
+static int rcar_gen3_phy_phy_power_off(struct phy *phy)
+{
+ struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
+
+ if (!priv->vbus_supply)
+ return 0;
+
+ return regulator_set_enable(priv->vbus_supply, false);
+}
+
+static const struct phy_ops rcar_gen3_phy_phy_ops = {
+ .init = rcar_gen3_phy_phy_init,
+ .power_on = rcar_gen3_phy_phy_power_on,
+ .power_off = rcar_gen3_phy_phy_power_off,
+};
+
+static int rcar_gen3_phy_probe(struct udevice *dev)
+{
+ struct rcar_gen3_phy *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->regs = dev_read_addr(dev);
+ if (priv->regs == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = device_get_supply_regulator(dev, "vbus-supply",
+ &priv->vbus_supply);
+ if (ret && ret != -ENOENT) {
+ pr_err("Failed to get PHY regulator\n");
+ return ret;
+ }
+
+ /* Enable clock */
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int rcar_gen3_phy_remove(struct udevice *dev)
+{
+ struct rcar_gen3_phy *priv = dev_get_priv(dev);
+
+ clk_disable(&priv->clk);
+ clk_free(&priv->clk);
+
+ return 0;
+}
+
+static const struct udevice_id rcar_gen3_phy_of_match[] = {
+ { .compatible = "renesas,rcar-gen3-usb2-phy", },
+ { },
+};
+
+U_BOOT_DRIVER(rcar_gen3_phy) = {
+ .name = "rcar-gen3-phy",
+ .id = UCLASS_PHY,
+ .of_match = rcar_gen3_phy_of_match,
+ .ops = &rcar_gen3_phy_phy_ops,
+ .probe = rcar_gen3_phy_probe,
+ .remove = rcar_gen3_phy_remove,
+ .priv_auto = sizeof(struct rcar_gen3_phy),
+};
diff --git a/roms/u-boot/drivers/phy/phy-stm32-usbphyc.c b/roms/u-boot/drivers/phy/phy-stm32-usbphyc.c
new file mode 100644
index 000000000..02d859a03
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-stm32-usbphyc.c
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#define LOG_CATEGORY UCLASS_PHY
+
+#include <common.h>
+#include <clk.h>
+#include <div64.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <reset.h>
+#include <syscon.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+
+/* USBPHYC registers */
+#define STM32_USBPHYC_PLL 0x0
+#define STM32_USBPHYC_MISC 0x8
+
+/* STM32_USBPHYC_PLL bit fields */
+#define PLLNDIV GENMASK(6, 0)
+#define PLLNDIV_SHIFT 0
+#define PLLFRACIN GENMASK(25, 10)
+#define PLLFRACIN_SHIFT 10
+#define PLLEN BIT(26)
+#define PLLSTRB BIT(27)
+#define PLLSTRBYP BIT(28)
+#define PLLFRACCTL BIT(29)
+#define PLLDITHEN0 BIT(30)
+#define PLLDITHEN1 BIT(31)
+
+/* STM32_USBPHYC_MISC bit fields */
+#define SWITHOST BIT(0)
+
+#define MAX_PHYS 2
+
+/* max 100 us for PLL lock and 100 us for PHY init */
+#define PLL_INIT_TIME_US 200
+#define PLL_PWR_DOWN_TIME_US 5
+#define PLL_FVCO 2880 /* in MHz */
+#define PLL_INFF_MIN_RATE 19200000 /* in Hz */
+#define PLL_INFF_MAX_RATE 38400000 /* in Hz */
+
+struct pll_params {
+ u8 ndiv;
+ u16 frac;
+};
+
+struct stm32_usbphyc {
+ fdt_addr_t base;
+ struct clk clk;
+ struct udevice *vdda1v1;
+ struct udevice *vdda1v8;
+ struct stm32_usbphyc_phy {
+ struct udevice *vdd;
+ struct udevice *vbus;
+ bool init;
+ bool powered;
+ } phys[MAX_PHYS];
+};
+
+static void stm32_usbphyc_get_pll_params(u32 clk_rate,
+ struct pll_params *pll_params)
+{
+ unsigned long long fvco, ndiv, frac;
+
+ /*
+ * | FVCO = INFF*2*(NDIV + FRACT/2^16 ) when DITHER_DISABLE[1] = 1
+ * | FVCO = 2880MHz
+ * | NDIV = integer part of input bits to set the LDF
+ * | FRACT = fractional part of input bits to set the LDF
+ * => PLLNDIV = integer part of (FVCO / (INFF*2))
+ * => PLLFRACIN = fractional part of(FVCO / INFF*2) * 2^16
+ * <=> PLLFRACIN = ((FVCO / (INFF*2)) - PLLNDIV) * 2^16
+ */
+ fvco = (unsigned long long)PLL_FVCO * 1000000; /* In Hz */
+
+ ndiv = fvco;
+ do_div(ndiv, (clk_rate * 2));
+ pll_params->ndiv = (u8)ndiv;
+
+ frac = fvco * (1 << 16);
+ do_div(frac, (clk_rate * 2));
+ frac = frac - (ndiv * (1 << 16));
+ pll_params->frac = (u16)frac;
+}
+
+static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc)
+{
+ struct pll_params pll_params;
+ u32 clk_rate = clk_get_rate(&usbphyc->clk);
+ u32 usbphyc_pll;
+
+ if ((clk_rate < PLL_INFF_MIN_RATE) || (clk_rate > PLL_INFF_MAX_RATE)) {
+ log_debug("input clk freq (%dHz) out of range\n",
+ clk_rate);
+ return -EINVAL;
+ }
+
+ stm32_usbphyc_get_pll_params(clk_rate, &pll_params);
+
+ usbphyc_pll = PLLDITHEN1 | PLLDITHEN0 | PLLSTRBYP;
+ usbphyc_pll |= ((pll_params.ndiv << PLLNDIV_SHIFT) & PLLNDIV);
+
+ if (pll_params.frac) {
+ usbphyc_pll |= PLLFRACCTL;
+ usbphyc_pll |= ((pll_params.frac << PLLFRACIN_SHIFT)
+ & PLLFRACIN);
+ }
+
+ writel(usbphyc_pll, usbphyc->base + STM32_USBPHYC_PLL);
+
+ log_debug("input clk freq=%dHz, ndiv=%d, frac=%d\n",
+ clk_rate, pll_params.ndiv, pll_params.frac);
+
+ return 0;
+}
+
+static bool stm32_usbphyc_is_init(struct stm32_usbphyc *usbphyc)
+{
+ int i;
+
+ for (i = 0; i < MAX_PHYS; i++) {
+ if (usbphyc->phys[i].init)
+ return true;
+ }
+
+ return false;
+}
+
+static bool stm32_usbphyc_is_powered(struct stm32_usbphyc *usbphyc)
+{
+ int i;
+
+ for (i = 0; i < MAX_PHYS; i++) {
+ if (usbphyc->phys[i].powered)
+ return true;
+ }
+
+ return false;
+}
+
+static int stm32_usbphyc_phy_init(struct phy *phy)
+{
+ struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev);
+ struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id;
+ bool pllen = readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN ?
+ true : false;
+ int ret;
+
+ dev_dbg(phy->dev, "phy ID = %lu\n", phy->id);
+ /* Check if one phy port has already configured the pll */
+ if (pllen && stm32_usbphyc_is_init(usbphyc))
+ goto initialized;
+
+ if (usbphyc->vdda1v1) {
+ ret = regulator_set_enable(usbphyc->vdda1v1, true);
+ if (ret)
+ return ret;
+ }
+
+ if (usbphyc->vdda1v8) {
+ ret = regulator_set_enable(usbphyc->vdda1v8, true);
+ if (ret)
+ return ret;
+ }
+
+ if (pllen) {
+ clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN);
+ udelay(PLL_PWR_DOWN_TIME_US);
+ }
+
+ ret = stm32_usbphyc_pll_init(usbphyc);
+ if (ret)
+ return ret;
+
+ setbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN);
+
+ /* We must wait PLL_INIT_TIME_US before using PHY */
+ udelay(PLL_INIT_TIME_US);
+
+ if (!(readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN))
+ return -EIO;
+
+initialized:
+ usbphyc_phy->init = true;
+
+ return 0;
+}
+
+static int stm32_usbphyc_phy_exit(struct phy *phy)
+{
+ struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev);
+ struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id;
+ int ret;
+
+ dev_dbg(phy->dev, "phy ID = %lu\n", phy->id);
+ usbphyc_phy->init = false;
+
+ /* Check if other phy port requires pllen */
+ if (stm32_usbphyc_is_init(usbphyc))
+ return 0;
+
+ clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN);
+
+ /*
+ * We must wait PLL_PWR_DOWN_TIME_US before checking that PLLEN
+ * bit is still clear
+ */
+ udelay(PLL_PWR_DOWN_TIME_US);
+
+ if (readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN)
+ return -EIO;
+
+ if (usbphyc->vdda1v1) {
+ ret = regulator_set_enable(usbphyc->vdda1v1, false);
+ if (ret)
+ return ret;
+ }
+
+ if (usbphyc->vdda1v8) {
+ ret = regulator_set_enable(usbphyc->vdda1v8, false);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_usbphyc_phy_power_on(struct phy *phy)
+{
+ struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev);
+ struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id;
+ int ret;
+
+ dev_dbg(phy->dev, "phy ID = %lu\n", phy->id);
+ if (usbphyc_phy->vdd) {
+ ret = regulator_set_enable(usbphyc_phy->vdd, true);
+ if (ret)
+ return ret;
+ }
+ if (usbphyc_phy->vbus) {
+ ret = regulator_set_enable(usbphyc_phy->vbus, true);
+ if (ret)
+ return ret;
+ }
+
+ usbphyc_phy->powered = true;
+
+ return 0;
+}
+
+static int stm32_usbphyc_phy_power_off(struct phy *phy)
+{
+ struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev);
+ struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id;
+ int ret;
+
+ dev_dbg(phy->dev, "phy ID = %lu\n", phy->id);
+ usbphyc_phy->powered = false;
+
+ if (stm32_usbphyc_is_powered(usbphyc))
+ return 0;
+
+ if (usbphyc_phy->vbus) {
+ ret = regulator_set_enable(usbphyc_phy->vbus, false);
+ if (ret)
+ return ret;
+ }
+ if (usbphyc_phy->vdd) {
+ ret = regulator_set_enable_if_allowed(usbphyc_phy->vdd, false);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_usbphyc_get_regulator(ofnode node,
+ char *supply_name,
+ struct udevice **regulator)
+{
+ struct ofnode_phandle_args regulator_phandle;
+ int ret;
+
+ ret = ofnode_parse_phandle_with_args(node, supply_name,
+ NULL, 0, 0,
+ &regulator_phandle);
+ if (ret)
+ return ret;
+
+ ret = uclass_get_device_by_ofnode(UCLASS_REGULATOR,
+ regulator_phandle.node,
+ regulator);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int stm32_usbphyc_of_xlate(struct phy *phy,
+ struct ofnode_phandle_args *args)
+{
+ if (args->args_count < 1)
+ return -ENODEV;
+
+ if (args->args[0] >= MAX_PHYS)
+ return -ENODEV;
+
+ phy->id = args->args[0];
+
+ if ((phy->id == 0 && args->args_count != 1) ||
+ (phy->id == 1 && args->args_count != 2)) {
+ dev_err(phy->dev, "invalid number of cells for phy port%ld\n",
+ phy->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct phy_ops stm32_usbphyc_phy_ops = {
+ .init = stm32_usbphyc_phy_init,
+ .exit = stm32_usbphyc_phy_exit,
+ .power_on = stm32_usbphyc_phy_power_on,
+ .power_off = stm32_usbphyc_phy_power_off,
+ .of_xlate = stm32_usbphyc_of_xlate,
+};
+
+static int stm32_usbphyc_probe(struct udevice *dev)
+{
+ struct stm32_usbphyc *usbphyc = dev_get_priv(dev);
+ struct reset_ctl reset;
+ ofnode node;
+ int i, ret;
+
+ usbphyc->base = dev_read_addr(dev);
+ if (usbphyc->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /* Enable clock */
+ ret = clk_get_by_index(dev, 0, &usbphyc->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&usbphyc->clk);
+ if (ret)
+ return ret;
+
+ /* Reset */
+ ret = reset_get_by_index(dev, 0, &reset);
+ if (!ret) {
+ reset_assert(&reset);
+ udelay(2);
+ reset_deassert(&reset);
+ }
+
+ /* get usbphyc regulator */
+ ret = device_get_supply_regulator(dev, "vdda1v1-supply",
+ &usbphyc->vdda1v1);
+ if (ret) {
+ dev_err(dev, "Can't get vdda1v1-supply regulator\n");
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vdda1v8-supply",
+ &usbphyc->vdda1v8);
+ if (ret) {
+ dev_err(dev, "Can't get vdda1v8-supply regulator\n");
+ return ret;
+ }
+
+ /*
+ * parse all PHY subnodes in order to populate regulator associated
+ * to each PHY port
+ */
+ node = dev_read_first_subnode(dev);
+ for (i = 0; i < MAX_PHYS; i++) {
+ struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + i;
+
+ usbphyc_phy->init = false;
+ usbphyc_phy->powered = false;
+ ret = stm32_usbphyc_get_regulator(node, "phy-supply",
+ &usbphyc_phy->vdd);
+ if (ret) {
+ dev_err(dev, "Can't get phy-supply regulator\n");
+ return ret;
+ }
+
+ ret = stm32_usbphyc_get_regulator(node, "vbus-supply",
+ &usbphyc_phy->vbus);
+ if (ret)
+ usbphyc_phy->vbus = NULL;
+
+ node = dev_read_next_subnode(node);
+ }
+
+ /* Check if second port has to be used for host controller */
+ if (dev_read_bool(dev, "st,port2-switch-to-host"))
+ setbits_le32(usbphyc->base + STM32_USBPHYC_MISC, SWITHOST);
+
+ return 0;
+}
+
+static const struct udevice_id stm32_usbphyc_of_match[] = {
+ { .compatible = "st,stm32mp1-usbphyc", },
+ { },
+};
+
+U_BOOT_DRIVER(stm32_usb_phyc) = {
+ .name = "stm32-usbphyc",
+ .id = UCLASS_PHY,
+ .of_match = stm32_usbphyc_of_match,
+ .ops = &stm32_usbphyc_phy_ops,
+ .probe = stm32_usbphyc_probe,
+ .priv_auto = sizeof(struct stm32_usbphyc),
+};
diff --git a/roms/u-boot/drivers/phy/phy-ti-am654.c b/roms/u-boot/drivers/phy/phy-ti-am654.c
new file mode 100644
index 000000000..82010e7c9
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-ti-am654.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * PCIe SERDES driver for AM654x SoC
+ *
+ * Copyright (C) 2018 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dt-bindings/phy/phy.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <asm/arch/sys_proto.h>
+#include <power-domain.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#define CMU_R07C 0x7c
+#define CMU_MASTER_CDN_O BIT(24)
+
+#define COMLANE_R138 0xb38
+#define CONFIG_VERSION_REG_MASK GENMASK(23, 16)
+#define CONFIG_VERSION_REG_SHIFT 16
+#define VERSION 0x70
+
+#define COMLANE_R190 0xb90
+#define L1_MASTER_CDN_O BIT(9)
+
+#define COMLANE_R194 0xb94
+#define CMU_OK_I_0 BIT(19)
+
+#define SERDES_CTRL 0x1fd0
+#define POR_EN BIT(29)
+
+#define WIZ_LANEXCTL_STS 0x1fe0
+#define TX0_ENABLE_OVL BIT(31)
+#define TX0_ENABLE_MASK GENMASK(30, 29)
+#define TX0_ENABLE_SHIFT 29
+#define TX0_DISABLE_STATE 0x0
+#define TX0_SLEEP_STATE 0x1
+#define TX0_SNOOZE_STATE 0x2
+#define TX0_ENABLE_STATE 0x3
+#define RX0_ENABLE_OVL BIT(15)
+#define RX0_ENABLE_MASK GENMASK(14, 13)
+#define RX0_ENABLE_SHIFT 13
+#define RX0_DISABLE_STATE 0x0
+#define RX0_SLEEP_STATE 0x1
+#define RX0_SNOOZE_STATE 0x2
+#define RX0_ENABLE_STATE 0x3
+
+#define WIZ_PLL_CTRL 0x1ff4
+#define PLL_ENABLE_OVL BIT(31)
+#define PLL_ENABLE_MASK GENMASK(30, 29)
+#define PLL_ENABLE_SHIFT 29
+#define PLL_DISABLE_STATE 0x0
+#define PLL_SLEEP_STATE 0x1
+#define PLL_SNOOZE_STATE 0x2
+#define PLL_ENABLE_STATE 0x3
+#define PLL_OK BIT(28)
+
+#define PLL_LOCK_TIME 1000 /* in milliseconds */
+#define SLEEP_TIME 100 /* in microseconds */
+
+#define LANE_USB3 0x0
+#define LANE_PCIE0_LANE0 0x1
+
+#define LANE_PCIE1_LANE0 0x0
+#define LANE_PCIE0_LANE1 0x1
+
+#define SERDES_NUM_CLOCKS 3
+
+/* SERDES control MMR bit offsets */
+#define SERDES_CTL_LANE_FUNC_SEL_SHIFT 0
+#define SERDES_CTL_LANE_FUNC_SEL_MASK GENMASK(1, 0)
+#define SERDES_CTL_CLK_SEL_SHIFT 4
+#define SERDES_CTL_CLK_SEL_MASK GENMASK(7, 4)
+
+/**
+ * struct serdes_am654_mux_clk_data - clock controller information structure
+ */
+struct serdes_am654_mux_clk_data {
+ struct regmap *regmap;
+ struct clk_bulk parents;
+};
+
+static int serdes_am654_mux_clk_probe(struct udevice *dev)
+{
+ struct serdes_am654_mux_clk_data *data = dev_get_priv(dev);
+ struct udevice *syscon;
+ struct regmap *regmap;
+ int ret;
+
+ debug("%s(dev=%s)\n", __func__, dev->name);
+
+ if (!data)
+ return -ENOMEM;
+
+ ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ "ti,serdes-clk", &syscon);
+ if (ret) {
+ dev_err(dev, "unable to find syscon device\n");
+ return ret;
+ }
+
+ regmap = syscon_get_regmap(syscon);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "Fail to get Syscon regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ data->regmap = regmap;
+
+ ret = clk_get_bulk(dev, &data->parents);
+ if (ret) {
+ dev_err(dev, "Failed to obtain parent clocks\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mux_table[SERDES_NUM_CLOCKS][3] = {
+ /*
+ * The entries represent values for selecting between
+ * {left input, external reference clock, right input}
+ * Only one of Left Output or Right Output should be used since
+ * both left and right output clock uses the same bits and modifying
+ * one clock will impact the other.
+ */
+ { BIT(2), 0, BIT(0) }, /* Mux of CMU refclk */
+ { -1, BIT(3), BIT(1) }, /* Mux of Left Output */
+ { BIT(1), BIT(3) | BIT(1), -1 }, /* Mux of Right Output */
+};
+
+static int serdes_am654_mux_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct serdes_am654_mux_clk_data *data = dev_get_priv(clk->dev);
+ u32 val;
+ int i;
+
+ debug("%s(clk=%s, parent=%s)\n", __func__, clk->dev->name,
+ parent->dev->name);
+
+ /*
+ * Since we have the same device-tree node represent both the
+ * clock and serdes device, we have two devices associated with
+ * the serdes node. assigned-clocks for this node is processed twice,
+ * once for the clock device and another time for the serdes
+ * device. When it is processed for the clock device, it is before
+ * the probe for clock device has been called. We ignore this case
+ * and rely on assigned-clocks to be processed correctly for the
+ * serdes case.
+ */
+ if (!data->regmap)
+ return 0;
+
+ for (i = 0; i < data->parents.count; i++) {
+ if (clk_is_match(&data->parents.clks[i], parent))
+ break;
+ }
+
+ if (i >= data->parents.count)
+ return -EINVAL;
+
+ val = mux_table[clk->id][i];
+ val <<= SERDES_CTL_CLK_SEL_SHIFT;
+
+ regmap_update_bits(data->regmap, 0, SERDES_CTL_CLK_SEL_MASK, val);
+
+ return 0;
+}
+
+static struct clk_ops serdes_am654_mux_clk_ops = {
+ .set_parent = serdes_am654_mux_clk_set_parent,
+};
+
+U_BOOT_DRIVER(serdes_am654_mux_clk) = {
+ .name = "ti-serdes-am654-mux-clk",
+ .id = UCLASS_CLK,
+ .probe = serdes_am654_mux_clk_probe,
+ .priv_auto = sizeof(struct serdes_am654_mux_clk_data),
+ .ops = &serdes_am654_mux_clk_ops,
+};
+
+struct serdes_am654 {
+ struct regmap *regmap;
+ struct regmap *serdes_ctl;
+};
+
+static int serdes_am654_enable_pll(struct serdes_am654 *phy)
+{
+ u32 mask = PLL_ENABLE_OVL | PLL_ENABLE_MASK;
+ u32 val = PLL_ENABLE_OVL | (PLL_ENABLE_STATE << PLL_ENABLE_SHIFT);
+
+ regmap_update_bits(phy->regmap, WIZ_PLL_CTRL, mask, val);
+
+ return regmap_read_poll_timeout(phy->regmap, WIZ_PLL_CTRL, val,
+ val & PLL_OK, 1000, PLL_LOCK_TIME);
+}
+
+static void serdes_am654_disable_pll(struct serdes_am654 *phy)
+{
+ u32 mask = PLL_ENABLE_OVL | PLL_ENABLE_MASK;
+
+ regmap_update_bits(phy->regmap, WIZ_PLL_CTRL, mask, 0);
+}
+
+static int serdes_am654_enable_txrx(struct serdes_am654 *phy)
+{
+ u32 mask;
+ u32 val;
+
+ /* Enable TX */
+ mask = TX0_ENABLE_OVL | TX0_ENABLE_MASK;
+ val = TX0_ENABLE_OVL | (TX0_ENABLE_STATE << TX0_ENABLE_SHIFT);
+ regmap_update_bits(phy->regmap, WIZ_LANEXCTL_STS, mask, val);
+
+ /* Enable RX */
+ mask = RX0_ENABLE_OVL | RX0_ENABLE_MASK;
+ val = RX0_ENABLE_OVL | (RX0_ENABLE_STATE << RX0_ENABLE_SHIFT);
+ regmap_update_bits(phy->regmap, WIZ_LANEXCTL_STS, mask, val);
+
+ return 0;
+}
+
+static int serdes_am654_disable_txrx(struct serdes_am654 *phy)
+{
+ u32 mask;
+
+ /* Disable TX */
+ mask = TX0_ENABLE_OVL | TX0_ENABLE_MASK;
+ regmap_update_bits(phy->regmap, WIZ_LANEXCTL_STS, mask, 0);
+
+ /* Disable RX */
+ mask = RX0_ENABLE_OVL | RX0_ENABLE_MASK;
+ regmap_update_bits(phy->regmap, WIZ_LANEXCTL_STS, mask, 0);
+
+ return 0;
+}
+
+static int serdes_am654_power_on(struct phy *x)
+{
+ struct serdes_am654 *phy = dev_get_priv(x->dev);
+ int ret;
+ u32 val;
+
+ ret = serdes_am654_enable_pll(phy);
+ if (ret) {
+ dev_err(x->dev, "Failed to enable PLL\n");
+ return ret;
+ }
+
+ ret = serdes_am654_enable_txrx(phy);
+ if (ret) {
+ dev_err(x->dev, "Failed to enable TX RX\n");
+ return ret;
+ }
+
+ return regmap_read_poll_timeout(phy->regmap, COMLANE_R194, val,
+ val & CMU_OK_I_0, SLEEP_TIME,
+ PLL_LOCK_TIME);
+}
+
+static int serdes_am654_power_off(struct phy *x)
+{
+ struct serdes_am654 *phy = dev_get_priv(x->dev);
+
+ serdes_am654_disable_txrx(phy);
+ serdes_am654_disable_pll(phy);
+
+ return 0;
+}
+
+static int serdes_am654_init(struct phy *x)
+{
+ struct serdes_am654 *phy = dev_get_priv(x->dev);
+ u32 mask;
+ u32 val;
+
+ mask = CONFIG_VERSION_REG_MASK;
+ val = VERSION << CONFIG_VERSION_REG_SHIFT;
+ regmap_update_bits(phy->regmap, COMLANE_R138, mask, val);
+
+ val = CMU_MASTER_CDN_O;
+ regmap_update_bits(phy->regmap, CMU_R07C, val, val);
+
+ val = L1_MASTER_CDN_O;
+ regmap_update_bits(phy->regmap, COMLANE_R190, val, val);
+
+ return 0;
+}
+
+static int serdes_am654_reset(struct phy *x)
+{
+ struct serdes_am654 *phy = dev_get_priv(x->dev);
+ u32 val;
+
+ val = POR_EN;
+ regmap_update_bits(phy->regmap, SERDES_CTRL, val, val);
+ mdelay(1);
+ regmap_update_bits(phy->regmap, SERDES_CTRL, val, 0);
+
+ return 0;
+}
+
+static int serdes_am654_of_xlate(struct phy *x,
+ struct ofnode_phandle_args *args)
+{
+ struct serdes_am654 *phy = dev_get_priv(x->dev);
+
+ if (args->args_count != 2) {
+ dev_err(x->dev, "Invalid DT PHY argument count: %d\n",
+ args->args_count);
+ return -EINVAL;
+ }
+
+ if (args->args[0] != PHY_TYPE_PCIE) {
+ dev_err(x->dev, "Unrecognized PHY type: %d\n",
+ args->args[0]);
+ return -EINVAL;
+ }
+
+ x->id = args->args[0] | (args->args[1] << 16);
+
+ /* Setup mux mode using second argument */
+ regmap_update_bits(phy->serdes_ctl, 0, SERDES_CTL_LANE_FUNC_SEL_MASK,
+ args->args[1]);
+
+ return 0;
+}
+
+static int serdes_am654_bind(struct udevice *dev)
+{
+ int ret;
+
+ ret = device_bind_driver_to_node(dev->parent,
+ "ti-serdes-am654-mux-clk",
+ dev_read_name(dev), dev_ofnode(dev),
+ NULL);
+ if (ret) {
+ dev_err(dev, "%s: not able to bind clock driver\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int serdes_am654_probe(struct udevice *dev)
+{
+ struct serdes_am654 *phy = dev_get_priv(dev);
+ struct power_domain serdes_pwrdmn;
+ struct regmap *serdes_ctl;
+ struct regmap *map;
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &map);
+ if (ret)
+ return ret;
+
+ phy->regmap = map;
+
+ serdes_ctl = syscon_regmap_lookup_by_phandle(dev, "ti,serdes-clk");
+ if (IS_ERR(serdes_ctl)) {
+ dev_err(dev, "unable to find syscon device\n");
+ return PTR_ERR(serdes_ctl);
+ }
+
+ phy->serdes_ctl = serdes_ctl;
+
+ ret = power_domain_get_by_index(dev, &serdes_pwrdmn, 0);
+ if (ret) {
+ dev_err(dev, "failed to get power domain\n");
+ return ret;
+ }
+
+ ret = power_domain_on(&serdes_pwrdmn);
+ if (ret) {
+ dev_err(dev, "Power domain on failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id serdes_am654_phy_ids[] = {
+ {
+ .compatible = "ti,phy-am654-serdes",
+ },
+};
+
+static const struct phy_ops serdes_am654_phy_ops = {
+ .reset = serdes_am654_reset,
+ .init = serdes_am654_init,
+ .power_on = serdes_am654_power_on,
+ .power_off = serdes_am654_power_off,
+ .of_xlate = serdes_am654_of_xlate,
+};
+
+U_BOOT_DRIVER(am654_serdes_phy) = {
+ .name = "am654_serdes_phy",
+ .id = UCLASS_PHY,
+ .of_match = serdes_am654_phy_ids,
+ .bind = serdes_am654_bind,
+ .ops = &serdes_am654_phy_ops,
+ .probe = serdes_am654_probe,
+ .priv_auto = sizeof(struct serdes_am654),
+};
diff --git a/roms/u-boot/drivers/phy/phy-uclass.c b/roms/u-boot/drivers/phy/phy-uclass.c
new file mode 100644
index 000000000..43ffbcee0
--- /dev/null
+++ b/roms/u-boot/drivers/phy/phy-uclass.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <generic-phy.h>
+
+static inline struct phy_ops *phy_dev_ops(struct udevice *dev)
+{
+ return (struct phy_ops *)dev->driver->ops;
+}
+
+static int generic_phy_xlate_offs_flags(struct phy *phy,
+ struct ofnode_phandle_args *args)
+{
+ debug("%s(phy=%p)\n", __func__, phy);
+
+ if (args->args_count > 1) {
+ debug("Invaild args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ if (args->args_count)
+ phy->id = args->args[0];
+ else
+ phy->id = 0;
+
+ return 0;
+}
+
+int generic_phy_get_by_index_nodev(ofnode node, int index, struct phy *phy)
+{
+ struct ofnode_phandle_args args;
+ struct phy_ops *ops;
+ struct udevice *phydev;
+ int i, ret;
+
+ debug("%s(node=%s, index=%d, phy=%p)\n",
+ __func__, ofnode_get_name(node), index, phy);
+
+ assert(phy);
+ phy->dev = NULL;
+ ret = ofnode_parse_phandle_with_args(node, "phys", "#phy-cells", 0,
+ index, &args);
+ if (ret) {
+ debug("%s: dev_read_phandle_with_args failed: err=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_ofnode(UCLASS_PHY, args.node, &phydev);
+ if (ret) {
+ debug("%s: uclass_get_device_by_ofnode failed: err=%d\n",
+ __func__, ret);
+
+ /* Check if args.node's parent is a PHY provider */
+ ret = uclass_get_device_by_ofnode(UCLASS_PHY,
+ ofnode_get_parent(args.node),
+ &phydev);
+ if (ret)
+ return ret;
+
+ /* insert phy idx at first position into args array */
+ for (i = args.args_count; i >= 1 ; i--)
+ args.args[i] = args.args[i - 1];
+
+ args.args_count++;
+ args.args[0] = ofnode_read_u32_default(args.node, "reg", -1);
+ }
+
+ phy->dev = phydev;
+
+ ops = phy_dev_ops(phydev);
+
+ if (ops->of_xlate)
+ ret = ops->of_xlate(phy, &args);
+ else
+ ret = generic_phy_xlate_offs_flags(phy, &args);
+ if (ret) {
+ debug("of_xlate() failed: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ return ret;
+}
+
+int generic_phy_get_by_index(struct udevice *dev, int index,
+ struct phy *phy)
+{
+ return generic_phy_get_by_index_nodev(dev_ofnode(dev), index, phy);
+}
+
+int generic_phy_get_by_name(struct udevice *dev, const char *phy_name,
+ struct phy *phy)
+{
+ int index;
+
+ debug("%s(dev=%p, name=%s, phy=%p)\n", __func__, dev, phy_name, phy);
+
+ index = dev_read_stringlist_search(dev, "phy-names", phy_name);
+ if (index < 0) {
+ debug("dev_read_stringlist_search() failed: %d\n", index);
+ return index;
+ }
+
+ return generic_phy_get_by_index(dev, index, phy);
+}
+
+int generic_phy_init(struct phy *phy)
+{
+ struct phy_ops const *ops;
+ int ret;
+
+ if (!generic_phy_valid(phy))
+ return 0;
+ ops = phy_dev_ops(phy->dev);
+ if (!ops->init)
+ return 0;
+ ret = ops->init(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to init %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
+}
+
+int generic_phy_reset(struct phy *phy)
+{
+ struct phy_ops const *ops;
+ int ret;
+
+ if (!generic_phy_valid(phy))
+ return 0;
+ ops = phy_dev_ops(phy->dev);
+ if (!ops->reset)
+ return 0;
+ ret = ops->reset(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to reset %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
+}
+
+int generic_phy_exit(struct phy *phy)
+{
+ struct phy_ops const *ops;
+ int ret;
+
+ if (!generic_phy_valid(phy))
+ return 0;
+ ops = phy_dev_ops(phy->dev);
+ if (!ops->exit)
+ return 0;
+ ret = ops->exit(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
+}
+
+int generic_phy_power_on(struct phy *phy)
+{
+ struct phy_ops const *ops;
+ int ret;
+
+ if (!generic_phy_valid(phy))
+ return 0;
+ ops = phy_dev_ops(phy->dev);
+ if (!ops->power_on)
+ return 0;
+ ret = ops->power_on(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
+}
+
+int generic_phy_power_off(struct phy *phy)
+{
+ struct phy_ops const *ops;
+ int ret;
+
+ if (!generic_phy_valid(phy))
+ return 0;
+ ops = phy_dev_ops(phy->dev);
+ if (!ops->power_off)
+ return 0;
+ ret = ops->power_off(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
+}
+
+int generic_phy_configure(struct phy *phy, void *params)
+{
+ struct phy_ops const *ops;
+
+ if (!generic_phy_valid(phy))
+ return 0;
+ ops = phy_dev_ops(phy->dev);
+
+ return ops->configure ? ops->configure(phy, params) : 0;
+}
+
+int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk)
+{
+ int i, ret, count;
+
+ bulk->count = 0;
+
+ /* Return if no phy declared */
+ if (!dev_read_prop(dev, "phys", NULL))
+ return 0;
+
+ count = dev_count_phandle_with_args(dev, "phys", "#phy-cells", 0);
+ if (count < 1)
+ return count;
+
+ bulk->phys = devm_kcalloc(dev, count, sizeof(struct phy), GFP_KERNEL);
+ if (!bulk->phys)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++) {
+ ret = generic_phy_get_by_index(dev, i, &bulk->phys[i]);
+ if (ret) {
+ pr_err("Failed to get PHY%d for %s\n", i, dev->name);
+ return ret;
+ }
+ bulk->count++;
+ }
+
+ return 0;
+}
+
+int generic_phy_init_bulk(struct phy_bulk *bulk)
+{
+ struct phy *phys = bulk->phys;
+ int i, ret;
+
+ for (i = 0; i < bulk->count; i++) {
+ ret = generic_phy_init(&phys[i]);
+ if (ret) {
+ pr_err("Can't init PHY%d\n", i);
+ goto phys_init_err;
+ }
+ }
+
+ return 0;
+
+phys_init_err:
+ for (; i > 0; i--)
+ generic_phy_exit(&phys[i - 1]);
+
+ return ret;
+}
+
+int generic_phy_exit_bulk(struct phy_bulk *bulk)
+{
+ struct phy *phys = bulk->phys;
+ int i, ret = 0;
+
+ for (i = 0; i < bulk->count; i++)
+ ret |= generic_phy_exit(&phys[i]);
+
+ return ret;
+}
+
+int generic_phy_power_on_bulk(struct phy_bulk *bulk)
+{
+ struct phy *phys = bulk->phys;
+ int i, ret;
+
+ for (i = 0; i < bulk->count; i++) {
+ ret = generic_phy_power_on(&phys[i]);
+ if (ret) {
+ pr_err("Can't power on PHY%d\n", i);
+ goto phys_poweron_err;
+ }
+ }
+
+ return 0;
+
+phys_poweron_err:
+ for (; i > 0; i--)
+ generic_phy_power_off(&phys[i - 1]);
+
+ return ret;
+}
+
+int generic_phy_power_off_bulk(struct phy_bulk *bulk)
+{
+ struct phy *phys = bulk->phys;
+ int i, ret = 0;
+
+ for (i = 0; i < bulk->count; i++)
+ ret |= generic_phy_power_off(&phys[i]);
+
+ return ret;
+}
+
+UCLASS_DRIVER(phy) = {
+ .id = UCLASS_PHY,
+ .name = "phy",
+};
diff --git a/roms/u-boot/drivers/phy/rockchip/Kconfig b/roms/u-boot/drivers/phy/rockchip/Kconfig
new file mode 100644
index 000000000..e477a6cd9
--- /dev/null
+++ b/roms/u-boot/drivers/phy/rockchip/Kconfig
@@ -0,0 +1,37 @@
+#
+# Phy drivers for Rockchip platforms
+#
+
+menu "Rockchip PHY driver"
+
+config PHY_ROCKCHIP_INNO_USB2
+ bool "Rockchip INNO USB2PHY Driver"
+ depends on ARCH_ROCKCHIP
+ select PHY
+ help
+ Support for Rockchip USB2.0 PHY with Innosilicon IP block.
+
+config PHY_ROCKCHIP_PCIE
+ bool "Rockchip PCIe PHY Driver"
+ depends on ARCH_ROCKCHIP
+ select PHY
+ help
+ Enable this to support the Rockchip PCIe PHY.
+
+config PHY_ROCKCHIP_SNPS_PCIE3
+ bool "Rockchip Snps PCIe3 PHY Driver"
+ depends on PHY && ARCH_ROCKCHIP
+ help
+ Support for Rockchip PCIe3 PHY with Synopsys IP block.
+ It could support PCIe Gen3 single root complex, and could
+ also be able splited into multiple combinations of lanes.
+
+
+config PHY_ROCKCHIP_TYPEC
+ bool "Rockchip TYPEC PHY Driver"
+ depends on ARCH_ROCKCHIP
+ select PHY
+ help
+ Enable this to support the Rockchip USB TYPEC PHY.
+
+endmenu
diff --git a/roms/u-boot/drivers/phy/rockchip/Makefile b/roms/u-boot/drivers/phy/rockchip/Makefile
new file mode 100644
index 000000000..f6ad3bf59
--- /dev/null
+++ b/roms/u-boot/drivers/phy/rockchip/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2020 Amarula Solutions(India)
+#
+
+obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
+obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
+obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o
+obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
diff --git a/roms/u-boot/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/roms/u-boot/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
new file mode 100644
index 000000000..62b8ba3a4
--- /dev/null
+++ b/roms/u-boot/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Rockchip USB2.0 PHY with Innosilicon IP block driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
+ * Copyright (C) 2020 Amarula Solutions(India)
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+#include <asm/arch-rockchip/clock.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define usleep_range(a, b) udelay((b))
+#define BIT_WRITEABLE_SHIFT 16
+
+enum rockchip_usb2phy_port_id {
+ USB2PHY_PORT_OTG,
+ USB2PHY_PORT_HOST,
+ USB2PHY_NUM_PORTS,
+};
+
+struct usb2phy_reg {
+ unsigned int offset;
+ unsigned int bitend;
+ unsigned int bitstart;
+ unsigned int disable;
+ unsigned int enable;
+};
+
+struct rockchip_usb2phy_port_cfg {
+ struct usb2phy_reg phy_sus;
+ struct usb2phy_reg bvalid_det_en;
+ struct usb2phy_reg bvalid_det_st;
+ struct usb2phy_reg bvalid_det_clr;
+ struct usb2phy_reg ls_det_en;
+ struct usb2phy_reg ls_det_st;
+ struct usb2phy_reg ls_det_clr;
+ struct usb2phy_reg utmi_avalid;
+ struct usb2phy_reg utmi_bvalid;
+ struct usb2phy_reg utmi_ls;
+ struct usb2phy_reg utmi_hstdet;
+};
+
+struct rockchip_usb2phy_cfg {
+ unsigned int reg;
+ const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS];
+};
+
+struct rockchip_usb2phy {
+ void *reg_base;
+ struct clk phyclk;
+ const struct rockchip_usb2phy_cfg *phy_cfg;
+};
+
+static inline int property_enable(void *reg_base,
+ const struct usb2phy_reg *reg, bool en)
+{
+ unsigned int val, mask, tmp;
+
+ tmp = en ? reg->enable : reg->disable;
+ mask = GENMASK(reg->bitend, reg->bitstart);
+ val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
+
+ return writel(val, reg_base + reg->offset);
+}
+
+static const
+struct rockchip_usb2phy_port_cfg *us2phy_get_port(struct phy *phy)
+{
+ struct udevice *parent = dev_get_parent(phy->dev);
+ struct rockchip_usb2phy *priv = dev_get_priv(parent);
+ const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg;
+
+ return &phy_cfg->port_cfgs[phy->id];
+}
+
+static int rockchip_usb2phy_power_on(struct phy *phy)
+{
+ struct udevice *parent = dev_get_parent(phy->dev);
+ struct rockchip_usb2phy *priv = dev_get_priv(parent);
+ const struct rockchip_usb2phy_port_cfg *port_cfg = us2phy_get_port(phy);
+
+ property_enable(priv->reg_base, &port_cfg->phy_sus, false);
+
+ /* waiting for the utmi_clk to become stable */
+ usleep_range(1500, 2000);
+
+ return 0;
+}
+
+static int rockchip_usb2phy_power_off(struct phy *phy)
+{
+ struct udevice *parent = dev_get_parent(phy->dev);
+ struct rockchip_usb2phy *priv = dev_get_priv(parent);
+ const struct rockchip_usb2phy_port_cfg *port_cfg = us2phy_get_port(phy);
+
+ property_enable(priv->reg_base, &port_cfg->phy_sus, true);
+
+ return 0;
+}
+
+static int rockchip_usb2phy_init(struct phy *phy)
+{
+ struct udevice *parent = dev_get_parent(phy->dev);
+ struct rockchip_usb2phy *priv = dev_get_priv(parent);
+ const struct rockchip_usb2phy_port_cfg *port_cfg = us2phy_get_port(phy);
+ int ret;
+
+ ret = clk_enable(&priv->phyclk);
+ if (ret) {
+ dev_err(phy->dev, "failed to enable phyclk (ret=%d)\n", ret);
+ return ret;
+ }
+
+ if (phy->id == USB2PHY_PORT_OTG) {
+ property_enable(priv->reg_base, &port_cfg->bvalid_det_clr, true);
+ property_enable(priv->reg_base, &port_cfg->bvalid_det_en, true);
+ } else if (phy->id == USB2PHY_PORT_HOST) {
+ property_enable(priv->reg_base, &port_cfg->bvalid_det_clr, true);
+ property_enable(priv->reg_base, &port_cfg->bvalid_det_en, true);
+ }
+
+ return 0;
+}
+
+static int rockchip_usb2phy_exit(struct phy *phy)
+{
+ struct udevice *parent = dev_get_parent(phy->dev);
+ struct rockchip_usb2phy *priv = dev_get_priv(parent);
+
+ clk_disable(&priv->phyclk);
+
+ return 0;
+}
+
+static int rockchip_usb2phy_of_xlate(struct phy *phy,
+ struct ofnode_phandle_args *args)
+{
+ const char *name = phy->dev->name;
+
+ if (!strcasecmp(name, "host-port"))
+ phy->id = USB2PHY_PORT_HOST;
+ else if (!strcasecmp(name, "otg-port"))
+ phy->id = USB2PHY_PORT_OTG;
+ else
+ dev_err(phy->dev, "improper %s device\n", name);
+
+ return 0;
+}
+
+static struct phy_ops rockchip_usb2phy_ops = {
+ .init = rockchip_usb2phy_init,
+ .exit = rockchip_usb2phy_exit,
+ .power_on = rockchip_usb2phy_power_on,
+ .power_off = rockchip_usb2phy_power_off,
+ .of_xlate = rockchip_usb2phy_of_xlate,
+};
+
+static int rockchip_usb2phy_probe(struct udevice *dev)
+{
+ struct rockchip_usb2phy *priv = dev_get_priv(dev);
+ const struct rockchip_usb2phy_cfg *phy_cfgs;
+ unsigned int reg;
+ int index, ret;
+
+ priv->reg_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ if (IS_ERR(priv->reg_base))
+ return PTR_ERR(priv->reg_base);
+
+ ret = ofnode_read_u32(dev_ofnode(dev), "reg", &reg);
+ if (ret) {
+ dev_err(dev, "failed to read reg property (ret = %d)\n", ret);
+ return ret;
+ }
+
+ phy_cfgs = (const struct rockchip_usb2phy_cfg *)
+ dev_get_driver_data(dev);
+ if (!phy_cfgs)
+ return -EINVAL;
+
+ /* find out a proper config which can be matched with dt. */
+ index = 0;
+ while (phy_cfgs[index].reg) {
+ if (phy_cfgs[index].reg == reg) {
+ priv->phy_cfg = &phy_cfgs[index];
+ break;
+ }
+
+ ++index;
+ }
+
+ if (!priv->phy_cfg) {
+ dev_err(dev, "failed find proper phy-cfg\n");
+ return -EINVAL;
+ }
+
+ ret = clk_get_by_name(dev, "phyclk", &priv->phyclk);
+ if (ret) {
+ dev_err(dev, "failed to get the phyclk (ret=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rockchip_usb2phy_bind(struct udevice *dev)
+{
+ struct udevice *usb2phy_dev;
+ ofnode node;
+ const char *name;
+ int ret = 0;
+
+ dev_for_each_subnode(node, dev) {
+ if (!ofnode_valid(node)) {
+ dev_info(dev, "subnode %s not found\n", dev->name);
+ return -ENXIO;
+ }
+
+ name = ofnode_get_name(node);
+ dev_dbg(dev, "subnode %s\n", name);
+
+ ret = device_bind_driver_to_node(dev, "rockchip_usb2phy_port",
+ name, node, &usb2phy_dev);
+ if (ret) {
+ dev_err(dev,
+ "'%s' cannot bind 'rockchip_usb2phy_port'\n", name);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
+ {
+ .reg = 0xe450,
+ .port_cfgs = {
+ [USB2PHY_PORT_OTG] = {
+ .phy_sus = { 0xe454, 1, 0, 2, 1 },
+ .bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 },
+ .bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 },
+ .bvalid_det_clr = { 0xe3d0, 3, 3, 0, 1 },
+ .utmi_avalid = { 0xe2ac, 7, 7, 0, 1 },
+ .utmi_bvalid = { 0xe2ac, 12, 12, 0, 1 },
+ },
+ [USB2PHY_PORT_HOST] = {
+ .phy_sus = { 0xe458, 1, 0, 0x2, 0x1 },
+ .ls_det_en = { 0xe3c0, 6, 6, 0, 1 },
+ .ls_det_st = { 0xe3e0, 6, 6, 0, 1 },
+ .ls_det_clr = { 0xe3d0, 6, 6, 0, 1 },
+ .utmi_ls = { 0xe2ac, 22, 21, 0, 1 },
+ .utmi_hstdet = { 0xe2ac, 23, 23, 0, 1 }
+ }
+ },
+ },
+ {
+ .reg = 0xe460,
+ .port_cfgs = {
+ [USB2PHY_PORT_OTG] = {
+ .phy_sus = { 0xe464, 1, 0, 2, 1 },
+ .bvalid_det_en = { 0xe3c0, 8, 8, 0, 1 },
+ .bvalid_det_st = { 0xe3e0, 8, 8, 0, 1 },
+ .bvalid_det_clr = { 0xe3d0, 8, 8, 0, 1 },
+ .utmi_avalid = { 0xe2ac, 10, 10, 0, 1 },
+ .utmi_bvalid = { 0xe2ac, 16, 16, 0, 1 },
+ },
+ [USB2PHY_PORT_HOST] = {
+ .phy_sus = { 0xe468, 1, 0, 0x2, 0x1 },
+ .ls_det_en = { 0xe3c0, 11, 11, 0, 1 },
+ .ls_det_st = { 0xe3e0, 11, 11, 0, 1 },
+ .ls_det_clr = { 0xe3d0, 11, 11, 0, 1 },
+ .utmi_ls = { 0xe2ac, 26, 25, 0, 1 },
+ .utmi_hstdet = { 0xe2ac, 27, 27, 0, 1 }
+ }
+ },
+ },
+ { /* sentinel */ }
+};
+
+static const struct udevice_id rockchip_usb2phy_ids[] = {
+ {
+ .compatible = "rockchip,rk3399-usb2phy",
+ .data = (ulong)&rk3399_usb2phy_cfgs,
+ },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(rockchip_usb2phy_port) = {
+ .name = "rockchip_usb2phy_port",
+ .id = UCLASS_PHY,
+ .ops = &rockchip_usb2phy_ops,
+};
+
+U_BOOT_DRIVER(rockchip_usb2phy) = {
+ .name = "rockchip_usb2phy",
+ .id = UCLASS_PHY,
+ .of_match = rockchip_usb2phy_ids,
+ .probe = rockchip_usb2phy_probe,
+ .bind = rockchip_usb2phy_bind,
+ .priv_auto = sizeof(struct rockchip_usb2phy),
+};
diff --git a/roms/u-boot/drivers/phy/rockchip/phy-rockchip-pcie.c b/roms/u-boot/drivers/phy/rockchip/phy-rockchip-pcie.c
new file mode 100644
index 000000000..44ca4bc79
--- /dev/null
+++ b/roms/u-boot/drivers/phy/rockchip/phy-rockchip-pcie.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: (GPL-2.0-only)
+/*
+ * Rockchip PCIe PHY driver
+ *
+ * Copyright (C) 2020 Amarula Solutions(India)
+ * Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+#include <asm/arch-rockchip/clock.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * The higher 16-bit of this register is used for write protection
+ * only if BIT(x + 16) set to 1 the BIT(x) can be written.
+ */
+#define HIWORD_UPDATE(val, mask, shift) \
+ ((val) << (shift) | (mask) << ((shift) + 16))
+
+#define PHY_MAX_LANE_NUM 4
+#define PHY_CFG_DATA_SHIFT 7
+#define PHY_CFG_ADDR_SHIFT 1
+#define PHY_CFG_DATA_MASK 0xf
+#define PHY_CFG_ADDR_MASK 0x3f
+#define PHY_CFG_RD_MASK 0x3ff
+#define PHY_CFG_WR_ENABLE 1
+#define PHY_CFG_WR_DISABLE 1
+#define PHY_CFG_WR_SHIFT 0
+#define PHY_CFG_WR_MASK 1
+#define PHY_CFG_PLL_LOCK 0x10
+#define PHY_CFG_CLK_TEST 0x10
+#define PHY_CFG_CLK_SCC 0x12
+#define PHY_CFG_SEPE_RATE BIT(3)
+#define PHY_CFG_PLL_100M BIT(3)
+#define PHY_PLL_LOCKED BIT(9)
+#define PHY_PLL_OUTPUT BIT(10)
+#define PHY_LANE_RX_DET_SHIFT 11
+#define PHY_LANE_RX_DET_TH 0x1
+#define PHY_LANE_IDLE_OFF 0x1
+#define PHY_LANE_IDLE_MASK 0x1
+#define PHY_LANE_IDLE_A_SHIFT 3
+#define PHY_LANE_IDLE_B_SHIFT 4
+#define PHY_LANE_IDLE_C_SHIFT 5
+#define PHY_LANE_IDLE_D_SHIFT 6
+
+struct rockchip_pcie_phy_data {
+ unsigned int pcie_conf;
+ unsigned int pcie_status;
+ unsigned int pcie_laneoff;
+};
+
+struct rockchip_pcie_phy {
+ void *reg_base;
+ struct clk refclk;
+ struct reset_ctl phy_rst;
+ const struct rockchip_pcie_phy_data *data;
+};
+
+static void phy_wr_cfg(struct rockchip_pcie_phy *priv, u32 addr, u32 data)
+{
+ u32 reg;
+
+ reg = HIWORD_UPDATE(data, PHY_CFG_DATA_MASK, PHY_CFG_DATA_SHIFT);
+ reg |= HIWORD_UPDATE(addr, PHY_CFG_ADDR_MASK, PHY_CFG_ADDR_SHIFT);
+ writel(reg, priv->reg_base + priv->data->pcie_conf);
+
+ udelay(1);
+
+ reg = HIWORD_UPDATE(PHY_CFG_WR_ENABLE,
+ PHY_CFG_WR_MASK,
+ PHY_CFG_WR_SHIFT);
+ writel(reg, priv->reg_base + priv->data->pcie_conf);
+
+ udelay(1);
+
+ reg = HIWORD_UPDATE(PHY_CFG_WR_DISABLE,
+ PHY_CFG_WR_MASK,
+ PHY_CFG_WR_SHIFT);
+ writel(reg, priv->reg_base + priv->data->pcie_conf);
+}
+
+static int rockchip_pcie_phy_power_on(struct phy *phy)
+{
+ struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev);
+ int ret = 0;
+ u32 reg, status;
+
+ ret = reset_deassert(&priv->phy_rst);
+ if (ret) {
+ dev_err(phy->dev, "failed to assert phy reset\n");
+ return ret;
+ }
+
+ reg = HIWORD_UPDATE(PHY_CFG_PLL_LOCK,
+ PHY_CFG_ADDR_MASK,
+ PHY_CFG_ADDR_SHIFT);
+ writel(reg, priv->reg_base + priv->data->pcie_conf);
+
+ reg = HIWORD_UPDATE(!PHY_LANE_IDLE_OFF,
+ PHY_LANE_IDLE_MASK,
+ PHY_LANE_IDLE_A_SHIFT);
+ writel(reg, priv->reg_base + priv->data->pcie_laneoff);
+
+ ret = -EINVAL;
+ ret = readl_poll_sleep_timeout(priv->reg_base + priv->data->pcie_status,
+ status,
+ status & PHY_PLL_LOCKED,
+ 20 * 1000,
+ 50);
+ if (ret) {
+ dev_err(phy->dev, "pll lock timeout!\n");
+ goto err_pll_lock;
+ }
+
+ phy_wr_cfg(priv, PHY_CFG_CLK_TEST, PHY_CFG_SEPE_RATE);
+ phy_wr_cfg(priv, PHY_CFG_CLK_SCC, PHY_CFG_PLL_100M);
+
+ ret = -ETIMEDOUT;
+ ret = readl_poll_sleep_timeout(priv->reg_base + priv->data->pcie_status,
+ status,
+ !(status & PHY_PLL_OUTPUT),
+ 20 * 1000,
+ 50);
+ if (ret) {
+ dev_err(phy->dev, "pll output enable timeout!\n");
+ goto err_pll_lock;
+ }
+
+ reg = HIWORD_UPDATE(PHY_CFG_PLL_LOCK,
+ PHY_CFG_ADDR_MASK,
+ PHY_CFG_ADDR_SHIFT);
+ writel(reg, priv->reg_base + priv->data->pcie_conf);
+
+ ret = -EINVAL;
+ ret = readl_poll_sleep_timeout(priv->reg_base + priv->data->pcie_status,
+ status,
+ status & PHY_PLL_LOCKED,
+ 20 * 1000,
+ 50);
+ if (ret) {
+ dev_err(phy->dev, "pll relock timeout!\n");
+ goto err_pll_lock;
+ }
+
+ return 0;
+
+err_pll_lock:
+ reset_assert(&priv->phy_rst);
+ return ret;
+}
+
+static int rockchip_pcie_phy_power_off(struct phy *phy)
+{
+ struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev);
+ int ret;
+ u32 reg;
+
+ reg = HIWORD_UPDATE(PHY_LANE_IDLE_OFF,
+ PHY_LANE_IDLE_MASK,
+ PHY_LANE_IDLE_A_SHIFT);
+ writel(reg, priv->reg_base + priv->data->pcie_laneoff);
+
+ ret = reset_assert(&priv->phy_rst);
+ if (ret) {
+ dev_err(phy->dev, "failed to assert phy reset\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rockchip_pcie_phy_init(struct phy *phy)
+{
+ struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev);
+ int ret;
+
+ ret = clk_enable(&priv->refclk);
+ if (ret) {
+ dev_err(phy->dev, "failed to enable refclk clock\n");
+ return ret;
+ }
+
+ ret = reset_assert(&priv->phy_rst);
+ if (ret) {
+ dev_err(phy->dev, "failed to assert phy reset\n");
+ goto err_reset;
+ }
+
+ return 0;
+
+err_reset:
+ clk_disable(&priv->refclk);
+ return ret;
+}
+
+static int rockchip_pcie_phy_exit(struct phy *phy)
+{
+ struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev);
+
+ clk_disable(&priv->refclk);
+
+ return 0;
+}
+
+static struct phy_ops rockchip_pcie_phy_ops = {
+ .init = rockchip_pcie_phy_init,
+ .power_on = rockchip_pcie_phy_power_on,
+ .power_off = rockchip_pcie_phy_power_off,
+ .exit = rockchip_pcie_phy_exit,
+};
+
+static int rockchip_pcie_phy_probe(struct udevice *dev)
+{
+ struct rockchip_pcie_phy *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->data = (const struct rockchip_pcie_phy_data *)
+ dev_get_driver_data(dev);
+ if (!priv->data)
+ return -EINVAL;
+
+ priv->reg_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
+ ret = clk_get_by_name(dev, "refclk", &priv->refclk);
+ if (ret) {
+ dev_err(dev, "failed to get refclk clock phandle\n");
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "phy", &priv->phy_rst);
+ if (ret) {
+ dev_err(dev, "failed to get phy reset phandle\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct rockchip_pcie_phy_data rk3399_pcie_data = {
+ .pcie_conf = 0xe220,
+ .pcie_status = 0xe2a4,
+ .pcie_laneoff = 0xe214,
+};
+
+static const struct udevice_id rockchip_pcie_phy_ids[] = {
+ {
+ .compatible = "rockchip,rk3399-pcie-phy",
+ .data = (ulong)&rk3399_pcie_data,
+ },
+ { /* sentile */ }
+};
+
+U_BOOT_DRIVER(rockchip_pcie_phy) = {
+ .name = "rockchip_pcie_phy",
+ .id = UCLASS_PHY,
+ .of_match = rockchip_pcie_phy_ids,
+ .ops = &rockchip_pcie_phy_ops,
+ .probe = rockchip_pcie_phy_probe,
+ .priv_auto = sizeof(struct rockchip_pcie_phy),
+};
diff --git a/roms/u-boot/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/roms/u-boot/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c
new file mode 100644
index 000000000..5ae41fbee
--- /dev/null
+++ b/roms/u-boot/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip PCIE3.0 phy driver
+ *
+ * Copyright (C) 2021 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <reset-uclass.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+
+#define GRF_PCIE30PHY_CON1 0x4
+#define GRF_PCIE30PHY_CON6 0x18
+#define GRF_PCIE30PHY_CON9 0x24
+
+/**
+ * struct rockchip_p3phy_priv - RK DW PCIe PHY state
+ *
+ * @mmio: The base address of PHY internal registers
+ * @phy_grf: The regmap for controlling pipe signal
+ * @p30phy: The reset signal for PHY
+ * @ref_clk_m: The reference clock of M for PHY
+ * @ref_clk_n: The reference clock of N for PHY
+ * @pclk: The clock for accessing PHY blocks
+ */
+struct rockchip_p3phy_priv {
+ void __iomem *mmio;
+ struct regmap *phy_grf;
+ struct reset_ctl p30phy;
+ struct clk ref_clk_m;
+ struct clk ref_clk_n;
+ struct clk pclk;
+};
+
+static int rochchip_p3phy_init(struct phy *phy)
+{
+ struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
+ int ret;
+
+ ret = clk_enable(&priv->ref_clk_m);
+ if (ret < 0 && ret != -ENOSYS)
+ return ret;
+
+ ret = clk_enable(&priv->ref_clk_n);
+ if (ret < 0 && ret != -ENOSYS)
+ goto err_ref;
+
+ ret = clk_enable(&priv->pclk);
+ if (ret < 0 && ret != -ENOSYS)
+ goto err_pclk;
+
+ reset_assert(&priv->p30phy);
+ udelay(1);
+
+ /* Deassert PCIe PMA output clamp mode */
+ regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9,
+ (0x1 << 15) | (0x1 << 31));
+
+ reset_deassert(&priv->p30phy);
+ udelay(1);
+
+ return 0;
+err_pclk:
+ clk_disable(&priv->ref_clk_n);
+err_ref:
+ clk_disable(&priv->ref_clk_m);
+
+ return ret;
+}
+
+static int rochchip_p3phy_exit(struct phy *phy)
+{
+ struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
+
+ clk_disable(&priv->ref_clk_m);
+ clk_disable(&priv->ref_clk_n);
+ clk_disable(&priv->pclk);
+ reset_assert(&priv->p30phy);
+
+ return 0;
+}
+
+static int rockchip_p3phy_probe(struct udevice *dev)
+{
+ struct rockchip_p3phy_priv *priv = dev_get_priv(dev);
+ struct udevice *syscon;
+ int ret;
+
+ priv->mmio = (void __iomem *)dev_read_addr(dev);
+ if ((fdt_addr_t)priv->mmio == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ "rockchip,phy-grf", &syscon);
+ if (ret) {
+ pr_err("unable to find syscon device for rockchip,phy-grf\n");
+ return ret;
+ }
+
+ priv->phy_grf = syscon_get_regmap(syscon);
+ if (IS_ERR(priv->phy_grf)) {
+ dev_err(dev, "failed to find rockchip,phy_grf regmap\n");
+ return PTR_ERR(priv->phy_grf);
+ }
+
+ ret = reset_get_by_name(dev, "phy", &priv->p30phy);
+ if (ret) {
+ dev_err(dev, "no phy reset control specified\n");
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "refclk_m", &priv->ref_clk_m);
+ if (ret) {
+ dev_err(dev, "failed to find ref clock M\n");
+ return PTR_ERR(&priv->ref_clk_m);
+ }
+
+ ret = clk_get_by_name(dev, "refclk_n", &priv->ref_clk_n);
+ if (ret) {
+ dev_err(dev, "failed to find ref clock N\n");
+ return PTR_ERR(&priv->ref_clk_n);
+ }
+
+ ret = clk_get_by_name(dev, "pclk", &priv->pclk);
+ if (ret) {
+ dev_err(dev, "failed to find pclk\n");
+ return PTR_ERR(&priv->pclk);
+ }
+
+ return 0;
+}
+
+static struct phy_ops rochchip_p3phy_ops = {
+ .init = rochchip_p3phy_init,
+ .exit = rochchip_p3phy_exit,
+};
+
+static const struct udevice_id rockchip_p3phy_of_match[] = {
+ { .compatible = "rockchip,rk3568-pcie3-phy" },
+ { },
+};
+
+U_BOOT_DRIVER(rockchip_pcie3phy) = {
+ .name = "rockchip_pcie3phy",
+ .id = UCLASS_PHY,
+ .of_match = rockchip_p3phy_of_match,
+ .ops = &rochchip_p3phy_ops,
+ .probe = rockchip_p3phy_probe,
+ .priv_auto = sizeof(struct rockchip_p3phy_priv),
+};
diff --git a/roms/u-boot/drivers/phy/rockchip/phy-rockchip-typec.c b/roms/u-boot/drivers/phy/rockchip/phy-rockchip-typec.c
new file mode 100644
index 000000000..ca63b856e
--- /dev/null
+++ b/roms/u-boot/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -0,0 +1,797 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ROCKCHIP Type-C PHY driver.
+ *
+ * Copyright (C) 2020 Amarula Solutions(India)
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Chris Zhong <zyw@rock-chips.com>
+ * Kever Yang <kever.yang@rock-chips.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+#include <asm/arch-rockchip/clock.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define usleep_range(a, b) udelay((b))
+
+#define CMN_SSM_BANDGAP (0x21 << 2)
+#define CMN_SSM_BIAS (0x22 << 2)
+#define CMN_PLLSM0_PLLEN (0x29 << 2)
+#define CMN_PLLSM0_PLLPRE (0x2a << 2)
+#define CMN_PLLSM0_PLLVREF (0x2b << 2)
+#define CMN_PLLSM0_PLLLOCK (0x2c << 2)
+#define CMN_PLLSM1_PLLEN (0x31 << 2)
+#define CMN_PLLSM1_PLLPRE (0x32 << 2)
+#define CMN_PLLSM1_PLLVREF (0x33 << 2)
+#define CMN_PLLSM1_PLLLOCK (0x34 << 2)
+#define CMN_PLLSM1_USER_DEF_CTRL (0x37 << 2)
+#define CMN_ICAL_OVRD (0xc1 << 2)
+#define CMN_PLL0_VCOCAL_OVRD (0x83 << 2)
+#define CMN_PLL0_VCOCAL_INIT (0x84 << 2)
+#define CMN_PLL0_VCOCAL_ITER (0x85 << 2)
+#define CMN_PLL0_LOCK_REFCNT_START (0x90 << 2)
+#define CMN_PLL0_LOCK_PLLCNT_START (0x92 << 2)
+#define CMN_PLL0_LOCK_PLLCNT_THR (0x93 << 2)
+#define CMN_PLL0_INTDIV (0x94 << 2)
+#define CMN_PLL0_FRACDIV (0x95 << 2)
+#define CMN_PLL0_HIGH_THR (0x96 << 2)
+#define CMN_PLL0_DSM_DIAG (0x97 << 2)
+#define CMN_PLL0_SS_CTRL1 (0x98 << 2)
+#define CMN_PLL0_SS_CTRL2 (0x99 << 2)
+#define CMN_PLL1_VCOCAL_START (0xa1 << 2)
+#define CMN_PLL1_VCOCAL_OVRD (0xa3 << 2)
+#define CMN_PLL1_VCOCAL_INIT (0xa4 << 2)
+#define CMN_PLL1_VCOCAL_ITER (0xa5 << 2)
+#define CMN_PLL1_LOCK_REFCNT_START (0xb0 << 2)
+#define CMN_PLL1_LOCK_PLLCNT_START (0xb2 << 2)
+#define CMN_PLL1_LOCK_PLLCNT_THR (0xb3 << 2)
+#define CMN_PLL1_INTDIV (0xb4 << 2)
+#define CMN_PLL1_FRACDIV (0xb5 << 2)
+#define CMN_PLL1_HIGH_THR (0xb6 << 2)
+#define CMN_PLL1_DSM_DIAG (0xb7 << 2)
+#define CMN_PLL1_SS_CTRL1 (0xb8 << 2)
+#define CMN_PLL1_SS_CTRL2 (0xb9 << 2)
+#define CMN_RXCAL_OVRD (0xd1 << 2)
+
+#define CMN_TXPUCAL_CTRL (0xe0 << 2)
+#define CMN_TXPUCAL_OVRD (0xe1 << 2)
+#define CMN_TXPDCAL_CTRL (0xf0 << 2)
+#define CMN_TXPDCAL_OVRD (0xf1 << 2)
+
+/* For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL */
+#define CMN_TXPXCAL_START BIT(15)
+#define CMN_TXPXCAL_DONE BIT(14)
+#define CMN_TXPXCAL_NO_RESPONSE BIT(13)
+#define CMN_TXPXCAL_CURRENT_RESPONSE BIT(12)
+
+#define CMN_TXPU_ADJ_CTRL (0x108 << 2)
+#define CMN_TXPD_ADJ_CTRL (0x10c << 2)
+
+/*
+ * For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL,
+ * CMN_TXPU_ADJ_CTRL, CMN_TXPDCAL_CTRL
+ *
+ * NOTE: some of these registers are documented to be 2's complement
+ * signed numbers, but then documented to be always positive. Weird.
+ * In such a case, using CMN_CALIB_CODE_POS() avoids the unnecessary
+ * sign extension.
+ */
+#define CMN_CALIB_CODE_WIDTH 7
+#define CMN_CALIB_CODE_OFFSET 0
+#define CMN_CALIB_CODE_MASK GENMASK(CMN_CALIB_CODE_WIDTH, 0)
+#define CMN_CALIB_CODE(x) \
+ sign_extend32((x) >> CMN_CALIB_CODE_OFFSET, CMN_CALIB_CODE_WIDTH)
+
+#define CMN_CALIB_CODE_POS_MASK GENMASK(CMN_CALIB_CODE_WIDTH - 1, 0)
+#define CMN_CALIB_CODE_POS(x) \
+ (((x) >> CMN_CALIB_CODE_OFFSET) & CMN_CALIB_CODE_POS_MASK)
+
+#define CMN_DIAG_PLL0_FBH_OVRD (0x1c0 << 2)
+#define CMN_DIAG_PLL0_FBL_OVRD (0x1c1 << 2)
+#define CMN_DIAG_PLL0_OVRD (0x1c2 << 2)
+#define CMN_DIAG_PLL0_V2I_TUNE (0x1c5 << 2)
+#define CMN_DIAG_PLL0_CP_TUNE (0x1c6 << 2)
+#define CMN_DIAG_PLL0_LF_PROG (0x1c7 << 2)
+#define CMN_DIAG_PLL1_FBH_OVRD (0x1d0 << 2)
+#define CMN_DIAG_PLL1_FBL_OVRD (0x1d1 << 2)
+#define CMN_DIAG_PLL1_OVRD (0x1d2 << 2)
+#define CMN_DIAG_PLL1_V2I_TUNE (0x1d5 << 2)
+#define CMN_DIAG_PLL1_CP_TUNE (0x1d6 << 2)
+#define CMN_DIAG_PLL1_LF_PROG (0x1d7 << 2)
+#define CMN_DIAG_PLL1_PTATIS_TUNE1 (0x1d8 << 2)
+#define CMN_DIAG_PLL1_PTATIS_TUNE2 (0x1d9 << 2)
+#define CMN_DIAG_PLL1_INCLK_CTRL (0x1da << 2)
+#define CMN_DIAG_HSCLK_SEL (0x1e0 << 2)
+
+#define XCVR_PSM_RCTRL(n) ((0x4001 | ((n) << 9)) << 2)
+#define XCVR_PSM_CAL_TMR(n) ((0x4002 | ((n) << 9)) << 2)
+#define XCVR_PSM_A0IN_TMR(n) ((0x4003 | ((n) << 9)) << 2)
+#define TX_TXCC_CAL_SCLR_MULT(n) ((0x4047 | ((n) << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_00(n) ((0x404c | ((n) << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_01(n) ((0x404d | ((n) << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_10(n) ((0x404e | ((n) << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_11(n) ((0x404f | ((n) << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_000(n) ((0x4050 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_001(n) ((0x4051 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_010(n) ((0x4052 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_011(n) ((0x4053 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_100(n) ((0x4054 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_101(n) ((0x4055 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_110(n) ((0x4056 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_111(n) ((0x4057 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNLS_MULT_000(n) ((0x4058 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNLS_MULT_001(n) ((0x4059 | ((n) << 9)) << 2)
+#define TX_TXCC_MGNLS_MULT_010(n) ((0x405a | ((n) << 9)) << 2)
+#define TX_TXCC_MGNLS_MULT_011(n) ((0x405b | ((n) << 9)) << 2)
+#define TX_TXCC_MGNLS_MULT_100(n) ((0x405c | ((n) << 9)) << 2)
+#define TX_TXCC_MGNLS_MULT_101(n) ((0x405d | ((n) << 9)) << 2)
+#define TX_TXCC_MGNLS_MULT_110(n) ((0x405e | ((n) << 9)) << 2)
+#define TX_TXCC_MGNLS_MULT_111(n) ((0x405f | ((n) << 9)) << 2)
+
+#define XCVR_DIAG_PLLDRC_CTRL(n) ((0x40e0 | ((n) << 9)) << 2)
+#define XCVR_DIAG_BIDI_CTRL(n) ((0x40e8 | ((n) << 9)) << 2)
+#define XCVR_DIAG_LANE_FCM_EN_MGN(n) ((0x40f2 | ((n) << 9)) << 2)
+#define TX_PSC_A0(n) ((0x4100 | ((n) << 9)) << 2)
+#define TX_PSC_A1(n) ((0x4101 | ((n) << 9)) << 2)
+#define TX_PSC_A2(n) ((0x4102 | ((n) << 9)) << 2)
+#define TX_PSC_A3(n) ((0x4103 | ((n) << 9)) << 2)
+#define TX_RCVDET_CTRL(n) ((0x4120 | ((n) << 9)) << 2)
+#define TX_RCVDET_EN_TMR(n) ((0x4122 | ((n) << 9)) << 2)
+#define TX_RCVDET_ST_TMR(n) ((0x4123 | ((n) << 9)) << 2)
+#define TX_DIAG_TX_DRV(n) ((0x41e1 | ((n) << 9)) << 2)
+#define TX_DIAG_BGREF_PREDRV_DELAY (0x41e7 << 2)
+
+/* Use this for "n" in macros like "_MULT_XXX" to target the aux channel */
+#define AUX_CH_LANE 8
+
+#define TX_ANA_CTRL_REG_1 (0x5020 << 2)
+
+#define TXDA_DP_AUX_EN BIT(15)
+#define AUXDA_SE_EN BIT(14)
+#define TXDA_CAL_LATCH_EN BIT(13)
+#define AUXDA_POLARITY BIT(12)
+#define TXDA_DRV_POWER_ISOLATION_EN BIT(11)
+#define TXDA_DRV_POWER_EN_PH_2_N BIT(10)
+#define TXDA_DRV_POWER_EN_PH_1_N BIT(9)
+#define TXDA_BGREF_EN BIT(8)
+#define TXDA_DRV_LDO_EN BIT(7)
+#define TXDA_DECAP_EN_DEL BIT(6)
+#define TXDA_DECAP_EN BIT(5)
+#define TXDA_UPHY_SUPPLY_EN_DEL BIT(4)
+#define TXDA_UPHY_SUPPLY_EN BIT(3)
+#define TXDA_LOW_LEAKAGE_EN BIT(2)
+#define TXDA_DRV_IDLE_LOWI_EN BIT(1)
+#define TXDA_DRV_CMN_MODE_EN BIT(0)
+
+#define TX_ANA_CTRL_REG_2 (0x5021 << 2)
+
+#define AUXDA_DEBOUNCING_CLK BIT(15)
+#define TXDA_LPBK_RECOVERED_CLK_EN BIT(14)
+#define TXDA_LPBK_ISI_GEN_EN BIT(13)
+#define TXDA_LPBK_SERIAL_EN BIT(12)
+#define TXDA_LPBK_LINE_EN BIT(11)
+#define TXDA_DRV_LDO_REDC_SINKIQ BIT(10)
+#define XCVR_DECAP_EN_DEL BIT(9)
+#define XCVR_DECAP_EN BIT(8)
+#define TXDA_MPHY_ENABLE_HS_NT BIT(7)
+#define TXDA_MPHY_SA_MODE BIT(6)
+#define TXDA_DRV_LDO_RBYR_FB_EN BIT(5)
+#define TXDA_DRV_RST_PULL_DOWN BIT(4)
+#define TXDA_DRV_LDO_BG_FB_EN BIT(3)
+#define TXDA_DRV_LDO_BG_REF_EN BIT(2)
+#define TXDA_DRV_PREDRV_EN_DEL BIT(1)
+#define TXDA_DRV_PREDRV_EN BIT(0)
+
+#define TXDA_COEFF_CALC_CTRL (0x5022 << 2)
+
+#define TX_HIGH_Z BIT(6)
+#define TX_VMARGIN_OFFSET 3
+#define TX_VMARGIN_MASK 0x7
+#define LOW_POWER_SWING_EN BIT(2)
+#define TX_FCM_DRV_MAIN_EN BIT(1)
+#define TX_FCM_FULL_MARGIN BIT(0)
+
+#define TX_DIG_CTRL_REG_2 (0x5024 << 2)
+
+#define TX_HIGH_Z_TM_EN BIT(15)
+#define TX_RESCAL_CODE_OFFSET 0
+#define TX_RESCAL_CODE_MASK 0x3f
+
+#define TXDA_CYA_AUXDA_CYA (0x5025 << 2)
+#define TX_ANA_CTRL_REG_3 (0x5026 << 2)
+#define TX_ANA_CTRL_REG_4 (0x5027 << 2)
+#define TX_ANA_CTRL_REG_5 (0x5029 << 2)
+
+#define RX_PSC_A0(n) ((0x8000 | ((n) << 9)) << 2)
+#define RX_PSC_A1(n) ((0x8001 | ((n) << 9)) << 2)
+#define RX_PSC_A2(n) ((0x8002 | ((n) << 9)) << 2)
+#define RX_PSC_A3(n) ((0x8003 | ((n) << 9)) << 2)
+#define RX_PSC_CAL(n) ((0x8006 | ((n) << 9)) << 2)
+#define RX_PSC_RDY(n) ((0x8007 | ((n) << 9)) << 2)
+#define RX_IQPI_ILL_CAL_OVRD (0x8023 << 2)
+#define RX_EPI_ILL_CAL_OVRD (0x8033 << 2)
+#define RX_SDCAL0_OVRD (0x8041 << 2)
+#define RX_SDCAL1_OVRD (0x8049 << 2)
+#define RX_SLC_INIT (0x806d << 2)
+#define RX_SLC_RUN (0x806e << 2)
+#define RX_CDRLF_CNFG2 (0x8081 << 2)
+#define RX_SIGDET_HL_FILT_TMR(n) ((0x8090 | ((n) << 9)) << 2)
+#define RX_SLC_IOP0_OVRD (0x8101 << 2)
+#define RX_SLC_IOP1_OVRD (0x8105 << 2)
+#define RX_SLC_QOP0_OVRD (0x8109 << 2)
+#define RX_SLC_QOP1_OVRD (0x810d << 2)
+#define RX_SLC_EOP0_OVRD (0x8111 << 2)
+#define RX_SLC_EOP1_OVRD (0x8115 << 2)
+#define RX_SLC_ION0_OVRD (0x8119 << 2)
+#define RX_SLC_ION1_OVRD (0x811d << 2)
+#define RX_SLC_QON0_OVRD (0x8121 << 2)
+#define RX_SLC_QON1_OVRD (0x8125 << 2)
+#define RX_SLC_EON0_OVRD (0x8129 << 2)
+#define RX_SLC_EON1_OVRD (0x812d << 2)
+#define RX_SLC_IEP0_OVRD (0x8131 << 2)
+#define RX_SLC_IEP1_OVRD (0x8135 << 2)
+#define RX_SLC_QEP0_OVRD (0x8139 << 2)
+#define RX_SLC_QEP1_OVRD (0x813d << 2)
+#define RX_SLC_EEP0_OVRD (0x8141 << 2)
+#define RX_SLC_EEP1_OVRD (0x8145 << 2)
+#define RX_SLC_IEN0_OVRD (0x8149 << 2)
+#define RX_SLC_IEN1_OVRD (0x814d << 2)
+#define RX_SLC_QEN0_OVRD (0x8151 << 2)
+#define RX_SLC_QEN1_OVRD (0x8155 << 2)
+#define RX_SLC_EEN0_OVRD (0x8159 << 2)
+#define RX_SLC_EEN1_OVRD (0x815d << 2)
+#define RX_REE_CTRL_DATA_MASK(n) ((0x81bb | ((n) << 9)) << 2)
+#define RX_DIAG_SIGDET_TUNE(n) ((0x81dc | ((n) << 9)) << 2)
+#define RX_DIAG_SC2C_DELAY (0x81e1 << 2)
+
+#define PMA_LANE_CFG (0xc000 << 2)
+#define PIPE_CMN_CTRL1 (0xc001 << 2)
+#define PIPE_CMN_CTRL2 (0xc002 << 2)
+#define PIPE_COM_LOCK_CFG1 (0xc003 << 2)
+#define PIPE_COM_LOCK_CFG2 (0xc004 << 2)
+#define PIPE_RCV_DET_INH (0xc005 << 2)
+#define DP_MODE_CTL (0xc008 << 2)
+#define DP_CLK_CTL (0xc009 << 2)
+#define STS (0xc00F << 2)
+#define PHY_ISO_CMN_CTRL (0xc010 << 2)
+#define PHY_DP_TX_CTL (0xc408 << 2)
+#define PMA_CMN_CTRL1 (0xc800 << 2)
+#define PHY_PMA_ISO_CMN_CTRL (0xc810 << 2)
+#define PHY_ISOLATION_CTRL (0xc81f << 2)
+#define PHY_PMA_ISO_XCVR_CTRL(n) ((0xcc11 | ((n) << 6)) << 2)
+#define PHY_PMA_ISO_LINK_MODE(n) ((0xcc12 | ((n) << 6)) << 2)
+#define PHY_PMA_ISO_PWRST_CTRL(n) ((0xcc13 | ((n) << 6)) << 2)
+#define PHY_PMA_ISO_TX_DATA_LO(n) ((0xcc14 | ((n) << 6)) << 2)
+#define PHY_PMA_ISO_TX_DATA_HI(n) ((0xcc15 | ((n) << 6)) << 2)
+#define PHY_PMA_ISO_RX_DATA_LO(n) ((0xcc16 | ((n) << 6)) << 2)
+#define PHY_PMA_ISO_RX_DATA_HI(n) ((0xcc17 | ((n) << 6)) << 2)
+#define TX_BIST_CTRL(n) ((0x4140 | ((n) << 9)) << 2)
+#define TX_BIST_UDDWR(n) ((0x4141 | ((n) << 9)) << 2)
+
+/*
+ * Selects which PLL clock will be driven on the analog high speed
+ * clock 0: PLL 0 div 1
+ * clock 1: PLL 1 div 2
+ */
+#define CLK_PLL_CONFIG 0X30
+#define CLK_PLL_MASK 0x33
+
+#define CMN_READY BIT(0)
+
+#define DP_PLL_CLOCK_ENABLE BIT(2)
+#define DP_PLL_ENABLE BIT(0)
+#define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8))
+#define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8))
+#define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8))
+
+#define DP_MODE_A0 BIT(4)
+#define DP_MODE_A2 BIT(6)
+#define DP_MODE_ENTER_A0 0xc101
+#define DP_MODE_ENTER_A2 0xc104
+
+#define PHY_MODE_SET_TIMEOUT 100000
+
+#define PIN_ASSIGN_C_E 0x51d9
+#define PIN_ASSIGN_D_F 0x5100
+
+#define MODE_DISCONNECT 0
+#define MODE_UFP_USB BIT(0)
+#define MODE_DFP_USB BIT(1)
+#define MODE_DFP_DP BIT(2)
+
+struct usb3phy_reg {
+ u32 offset;
+ u32 enable_bit;
+ u32 write_enable;
+};
+
+/**
+ * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration.
+ * @reg: the base address for usb3-phy config.
+ * @typec_conn_dir: the register of type-c connector direction.
+ * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable.
+ * @external_psm: the register of type-c phy external psm clock.
+ * @pipe_status: the register of type-c phy pipe status.
+ * @usb3_host_disable: the register of type-c usb3 host disable.
+ * @usb3_host_port: the register of type-c usb3 host port.
+ * @uphy_dp_sel: the register of type-c phy DP select control.
+ */
+struct rockchip_usb3phy_port_cfg {
+ unsigned int reg;
+ struct usb3phy_reg typec_conn_dir;
+ struct usb3phy_reg usb3tousb2_en;
+ struct usb3phy_reg external_psm;
+ struct usb3phy_reg pipe_status;
+ struct usb3phy_reg usb3_host_disable;
+ struct usb3phy_reg usb3_host_port;
+ struct usb3phy_reg uphy_dp_sel;
+};
+
+struct rockchip_tcphy {
+ void __iomem *reg_base;
+ void __iomem *grf_base;
+ struct clk clk_core;
+ struct clk clk_ref;
+ struct reset_ctl uphy_rst;
+ struct reset_ctl pipe_rst;
+ struct reset_ctl tcphy_rst;
+ const struct rockchip_usb3phy_port_cfg *port_cfgs;
+ u8 mode;
+};
+
+struct phy_reg {
+ u16 value;
+ u32 addr;
+};
+
+static struct phy_reg usb3_pll_cfg[] = {
+ { 0xf0, CMN_PLL0_VCOCAL_INIT },
+ { 0x18, CMN_PLL0_VCOCAL_ITER },
+ { 0xd0, CMN_PLL0_INTDIV },
+ { 0x4a4a, CMN_PLL0_FRACDIV },
+ { 0x34, CMN_PLL0_HIGH_THR },
+ { 0x1ee, CMN_PLL0_SS_CTRL1 },
+ { 0x7f03, CMN_PLL0_SS_CTRL2 },
+ { 0x20, CMN_PLL0_DSM_DIAG },
+ { 0, CMN_DIAG_PLL0_OVRD },
+ { 0, CMN_DIAG_PLL0_FBH_OVRD },
+ { 0, CMN_DIAG_PLL0_FBL_OVRD },
+ { 0x7, CMN_DIAG_PLL0_V2I_TUNE },
+ { 0x45, CMN_DIAG_PLL0_CP_TUNE },
+ { 0x8, CMN_DIAG_PLL0_LF_PROG },
+};
+
+static inline int property_enable(struct rockchip_tcphy *priv,
+ const struct usb3phy_reg *reg, bool en)
+{
+ u32 mask = 1 << reg->write_enable;
+ u32 val = en << reg->enable_bit;
+
+ return writel(val | mask, priv->grf_base + reg->offset);
+}
+
+static int rockchip_tcphy_get_mode(struct rockchip_tcphy *priv)
+{
+ /* TODO: Add proper logic to find DP or USB3 mode */
+ return MODE_DFP_USB | MODE_UFP_USB;
+}
+
+static void rockchip_tcphy_cfg_24m(struct rockchip_tcphy *priv)
+{
+ u32 i, rdata;
+
+ /*
+ * cmn_ref_clk_sel = 3, select the 24Mhz for clk parent
+ * cmn_psm_clk_dig_div = 2, set the clk division to 2
+ */
+ writel(0x830, priv->reg_base + PMA_CMN_CTRL1);
+ for (i = 0; i < 4; i++) {
+ /*
+ * The following PHY configuration assumes a 24 MHz reference
+ * clock.
+ */
+ writel(0x90, priv->reg_base + XCVR_DIAG_LANE_FCM_EN_MGN(i));
+ writel(0x960, priv->reg_base + TX_RCVDET_EN_TMR(i));
+ writel(0x30, priv->reg_base + TX_RCVDET_ST_TMR(i));
+ }
+
+ rdata = readl(priv->reg_base + CMN_DIAG_HSCLK_SEL);
+ rdata &= ~CLK_PLL_MASK;
+ rdata |= CLK_PLL_CONFIG;
+ writel(rdata, priv->reg_base + CMN_DIAG_HSCLK_SEL);
+}
+
+static void rockchip_tcphy_cfg_usb3_pll(struct rockchip_tcphy *priv)
+{
+ u32 i;
+
+ /* load the configuration of PLL0 */
+ for (i = 0; i < ARRAY_SIZE(usb3_pll_cfg); i++)
+ writel(usb3_pll_cfg[i].value,
+ priv->reg_base + usb3_pll_cfg[i].addr);
+}
+
+static void rockchip_tcphy_tx_usb3_cfg_lane(struct rockchip_tcphy *priv,
+ u32 lane)
+{
+ writel(0x7799, priv->reg_base + TX_PSC_A0(lane));
+ writel(0x7798, priv->reg_base + TX_PSC_A1(lane));
+ writel(0x5098, priv->reg_base + TX_PSC_A2(lane));
+ writel(0x5098, priv->reg_base + TX_PSC_A3(lane));
+ writel(0, priv->reg_base + TX_TXCC_MGNFS_MULT_000(lane));
+ writel(0xbf, priv->reg_base + XCVR_DIAG_BIDI_CTRL(lane));
+}
+
+static void rockchip_tcphy_rx_usb3_cfg_lane(struct rockchip_tcphy *priv,
+ u32 lane)
+{
+ writel(0xa6fd, priv->reg_base + RX_PSC_A0(lane));
+ writel(0xa6fd, priv->reg_base + RX_PSC_A1(lane));
+ writel(0xa410, priv->reg_base + RX_PSC_A2(lane));
+ writel(0x2410, priv->reg_base + RX_PSC_A3(lane));
+ writel(0x23ff, priv->reg_base + RX_PSC_CAL(lane));
+ writel(0x13, priv->reg_base + RX_SIGDET_HL_FILT_TMR(lane));
+ writel(0x03e7, priv->reg_base + RX_REE_CTRL_DATA_MASK(lane));
+ writel(0x1004, priv->reg_base + RX_DIAG_SIGDET_TUNE(lane));
+ writel(0x2010, priv->reg_base + RX_PSC_RDY(lane));
+ writel(0xfb, priv->reg_base + XCVR_DIAG_BIDI_CTRL(lane));
+}
+
+static int rockchip_tcphy_init(struct phy *phy, struct rockchip_tcphy *priv)
+{
+ const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs;
+ u32 val;
+ int ret;
+
+ ret = clk_enable(&priv->clk_core);
+ if (ret) {
+ dev_err(phy->dev, "failed to enable core clk (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(&priv->clk_ref);
+ if (ret) {
+ dev_err(phy->dev, "failed to enable ref clk (ret=%d)\n", ret);
+ goto err_clk_core;
+ }
+
+ ret = reset_deassert(&priv->tcphy_rst);
+ if (ret) {
+ dev_err(phy->dev, "failed to deassert uphy-tcphy reset (ret=%d)\n",
+ ret);
+ goto err_clk_ref;
+ }
+
+ property_enable(priv, &cfg->typec_conn_dir, 0);
+
+ rockchip_tcphy_cfg_24m(priv);
+
+ rockchip_tcphy_cfg_usb3_pll(priv);
+
+ rockchip_tcphy_tx_usb3_cfg_lane(priv, 0);
+ rockchip_tcphy_rx_usb3_cfg_lane(priv, 1);
+
+ ret = reset_deassert(&priv->uphy_rst);
+ if (ret) {
+ dev_err(phy->dev, "failed to deassert uphy rst (ret=%d)\n",
+ ret);
+ goto err_tcphy_rst;
+ }
+
+ ret = readl_poll_sleep_timeout(priv->reg_base + PMA_CMN_CTRL1,
+ val, val & CMN_READY, 10,
+ PHY_MODE_SET_TIMEOUT);
+ if (ret < 0) {
+ dev_err(phy->dev, "PMA Timeout!\n");
+ ret = -ETIMEDOUT;
+ goto err_uphy_rst;
+ }
+
+ ret = reset_deassert(&priv->pipe_rst);
+ if (ret) {
+ dev_err(phy->dev, "failed to deassert pipe rst (ret=%d)\n",
+ ret);
+ goto err_uphy_rst;
+ }
+
+ return 0;
+
+err_uphy_rst:
+ reset_assert(&priv->uphy_rst);
+err_tcphy_rst:
+ reset_assert(&priv->tcphy_rst);
+err_clk_ref:
+ clk_disable(&priv->clk_ref);
+err_clk_core:
+ clk_disable(&priv->clk_core);
+ return ret;
+}
+
+static void rockchip_tcphy_exit(struct rockchip_tcphy *priv)
+{
+ reset_assert(&priv->tcphy_rst);
+ reset_assert(&priv->uphy_rst);
+ reset_assert(&priv->pipe_rst);
+ clk_disable(&priv->clk_core);
+ clk_disable(&priv->clk_ref);
+}
+
+static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_tcphy *priv,
+ bool value)
+{
+ const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs;
+
+ property_enable(priv, &cfg->usb3tousb2_en, value);
+ property_enable(priv, &cfg->usb3_host_disable, value);
+ property_enable(priv, &cfg->usb3_host_port, !value);
+
+ return 0;
+}
+
+static int rockchip_usb3_phy_power_on(struct phy *phy)
+{
+ struct udevice *parent = dev_get_parent(phy->dev);
+ struct rockchip_tcphy *priv = dev_get_priv(parent);
+ const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs;
+ const struct usb3phy_reg *reg = &cfg->pipe_status;
+ int timeout, new_mode;
+ u32 val;
+ int ret;
+
+ new_mode = rockchip_tcphy_get_mode(priv);
+ if (new_mode < 0) {
+ dev_err(phy->dev, "invalid mode %d\n", new_mode);
+ return new_mode;
+ }
+
+ if (priv->mode == new_mode)
+ return 0;
+
+ if (priv->mode == MODE_DISCONNECT) {
+ ret = rockchip_tcphy_init(phy, priv);
+ if (ret) {
+ dev_err(phy->dev, "failed to init tcphy (ret=%d)\n", ret);
+ return ret;
+ }
+ }
+
+ /* wait TCPHY for pipe ready */
+ for (timeout = 0; timeout < 100; timeout++) {
+ val = readl(priv->grf_base + reg->offset);
+ if (!(val & BIT(reg->enable_bit))) {
+ priv->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB);
+
+ /* enable usb3 host */
+ tcphy_cfg_usb3_to_usb2_only(priv, false);
+ return 0;
+ }
+ usleep_range(10, 20);
+ }
+
+ if (priv->mode == MODE_DISCONNECT)
+ rockchip_tcphy_exit(priv);
+
+ return -ETIMEDOUT;
+}
+
+static int rockchip_usb3_phy_power_off(struct phy *phy)
+{
+ struct udevice *parent = dev_get_parent(phy->dev);
+ struct rockchip_tcphy *priv = dev_get_priv(parent);
+
+ tcphy_cfg_usb3_to_usb2_only(priv, false);
+
+ if (priv->mode == MODE_DISCONNECT)
+ goto exit;
+
+ priv->mode &= ~(MODE_UFP_USB | MODE_DFP_USB);
+ if (priv->mode == MODE_DISCONNECT)
+ rockchip_tcphy_exit(priv);
+
+exit:
+ return 0;
+}
+
+static struct phy_ops rockchip_tcphy_usb3_ops = {
+ .power_on = rockchip_usb3_phy_power_on,
+ .power_off = rockchip_usb3_phy_power_off,
+};
+
+static void rockchip_tcphy_pre_init(struct udevice *dev)
+{
+ struct rockchip_tcphy *priv = dev_get_priv(dev);
+ const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs;
+
+ reset_assert(&priv->tcphy_rst);
+ reset_assert(&priv->uphy_rst);
+ reset_assert(&priv->pipe_rst);
+
+ /* select external psm clock */
+ property_enable(priv, &cfg->external_psm, 1);
+ property_enable(priv, &cfg->usb3tousb2_en, 0);
+
+ priv->mode = MODE_DISCONNECT;
+}
+
+static int rockchip_tcphy_parse_dt(struct udevice *dev)
+{
+ struct rockchip_tcphy *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ if (IS_ERR(priv->grf_base))
+ return PTR_ERR(priv->grf_base);
+
+ ret = clk_get_by_name(dev, "tcpdcore", &priv->clk_core);
+ if (ret) {
+ dev_err(dev, "failed to get tcpdcore clk (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "tcpdphy-ref", &priv->clk_ref);
+ if (ret) {
+ dev_err(dev, "failed to get tcpdphy-ref clk (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "uphy", &priv->uphy_rst);
+ if (ret) {
+ dev_err(dev, "failed to get uphy reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "uphy-pipe", &priv->pipe_rst);
+ if (ret) {
+ dev_err(dev, "failed to get uphy-pipe reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "uphy-tcphy", &priv->tcphy_rst);
+ if (ret) {
+ dev_err(dev, "failed to get uphy-tcphy reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rockchip_tcphy_probe(struct udevice *dev)
+{
+ struct rockchip_tcphy *priv = dev_get_priv(dev);
+ const struct rockchip_usb3phy_port_cfg *phy_cfgs;
+ unsigned int reg;
+ int index, ret;
+
+ priv->reg_base = (void __iomem *)dev_read_addr(dev);
+ if (IS_ERR(priv->reg_base))
+ return PTR_ERR(priv->reg_base);
+
+ ret = dev_read_u32_index(dev, "reg", 1, &reg);
+ if (ret) {
+ dev_err(dev, "failed to read reg property (ret = %d)\n", ret);
+ return ret;
+ }
+
+ phy_cfgs = (const struct rockchip_usb3phy_port_cfg *)
+ dev_get_driver_data(dev);
+ if (!phy_cfgs)
+ return -EINVAL;
+
+ /* find out a proper config which can be matched with dt. */
+ index = 0;
+ while (phy_cfgs[index].reg) {
+ if (phy_cfgs[index].reg == reg) {
+ priv->port_cfgs = &phy_cfgs[index];
+ break;
+ }
+
+ ++index;
+ }
+
+ if (!priv->port_cfgs) {
+ dev_err(dev, "failed find proper phy-cfg\n");
+ return -EINVAL;
+ }
+
+ ret = rockchip_tcphy_parse_dt(dev);
+ if (ret)
+ return ret;
+
+ rockchip_tcphy_pre_init(dev);
+
+ return 0;
+}
+
+static int rockchip_tcphy_bind(struct udevice *dev)
+{
+ struct udevice *tcphy_dev;
+ ofnode node;
+ const char *name;
+ int ret = 0;
+
+ dev_for_each_subnode(node, dev) {
+ if (!ofnode_valid(node)) {
+ dev_info(dev, "subnode %s not found\n", dev->name);
+ return -ENXIO;
+ }
+
+ name = ofnode_get_name(node);
+ dev_dbg(dev, "subnode %s\n", name);
+
+ if (!strcasecmp(name, "dp-port")) {
+ dev_dbg(dev, "Warning: dp-port not supported yet!\n");
+ continue;
+ } else if (!strcasecmp(name, "usb3-port")) {
+ ret = device_bind_driver_to_node(dev,
+ "rockchip_tcphy_usb3_port",
+ name, node, &tcphy_dev);
+ if (ret) {
+ dev_err(dev,
+ "'%s' cannot bind 'rockchip_tcphy_usb3_port'\n",
+ name);
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static const struct rockchip_usb3phy_port_cfg rk3399_typec_phy_cfgs[] = {
+ {
+ .reg = 0xff7c0000,
+ .typec_conn_dir = { 0xe580, 0, 16 },
+ .usb3tousb2_en = { 0xe580, 3, 19 },
+ .external_psm = { 0xe588, 14, 30 },
+ .pipe_status = { 0xe5c0, 0, 0 },
+ .usb3_host_disable = { 0x2434, 0, 16 },
+ .usb3_host_port = { 0x2434, 12, 28 },
+ .uphy_dp_sel = { 0x6268, 19, 19 },
+ },
+ {
+ .reg = 0xff800000,
+ .typec_conn_dir = { 0xe58c, 0, 16 },
+ .usb3tousb2_en = { 0xe58c, 3, 19 },
+ .external_psm = { 0xe594, 14, 30 },
+ .pipe_status = { 0xe5c0, 16, 16 },
+ .usb3_host_disable = { 0x2444, 0, 16 },
+ .usb3_host_port = { 0x2444, 12, 28 },
+ .uphy_dp_sel = { 0x6268, 3, 19 },
+ },
+ { /* sentinel */ }
+};
+
+static const struct udevice_id rockchip_typec_phy_ids[] = {
+ {
+ .compatible = "rockchip,rk3399-typec-phy",
+ .data = (ulong)&rk3399_typec_phy_cfgs,
+ },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(rockchip_tcphy_usb3_port) = {
+ .name = "rockchip_tcphy_usb3_port",
+ .id = UCLASS_PHY,
+ .ops = &rockchip_tcphy_usb3_ops,
+};
+
+U_BOOT_DRIVER(rockchip_typec_phy) = {
+ .name = "rockchip_typec_phy",
+ .id = UCLASS_PHY,
+ .of_match = rockchip_typec_phy_ids,
+ .probe = rockchip_tcphy_probe,
+ .bind = rockchip_tcphy_bind,
+ .priv_auto = sizeof(struct rockchip_tcphy),
+};
diff --git a/roms/u-boot/drivers/phy/sandbox-phy.c b/roms/u-boot/drivers/phy/sandbox-phy.c
new file mode 100644
index 000000000..7b3d98861
--- /dev/null
+++ b/roms/u-boot/drivers/phy/sandbox-phy.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+
+#define DRIVER_DATA 0x12345678
+
+struct sandbox_phy_priv {
+ bool initialized;
+ bool on;
+ bool broken;
+};
+
+static int sandbox_phy_power_on(struct phy *phy)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(phy->dev);
+
+ if (!priv->initialized)
+ return -EIO;
+
+ if (priv->broken)
+ return -EIO;
+
+ priv->on = true;
+
+ return 0;
+}
+
+static int sandbox_phy_power_off(struct phy *phy)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(phy->dev);
+
+ if (!priv->initialized)
+ return -EIO;
+
+ if (priv->broken)
+ return -EIO;
+
+ /*
+ * for validation purpose, let's says that power off
+ * works only for PHY 0
+ */
+ if (phy->id)
+ return -EIO;
+
+ priv->on = false;
+
+ return 0;
+}
+
+static int sandbox_phy_init(struct phy *phy)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(phy->dev);
+
+ priv->initialized = true;
+ priv->on = true;
+
+ return 0;
+}
+
+static int sandbox_phy_exit(struct phy *phy)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(phy->dev);
+
+ priv->initialized = false;
+ priv->on = false;
+
+ return 0;
+}
+
+static int sandbox_phy_bind(struct udevice *dev)
+{
+ if (dev_get_driver_data(dev) != DRIVER_DATA)
+ return -ENODATA;
+
+ return 0;
+}
+
+static int sandbox_phy_probe(struct udevice *dev)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(dev);
+
+ priv->initialized = false;
+ priv->on = false;
+ priv->broken = dev_read_bool(dev, "broken");
+
+ return 0;
+}
+
+static struct phy_ops sandbox_phy_ops = {
+ .power_on = sandbox_phy_power_on,
+ .power_off = sandbox_phy_power_off,
+ .init = sandbox_phy_init,
+ .exit = sandbox_phy_exit,
+};
+
+static const struct udevice_id sandbox_phy_ids[] = {
+ { .compatible = "sandbox,phy_no_driver_data",
+ },
+
+ { .compatible = "sandbox,phy",
+ .data = DRIVER_DATA
+ },
+ { }
+};
+
+U_BOOT_DRIVER(phy_sandbox) = {
+ .name = "phy_sandbox",
+ .id = UCLASS_PHY,
+ .bind = sandbox_phy_bind,
+ .of_match = sandbox_phy_ids,
+ .ops = &sandbox_phy_ops,
+ .probe = sandbox_phy_probe,
+ .priv_auto = sizeof(struct sandbox_phy_priv),
+};
diff --git a/roms/u-boot/drivers/phy/sti_usb_phy.c b/roms/u-boot/drivers/phy/sti_usb_phy.c
new file mode 100644
index 000000000..ce4caafce
--- /dev/null
+++ b/roms/u-boot/drivers/phy/sti_usb_phy.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <bitfield.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <generic-phy.h>
+#include <linux/libfdt.h>
+#include <regmap.h>
+#include <reset-uclass.h>
+#include <syscon.h>
+#include <wait_bit.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Default PHY_SEL and REFCLKSEL configuration */
+#define STIH407_USB_PICOPHY_CTRL_PORT_CONF 0x6
+
+/* ports parameters overriding */
+#define STIH407_USB_PICOPHY_PARAM_DEF 0x39a4dc
+
+#define PHYPARAM_REG 1
+#define PHYCTRL_REG 2
+#define PHYPARAM_NB 3
+
+struct sti_usb_phy {
+ struct regmap *regmap;
+ struct reset_ctl global_ctl;
+ struct reset_ctl port_ctl;
+ int param;
+ int ctrl;
+};
+
+static int sti_usb_phy_deassert(struct sti_usb_phy *phy)
+{
+ int ret;
+
+ ret = reset_deassert(&phy->global_ctl);
+ if (ret < 0) {
+ pr_err("PHY global deassert failed: %d", ret);
+ return ret;
+ }
+
+ ret = reset_deassert(&phy->port_ctl);
+ if (ret < 0)
+ pr_err("PHY port deassert failed: %d", ret);
+
+ return ret;
+}
+
+static int sti_usb_phy_init(struct phy *usb_phy)
+{
+ struct udevice *dev = usb_phy->dev;
+ struct sti_usb_phy *phy = dev_get_priv(dev);
+ void __iomem *reg;
+
+ /* set ctrl picophy value */
+ reg = (void __iomem *)phy->regmap->ranges[0].start + phy->ctrl;
+ /* CTRL_PORT mask is 0x1f */
+ clrsetbits_le32(reg, 0x1f, STIH407_USB_PICOPHY_CTRL_PORT_CONF);
+
+ /* set ports parameters overriding */
+ reg = (void __iomem *)phy->regmap->ranges[0].start + phy->param;
+ /* PARAM_DEF mask is 0xffffffff */
+ clrsetbits_le32(reg, 0xffffffff, STIH407_USB_PICOPHY_PARAM_DEF);
+
+ return sti_usb_phy_deassert(phy);
+}
+
+static int sti_usb_phy_exit(struct phy *usb_phy)
+{
+ struct udevice *dev = usb_phy->dev;
+ struct sti_usb_phy *phy = dev_get_priv(dev);
+ int ret;
+
+ ret = reset_assert(&phy->port_ctl);
+ if (ret < 0) {
+ pr_err("PHY port assert failed: %d", ret);
+ return ret;
+ }
+
+ ret = reset_assert(&phy->global_ctl);
+ if (ret < 0)
+ pr_err("PHY global assert failed: %d", ret);
+
+ return ret;
+}
+
+struct phy_ops sti_usb_phy_ops = {
+ .init = sti_usb_phy_init,
+ .exit = sti_usb_phy_exit,
+};
+
+int sti_usb_phy_probe(struct udevice *dev)
+{
+ struct sti_usb_phy *priv = dev_get_priv(dev);
+ struct udevice *syscon;
+ struct ofnode_phandle_args syscfg_phandle;
+ u32 cells[PHYPARAM_NB];
+ int ret, count;
+
+ /* get corresponding syscon phandle */
+ ret = dev_read_phandle_with_args(dev, "st,syscfg", NULL, 0, 0,
+ &syscfg_phandle);
+
+ if (ret < 0) {
+ pr_err("Can't get syscfg phandle: %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, syscfg_phandle.node,
+ &syscon);
+ if (ret) {
+ pr_err("unable to find syscon device (%d)\n", ret);
+ return ret;
+ }
+
+ priv->regmap = syscon_get_regmap(syscon);
+ if (!priv->regmap) {
+ pr_err("unable to find regmap\n");
+ return -ENODEV;
+ }
+
+ /* get phy param offset */
+ count = fdtdec_get_int_array_count(gd->fdt_blob, dev_of_offset(dev),
+ "st,syscfg", cells,
+ ARRAY_SIZE(cells));
+
+ if (count < 0) {
+ pr_err("Bad PHY st,syscfg property %d\n", count);
+ return -EINVAL;
+ }
+
+ if (count > PHYPARAM_NB) {
+ pr_err("Unsupported PHY param count %d\n", count);
+ return -EINVAL;
+ }
+
+ priv->param = cells[PHYPARAM_REG];
+ priv->ctrl = cells[PHYCTRL_REG];
+
+ /* get global reset control */
+ ret = reset_get_by_name(dev, "global", &priv->global_ctl);
+ if (ret) {
+ pr_err("can't get global reset for %s (%d)", dev->name, ret);
+ return ret;
+ }
+
+ /* get port reset control */
+ ret = reset_get_by_name(dev, "port", &priv->port_ctl);
+ if (ret) {
+ pr_err("can't get port reset for %s (%d)", dev->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id sti_usb_phy_ids[] = {
+ { .compatible = "st,stih407-usb2-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(sti_usb_phy) = {
+ .name = "sti_usb_phy",
+ .id = UCLASS_PHY,
+ .of_match = sti_usb_phy_ids,
+ .probe = sti_usb_phy_probe,
+ .ops = &sti_usb_phy_ops,
+ .priv_auto = sizeof(struct sti_usb_phy),
+};
diff --git a/roms/u-boot/drivers/phy/ti-pipe3-phy.c b/roms/u-boot/drivers/phy/ti-pipe3-phy.c
new file mode 100644
index 000000000..b5b3c3f15
--- /dev/null
+++ b/roms/u-boot/drivers/phy/ti-pipe3-phy.c
@@ -0,0 +1,609 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <generic-phy.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/sys_proto.h>
+#include <syscon.h>
+#include <regmap.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+/* PLLCTRL Registers */
+#define PLL_STATUS 0x00000004
+#define PLL_GO 0x00000008
+#define PLL_CONFIGURATION1 0x0000000C
+#define PLL_CONFIGURATION2 0x00000010
+#define PLL_CONFIGURATION3 0x00000014
+#define PLL_CONFIGURATION4 0x00000020
+
+#define PLL_REGM_MASK 0x001FFE00
+#define PLL_REGM_SHIFT 9
+#define PLL_REGM_F_MASK 0x0003FFFF
+#define PLL_REGM_F_SHIFT 0
+#define PLL_REGN_MASK 0x000001FE
+#define PLL_REGN_SHIFT 1
+#define PLL_SELFREQDCO_MASK 0x0000000E
+#define PLL_SELFREQDCO_SHIFT 1
+#define PLL_SD_MASK 0x0003FC00
+#define PLL_SD_SHIFT 10
+#define SET_PLL_GO 0x1
+#define PLL_TICOPWDN BIT(16)
+#define PLL_LDOPWDN BIT(15)
+#define PLL_LOCK 0x2
+#define PLL_IDLE 0x1
+
+/* Software rest for the SATA PLL (in CTRL_CORE_SMA_SW_0 register)*/
+#define SATA_PLL_SOFT_RESET (1<<18)
+
+/* PHY POWER CONTROL Register */
+#define PIPE3_PHY_PWRCTL_CLK_CMD_MASK GENMASK(21, 14)
+#define PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 14
+
+#define PIPE3_PHY_PWRCTL_CLK_FREQ_MASK GENMASK(31, 22)
+#define PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 22
+
+#define PIPE3_PHY_RX_POWERON (0x1 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT)
+#define PIPE3_PHY_TX_POWERON (0x2 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT)
+
+/* PHY RX Registers */
+#define PIPE3_PHY_RX_ANA_PROGRAMMABILITY 0x0000000C
+#define INTERFACE_MASK GENMASK(31, 27)
+#define INTERFACE_SHIFT 27
+#define INTERFACE_MODE_USBSS BIT(4)
+#define INTERFACE_MODE_SATA_1P5 BIT(3)
+#define INTERFACE_MODE_SATA_3P0 BIT(2)
+#define INTERFACE_MODE_PCIE BIT(0)
+
+#define LOSD_MASK GENMASK(17, 14)
+#define LOSD_SHIFT 14
+#define MEM_PLLDIV GENMASK(6, 5)
+
+#define PIPE3_PHY_RX_TRIM 0x0000001C
+#define MEM_DLL_TRIM_SEL_MASK GENMASK(31, 30)
+#define MEM_DLL_TRIM_SHIFT 30
+
+#define PIPE3_PHY_RX_DLL 0x00000024
+#define MEM_DLL_PHINT_RATE_MASK GENMASK(31, 30)
+#define MEM_DLL_PHINT_RATE_SHIFT 30
+
+#define PIPE3_PHY_RX_DIGITAL_MODES 0x00000028
+#define MEM_HS_RATE_MASK GENMASK(28, 27)
+#define MEM_HS_RATE_SHIFT 27
+#define MEM_OVRD_HS_RATE BIT(26)
+#define MEM_OVRD_HS_RATE_SHIFT 26
+#define MEM_CDR_FASTLOCK BIT(23)
+#define MEM_CDR_FASTLOCK_SHIFT 23
+#define MEM_CDR_LBW_MASK GENMASK(22, 21)
+#define MEM_CDR_LBW_SHIFT 21
+#define MEM_CDR_STEPCNT_MASK GENMASK(20, 19)
+#define MEM_CDR_STEPCNT_SHIFT 19
+#define MEM_CDR_STL_MASK GENMASK(18, 16)
+#define MEM_CDR_STL_SHIFT 16
+#define MEM_CDR_THR_MASK GENMASK(15, 13)
+#define MEM_CDR_THR_SHIFT 13
+#define MEM_CDR_THR_MODE BIT(12)
+#define MEM_CDR_THR_MODE_SHIFT 12
+#define MEM_CDR_2NDO_SDM_MODE BIT(11)
+#define MEM_CDR_2NDO_SDM_MODE_SHIFT 11
+
+#define PIPE3_PHY_RX_EQUALIZER 0x00000038
+#define MEM_EQLEV_MASK GENMASK(31, 16)
+#define MEM_EQLEV_SHIFT 16
+#define MEM_EQFTC_MASK GENMASK(15, 11)
+#define MEM_EQFTC_SHIFT 11
+#define MEM_EQCTL_MASK GENMASK(10, 7)
+#define MEM_EQCTL_SHIFT 7
+#define MEM_OVRD_EQLEV BIT(2)
+#define MEM_OVRD_EQLEV_SHIFT 2
+#define MEM_OVRD_EQFTC BIT(1)
+#define MEM_OVRD_EQFTC_SHIFT 1
+
+#define SATA_PHY_RX_IO_AND_A2D_OVERRIDES 0x44
+#define MEM_CDR_LOS_SOURCE_MASK GENMASK(10, 9)
+#define MEM_CDR_LOS_SOURCE_SHIFT 9
+
+#define PLL_IDLE_TIME 100 /* in milliseconds */
+#define PLL_LOCK_TIME 100 /* in milliseconds */
+
+enum pipe3_mode { PIPE3_MODE_PCIE = 1,
+ PIPE3_MODE_SATA,
+ PIPE3_MODE_USBSS };
+
+struct pipe3_settings {
+ u8 ana_interface;
+ u8 ana_losd;
+ u8 dig_fastlock;
+ u8 dig_lbw;
+ u8 dig_stepcnt;
+ u8 dig_stl;
+ u8 dig_thr;
+ u8 dig_thr_mode;
+ u8 dig_2ndo_sdm_mode;
+ u8 dig_hs_rate;
+ u8 dig_ovrd_hs_rate;
+ u8 dll_trim_sel;
+ u8 dll_phint_rate;
+ u8 eq_lev;
+ u8 eq_ftc;
+ u8 eq_ctl;
+ u8 eq_ovrd_lev;
+ u8 eq_ovrd_ftc;
+};
+
+struct omap_pipe3 {
+ void __iomem *pll_ctrl_base;
+ void __iomem *phy_rx;
+ void __iomem *power_reg;
+ void __iomem *pll_reset_reg;
+ struct pipe3_dpll_map *dpll_map;
+ enum pipe3_mode mode;
+ struct pipe3_settings settings;
+};
+
+struct pipe3_dpll_params {
+ u16 m;
+ u8 n;
+ u8 freq:3;
+ u8 sd;
+ u32 mf;
+};
+
+struct pipe3_dpll_map {
+ unsigned long rate;
+ struct pipe3_dpll_params params;
+};
+
+struct pipe3_data {
+ enum pipe3_mode mode;
+ struct pipe3_dpll_map *dpll_map;
+ struct pipe3_settings settings;
+};
+
+static inline u32 omap_pipe3_readl(void __iomem *addr, unsigned offset)
+{
+ return readl(addr + offset);
+}
+
+static inline void omap_pipe3_writel(void __iomem *addr, unsigned offset,
+ u32 data)
+{
+ writel(data, addr + offset);
+}
+
+static struct pipe3_dpll_params *omap_pipe3_get_dpll_params(struct omap_pipe3
+ *pipe3)
+{
+ u32 rate;
+ struct pipe3_dpll_map *dpll_map = pipe3->dpll_map;
+
+ rate = get_sys_clk_freq();
+
+ for (; dpll_map->rate; dpll_map++) {
+ if (rate == dpll_map->rate)
+ return &dpll_map->params;
+ }
+
+ printf("%s: No DPLL configuration for %u Hz SYS CLK\n",
+ __func__, rate);
+ return NULL;
+}
+
+static int omap_pipe3_wait_lock(struct omap_pipe3 *pipe3)
+{
+ u32 val;
+ int timeout = PLL_LOCK_TIME;
+
+ do {
+ mdelay(1);
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
+ if (val & PLL_LOCK)
+ break;
+ } while (--timeout);
+
+ if (!(val & PLL_LOCK)) {
+ printf("%s: DPLL failed to lock\n", __func__);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int omap_pipe3_dpll_program(struct omap_pipe3 *pipe3)
+{
+ u32 val;
+ struct pipe3_dpll_params *dpll_params;
+
+ dpll_params = omap_pipe3_get_dpll_params(pipe3);
+ if (!dpll_params) {
+ printf("%s: Invalid DPLL parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION1);
+ val &= ~PLL_REGN_MASK;
+ val |= dpll_params->n << PLL_REGN_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION2);
+ val &= ~(PLL_SELFREQDCO_MASK | PLL_IDLE);
+ val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION1);
+ val &= ~PLL_REGM_MASK;
+ val |= dpll_params->m << PLL_REGM_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION4);
+ val &= ~PLL_REGM_F_MASK;
+ val |= dpll_params->mf << PLL_REGM_F_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION4, val);
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION3);
+ val &= ~PLL_SD_MASK;
+ val |= dpll_params->sd << PLL_SD_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION3, val);
+
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_GO, SET_PLL_GO);
+
+ return omap_pipe3_wait_lock(pipe3);
+}
+
+static void omap_control_pipe3_power(struct omap_pipe3 *pipe3, int on)
+{
+ u32 val, rate;
+
+ val = readl(pipe3->power_reg);
+
+ rate = get_sys_clk_freq();
+ rate = rate/1000000;
+
+ if (on) {
+ val &= ~(PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
+ PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
+ val |= rate << PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
+ writel(val, pipe3->power_reg);
+
+ /* Power up TX before RX for SATA & USB */
+ val |= PIPE3_PHY_TX_POWERON;
+ writel(val, pipe3->power_reg);
+
+ val |= PIPE3_PHY_RX_POWERON;
+ writel(val, pipe3->power_reg);
+ } else {
+ val &= ~PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
+ writel(val, pipe3->power_reg);
+ }
+}
+
+static void ti_pipe3_calibrate(struct omap_pipe3 *phy)
+{
+ u32 val;
+ struct pipe3_settings *s = &phy->settings;
+
+ val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY);
+ val &= ~(INTERFACE_MASK | LOSD_MASK | MEM_PLLDIV);
+ val = (s->ana_interface << INTERFACE_SHIFT | s->ana_losd << LOSD_SHIFT);
+ omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY, val);
+
+ val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES);
+ val &= ~(MEM_HS_RATE_MASK | MEM_OVRD_HS_RATE | MEM_CDR_FASTLOCK |
+ MEM_CDR_LBW_MASK | MEM_CDR_STEPCNT_MASK | MEM_CDR_STL_MASK |
+ MEM_CDR_THR_MASK | MEM_CDR_THR_MODE | MEM_CDR_2NDO_SDM_MODE);
+ val |= s->dig_hs_rate << MEM_HS_RATE_SHIFT |
+ s->dig_ovrd_hs_rate << MEM_OVRD_HS_RATE_SHIFT |
+ s->dig_fastlock << MEM_CDR_FASTLOCK_SHIFT |
+ s->dig_lbw << MEM_CDR_LBW_SHIFT |
+ s->dig_stepcnt << MEM_CDR_STEPCNT_SHIFT |
+ s->dig_stl << MEM_CDR_STL_SHIFT |
+ s->dig_thr << MEM_CDR_THR_SHIFT |
+ s->dig_thr_mode << MEM_CDR_THR_MODE_SHIFT |
+ s->dig_2ndo_sdm_mode << MEM_CDR_2NDO_SDM_MODE_SHIFT;
+ omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES, val);
+
+ val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_TRIM);
+ val &= ~MEM_DLL_TRIM_SEL_MASK;
+ val |= s->dll_trim_sel << MEM_DLL_TRIM_SHIFT;
+ omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_TRIM, val);
+
+ val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DLL);
+ val &= ~MEM_DLL_PHINT_RATE_MASK;
+ val |= s->dll_phint_rate << MEM_DLL_PHINT_RATE_SHIFT;
+ omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DLL, val);
+
+ val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER);
+ val &= ~(MEM_EQLEV_MASK | MEM_EQFTC_MASK | MEM_EQCTL_MASK |
+ MEM_OVRD_EQLEV | MEM_OVRD_EQFTC);
+ val |= s->eq_lev << MEM_EQLEV_SHIFT |
+ s->eq_ftc << MEM_EQFTC_SHIFT |
+ s->eq_ctl << MEM_EQCTL_SHIFT |
+ s->eq_ovrd_lev << MEM_OVRD_EQLEV_SHIFT |
+ s->eq_ovrd_ftc << MEM_OVRD_EQFTC_SHIFT;
+ omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER, val);
+
+ if (phy->mode == PIPE3_MODE_SATA) {
+ val = omap_pipe3_readl(phy->phy_rx,
+ SATA_PHY_RX_IO_AND_A2D_OVERRIDES);
+ val &= ~MEM_CDR_LOS_SOURCE_MASK;
+ omap_pipe3_writel(phy->phy_rx, SATA_PHY_RX_IO_AND_A2D_OVERRIDES,
+ val);
+ }
+}
+
+static int pipe3_init(struct phy *phy)
+{
+ int ret;
+ u32 val;
+ struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
+
+ /* Program the DPLL only if not locked */
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
+ if (!(val & PLL_LOCK)) {
+ ret = omap_pipe3_dpll_program(pipe3);
+ if (ret)
+ return ret;
+
+ ti_pipe3_calibrate(pipe3);
+ } else {
+ /* else just bring it out of IDLE mode */
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base,
+ PLL_CONFIGURATION2);
+ if (val & PLL_IDLE) {
+ val &= ~PLL_IDLE;
+ omap_pipe3_writel(pipe3->pll_ctrl_base,
+ PLL_CONFIGURATION2, val);
+ ret = omap_pipe3_wait_lock(pipe3);
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int pipe3_power_on(struct phy *phy)
+{
+ struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
+
+ /* Power up the PHY */
+ omap_control_pipe3_power(pipe3, 1);
+
+ return 0;
+}
+
+static int pipe3_power_off(struct phy *phy)
+{
+ struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
+
+ /* Power down the PHY */
+ omap_control_pipe3_power(pipe3, 0);
+
+ return 0;
+}
+
+static int pipe3_exit(struct phy *phy)
+{
+ u32 val;
+ int timeout = PLL_IDLE_TIME;
+ struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
+
+ pipe3_power_off(phy);
+
+ /* Put DPLL in IDLE mode */
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION2);
+ val |= PLL_IDLE;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+ /* wait for LDO and Oscillator to power down */
+ do {
+ mdelay(1);
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
+ if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
+ break;
+ } while (--timeout);
+
+ if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
+ pr_err("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n",
+ __func__, val);
+ return -EBUSY;
+ }
+
+ if (pipe3->pll_reset_reg) {
+ val = readl(pipe3->pll_reset_reg);
+ writel(val | SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg);
+ mdelay(1);
+ writel(val & ~SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg);
+ }
+
+ return 0;
+}
+
+static void *get_reg(struct udevice *dev, const char *name)
+{
+ struct udevice *syscon;
+ struct regmap *regmap;
+ const fdt32_t *cell;
+ int len, err;
+ void *base;
+
+ err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ name, &syscon);
+ if (err) {
+ pr_err("unable to find syscon device for %s (%d)\n",
+ name, err);
+ return NULL;
+ }
+
+ regmap = syscon_get_regmap(syscon);
+ if (IS_ERR(regmap)) {
+ pr_err("unable to find regmap for %s (%ld)\n",
+ name, PTR_ERR(regmap));
+ return NULL;
+ }
+
+ cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), name,
+ &len);
+ if (len < 2*sizeof(fdt32_t)) {
+ pr_err("offset not available for %s\n", name);
+ return NULL;
+ }
+
+ base = regmap_get_range(regmap, 0);
+ if (!base)
+ return NULL;
+
+ return fdtdec_get_number(cell + 1, 1) + base;
+}
+
+static int pipe3_phy_probe(struct udevice *dev)
+{
+ fdt_addr_t addr;
+ fdt_size_t sz;
+ struct omap_pipe3 *pipe3 = dev_get_priv(dev);
+ struct pipe3_data *data;
+
+ /* PHY_RX */
+ addr = devfdt_get_addr_size_index(dev, 0, &sz);
+ if (addr == FDT_ADDR_T_NONE) {
+ pr_err("missing phy_rx address\n");
+ return -EINVAL;
+ }
+
+ pipe3->phy_rx = map_physmem(addr, sz, MAP_NOCACHE);
+ if (!pipe3->phy_rx) {
+ pr_err("unable to remap phy_rx\n");
+ return -EINVAL;
+ }
+
+ /* PLLCTRL */
+ addr = devfdt_get_addr_size_index(dev, 2, &sz);
+ if (addr == FDT_ADDR_T_NONE) {
+ pr_err("missing pll ctrl address\n");
+ return -EINVAL;
+ }
+
+ pipe3->pll_ctrl_base = map_physmem(addr, sz, MAP_NOCACHE);
+ if (!pipe3->pll_ctrl_base) {
+ pr_err("unable to remap pll ctrl\n");
+ return -EINVAL;
+ }
+
+ pipe3->power_reg = get_reg(dev, "syscon-phy-power");
+ if (!pipe3->power_reg)
+ return -EINVAL;
+
+ data = (struct pipe3_data *)dev_get_driver_data(dev);
+ pipe3->mode = data->mode;
+ pipe3->dpll_map = data->dpll_map;
+ pipe3->settings = data->settings;
+
+ if (pipe3->mode == PIPE3_MODE_SATA) {
+ pipe3->pll_reset_reg = get_reg(dev, "syscon-pllreset");
+ if (!pipe3->pll_reset_reg)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct pipe3_dpll_map dpll_map_sata[] = {
+ {12000000, {625, 4, 4, 6, 0} }, /* 12 MHz */
+ {16800000, {625, 6, 4, 7, 0} }, /* 16.8 MHz */
+ {19200000, {625, 7, 4, 6, 0} }, /* 19.2 MHz */
+ {20000000, {750, 9, 4, 6, 0} }, /* 20 MHz */
+ {26000000, {750, 12, 4, 6, 0} }, /* 26 MHz */
+ {38400000, {625, 15, 4, 6, 0} }, /* 38.4 MHz */
+ { }, /* Terminator */
+};
+
+static struct pipe3_dpll_map dpll_map_usb[] = {
+ {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */
+ {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */
+ {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */
+ {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */
+ {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */
+ {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */
+ { }, /* Terminator */
+};
+
+static struct pipe3_data data_usb = {
+ .mode = PIPE3_MODE_USBSS,
+ .dpll_map = dpll_map_usb,
+ .settings = {
+ /* DRA75x TRM Table 26-17. Preferred USB3_PHY_RX SCP Register Settings */
+ .ana_interface = INTERFACE_MODE_USBSS,
+ .ana_losd = 0xa,
+ .dig_fastlock = 1,
+ .dig_lbw = 3,
+ .dig_stepcnt = 0,
+ .dig_stl = 0x3,
+ .dig_thr = 1,
+ .dig_thr_mode = 1,
+ .dig_2ndo_sdm_mode = 0,
+ .dig_hs_rate = 0,
+ .dig_ovrd_hs_rate = 1,
+ .dll_trim_sel = 0x2,
+ .dll_phint_rate = 0x3,
+ .eq_lev = 0,
+ .eq_ftc = 0,
+ .eq_ctl = 0x9,
+ .eq_ovrd_lev = 0,
+ .eq_ovrd_ftc = 0,
+ },
+};
+
+static struct pipe3_data data_sata = {
+ .mode = PIPE3_MODE_SATA,
+ .dpll_map = dpll_map_sata,
+ .settings = {
+ /* DRA75x TRM Table 26-9. Preferred SATA_PHY_RX SCP Register Settings */
+ .ana_interface = INTERFACE_MODE_SATA_3P0,
+ .ana_losd = 0x5,
+ .dig_fastlock = 1,
+ .dig_lbw = 3,
+ .dig_stepcnt = 0,
+ .dig_stl = 0x3,
+ .dig_thr = 1,
+ .dig_thr_mode = 1,
+ .dig_2ndo_sdm_mode = 0,
+ .dig_hs_rate = 0, /* Not in TRM preferred settings */
+ .dig_ovrd_hs_rate = 0, /* Not in TRM preferred settings */
+ .dll_trim_sel = 0x1,
+ .dll_phint_rate = 0x2, /* for 1.5 GHz DPLL clock */
+ .eq_lev = 0,
+ .eq_ftc = 0x1f,
+ .eq_ctl = 0,
+ .eq_ovrd_lev = 1,
+ .eq_ovrd_ftc = 1,
+ },
+};
+
+static const struct udevice_id pipe3_phy_ids[] = {
+ { .compatible = "ti,phy-pipe3-sata", .data = (ulong)&data_sata },
+ { .compatible = "ti,omap-usb3", .data = (ulong)&data_usb},
+ { }
+};
+
+static struct phy_ops pipe3_phy_ops = {
+ .init = pipe3_init,
+ .power_on = pipe3_power_on,
+ .power_off = pipe3_power_off,
+ .exit = pipe3_exit,
+};
+
+U_BOOT_DRIVER(pipe3_phy) = {
+ .name = "pipe3_phy",
+ .id = UCLASS_PHY,
+ .of_match = pipe3_phy_ids,
+ .ops = &pipe3_phy_ops,
+ .probe = pipe3_phy_probe,
+ .priv_auto = sizeof(struct omap_pipe3),
+};