From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A31D9442FB5 for ; Tue, 11 Aug 2026 12:47:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.46 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786452461; cv=none; b=gAXe3MQIE3tMUue1ueej2w7c08vIx0ecyaKvAJ6owNg1WUKxmoVlv3AlrXj4BfeGYOxR7rki4DMyOsXJIxUCTmSdUT9X9HJwvOkyFWObX6gFH+EdlAjv1TybD5z1+LkLWF/c7/6USqZYLZj6+kJheovP7M5cYudT2bV6PulLIOs= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786452461; c=relaxed/simple; bh=eVY0/QK3JH36s92EisYZv4hEQPylm9CJ5zjYgfetLY8=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GHktDXIaYVm7/TY6NNxDxYU7uwv5perT5JqBxEG+slPmK1FcWTJ3R5txLAQHY/yoOAPxwVgG3kB1tImRPEXI7I4tEKkKT+/yvMnUMUeZFVvLBwfCsyRdmALECw33jkdjui6VTqaC6aLCzO8pM9yh8rgAZ4NPSiwXZ4FuB7K54pY= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=AEPDM4td; arc=none smtp.client-ip=209.85.221.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="AEPDM4td" Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-47de008b020so575528f8f.1 for ; Tue, 11 Aug 2026 05:47:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786452455; x=1787057255; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=NRXmRcTAreGAjHcITrtW0V4393gZ1o/fGkImQb0anHM=; b=AEPDM4tdK3aGIt4/asiP/C1Hbwxv4uJWs8WCM+k2JNq6eOau24xcFXEpIvYRRxnBHQ 37t7ume6J4TFa1f09GYK9zMpcnJkvmIPPHiqkiXtFN7B02cMRddHdkq7OrBFpky4OKPv 0bd3eKBPXFYyUazEvJFKASBVynrUO7uX2ydnWCcs371snYUl/rvYw4BjPrThur5L5RXI Up4YoiPPk3ojVgqgWhxcswAa24udH9lg2Di/DmSzp7VEvMMAUrqVpUbfA1DQOORgQfJK FcoPtMdrQSaZTwG7XVuoMwyTazNF+bh3bkDqTTvqOXvRBdjUCC2tho3ZJI5Ol/zo6HM0 RtBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786452455; x=1787057255; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=NRXmRcTAreGAjHcITrtW0V4393gZ1o/fGkImQb0anHM=; b=DK8JMM5/gql+NqjZESbq3vAVvj88o91ORLGYSdcFgPljEOAEJAugjp4T2ZL7fqU/Fh 1Fa+W22jLYByyP4daISmqF0A5wntfO0MKajtGVxMlUKiAwelKvuroaiex0scXGHofjRg 90erH2If/lHpmz5UwZjcbiIw5djsoAkSQSe8H7yRVyxEBW2qVrstFSCGdBZFs0UYF7d/ JUKKAAGpbvak8WUZrpwqHltLzrk7OqQR4hPhq4Z20uBpqxrMb8OycCyQ4IEJayy1fJYn Mtnvkx51cJoESFIJj5Q3Q7Nq9psOxf4SLy+6uosaHXGKFLdIm3MeOi9jU91HvlMOXtSz N40g== X-Forwarded-Encrypted: i=1; AHgh+Ro10plyCNWH32QMva0Mf/xqHq97mzmK//HfPppBgDoWKMhaNbTOAne9r6Kw2sOWKhncivZ0bQkfWqE/69o=@vger.kernel.org X-Gm-Message-State: AOJu0YyuJKU+oZcjXlOgomayH3lKraoZKlq34f7MYSxA1YxQZRxHLeHj iXrXBn/900GGW27aJo1VgKEX7sxHt4Zu3ZH1roAAjZqkVe6nYT1h/0qUBP1r7bbi X-Gm-Gg: AR+sD13n5DxJwhWZPyfyo46fWhwp+MgyYoPHtS3vLN0m7BaXy89eFJISENN6e7flwru I4/8uHjkmZeWYfvL29NEQxPJRsCSNm1JG4cgo1Ne3yaZDOnPEZxBQ9U+fYZxutaKSCAqs6YigE3 2hEwePhWUBlpazOLNFZlH4YpzOAqhgntf3VrBZA0bha7vQhyBN656x72W4sEXkcJ1Qk7z3F+hxe LQAlgWF/xGlJk8XWDiMluYIAtLdCUVgy8lVkvBEpTiygDLzj4boqwBnu0ZW03tDQgQ/hFwr7NVr HECDmkWmfv9SxxqoYl2JONdOCzVyj8nlhIR1eVXcx5gSmex4u9oHkmuvLpWZifZcVtT6i2Cp/am OvFX2viVIialV2zog3FlfC4UTqk7jBmuBLTnqcwawIPahhiiAZOhp15ANiEhp98KLXeu4JsG2b/ 8FbRA7vB4Ye1aobGeDKoLCsX7ZaOC6E8o2wBOIT75CIkQmrtxdgdvAVvYdbvy1dsFDwPDup//ch EtCGRDDUdHTqdI9oW3ULKJrnu3f7f5TgqGJY4cRSL8Cktr2 X-Received: by 2002:a05:6000:490c:b0:47f:71a0:c060 with SMTP id ffacd0b85a97d-4814b4ef90cmr5081080f8f.2.1786452454497; Tue, 11 Aug 2026 05:47:34 -0700 (PDT) Received: from Ansuel-XPS24.localdomain (host-87-20-3-207.retail.telecomitalia.it. [87.20.3.207]) by smtp.googlemail.com with ESMTPSA id ffacd0b85a97d-4814a7165a3sm4118207f8f.26.2026.08.11.05.47.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 11 Aug 2026 05:47:33 -0700 (PDT) From: Christian Marangi To: Vinod Koul , Neil Armstrong , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Christian Marangi , linux-phy@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/2] phy: airoha: Add support for Airoha AN7583 USB PHY Date: Tue, 11 Aug 2026 14:47:23 +0200 Message-ID: <20260811124724.702467-3-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260811124724.702467-1-ansuelsmth@gmail.com> References: <20260811124724.702467-1-ansuelsmth@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Add support for USB PHY for Airoha AN7583 SoC, this share some U2 init from AN7581 but use a totally different init phase for PLL and calibration for U3. Also on AN7583 there is a single USB PHY that init 2 U2 port and one U3 port. (the USB controller expose 2 hub, one with 2 usb 2.0 port and one with one 3.0 port) A second USB PHY is used for PCIe Gen2 controller and follow the same calibration and setup logic of USB. Signed-off-by: Christian Marangi --- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 3 +- drivers/phy/airoha/Kconfig | 11 + drivers/phy/airoha/Makefile | 3 + drivers/phy/airoha/phy-an7583-usb.c | 2009 +++++++++++++++++++++++++++ 5 files changed, 2026 insertions(+), 1 deletion(-) create mode 100644 drivers/phy/airoha/Kconfig create mode 100644 drivers/phy/airoha/Makefile create mode 100644 drivers/phy/airoha/phy-an7583-usb.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 19f3b7d12b7d..80b7c50fd768 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -168,6 +168,7 @@ config PHY_XGENE help This option enables support for APM X-Gene SoC multi-purpose PHY. +source "drivers/phy/airoha/Kconfig" source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/apple/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index d7aa516bcc49..0baf0b7fd077 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -20,7 +20,8 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o -obj-$(CONFIG_GENERIC_PHY) += allwinner/ \ +obj-$(CONFIG_GENERIC_PHY) += airoha/ \ + allwinner/ \ amlogic/ \ apple/ \ axiado/ \ diff --git a/drivers/phy/airoha/Kconfig b/drivers/phy/airoha/Kconfig new file mode 100644 index 000000000000..13e49ff947e3 --- /dev/null +++ b/drivers/phy/airoha/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config PHY_AIROHA_AN7583_USB + tristate "Airoha AN7583 USB PHY Driver" + depends on ARCH_AIROHA || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Say 'Y' here to add support for Airoha AN7583 USB PHY driver. + This driver create the basic PHY instance and provides initialize + callback for USB port. diff --git a/drivers/phy/airoha/Makefile b/drivers/phy/airoha/Makefile new file mode 100644 index 000000000000..e484a803505b --- /dev/null +++ b/drivers/phy/airoha/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_PHY_AIROHA_AN7583_USB) += phy-an7583-usb.o diff --git a/drivers/phy/airoha/phy-an7583-usb.c b/drivers/phy/airoha/phy-an7583-usb.c new file mode 100644 index 000000000000..17394ab0e133 --- /dev/null +++ b/drivers/phy/airoha/phy-an7583-usb.c @@ -0,0 +1,2009 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Christian Marangi + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PHY */ +#define AIROHA_USB_PHY_FMCR0 0x100 +#define AIROHA_USB_PHY_MONCLK_SEL GENMASK(27, 26) +#define AIROHA_USB_PHY_MONCLK_SEL0 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x0) +#define AIROHA_USB_PHY_MONCLK_SEL1 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x1) +#define AIROHA_USB_PHY_MONCLK_SEL2 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x2) +#define AIROHA_USB_PHY_MONCLK_SEL3 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x3) +#define AIROHA_USB_PHY_FREQDET_EN BIT(24) +#define AIROHA_USB_PHY_CYCLECNT GENMASK(23, 0) +#define AIROHA_USB_PHY_FMMONR0 0x10c +#define AIROHA_USB_PHY_USB_FM_OUT GENMASK(31, 0) +#define AIROHA_USB_PHY_FMMONR1 0x110 +#define AIROHA_USB_PHY_FRCK_EN BIT(8) + +#define AIROHA_USB_PHY_USBPHYACR2 0x308 +#define AIROHA_USB_PHY_SIFSLV_MAC_BANDGAP_EN BIT(17) +#define AIROHA_USB_PHY_USBPHYACR4 0x310 +#define AIROHA_USB_PHY_USB20_FS_CR GENMASK(10, 8) +#define AIROHA_USB_PHY_USB20_FS_CR_MAX FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x0) +#define AIROHA_USB_PHY_USB20_FS_CR_NORMAL FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x2) +#define AIROHA_USB_PHY_USB20_FS_CR_SMALLER FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x4) +#define AIROHA_USB_PHY_USB20_FS_CR_MIN FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x6) +#define AIROHA_USB_PHY_USB20_FS_SR GENMASK(2, 0) +#define AIROHA_USB_PHY_USB20_FS_SR_MAX FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x0) +#define AIROHA_USB_PHY_USB20_FS_SR_NORMAL FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x2) +#define AIROHA_USB_PHY_USB20_FS_SR_SMALLER FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x4) +#define AIROHA_USB_PHY_USB20_FS_SR_MIN FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x6) +#define AIROHA_USB_PHY_USBPHYACR5 0x314 +#define AIROHA_USB_PHY_USB20_DISC_FIT_EN BIT(28) +#define AIROHA_USB_PHY_USB20_HSTX_SRCAL_EN BIT(15) +#define AIROHA_USB_PHY_USB20_HSTX_SRCTRL GENMASK(14, 12) +#define AIROHA_USB_PHY_USBPHYACR6 0x318 +#define AIROHA_USB_PHY_USB20_BC11_SW_EN BIT(23) +#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL GENMASK(10, 9) +#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_ENPLL \ + FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, 0x0) +#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_IDLEB_RCV_EN \ + FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, 0x1) +#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_NO_ENPLL_FS_BIAS_EN \ + FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, 0x2) +#define AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_USB20_HSRX_TMODE_EN \ + FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, 0x3) +#define AIROHA_USB_PHY_USB20_DISCTH GENMASK(7, 4) +#define AIROHA_USB_PHY_USB20_DISCTH_400 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x0) +#define AIROHA_USB_PHY_USB20_DISCTH_420 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x1) +#define AIROHA_USB_PHY_USB20_DISCTH_440 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x2) +#define AIROHA_USB_PHY_USB20_DISCTH_460 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x3) +#define AIROHA_USB_PHY_USB20_DISCTH_480 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x4) +#define AIROHA_USB_PHY_USB20_DISCTH_500 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x5) +#define AIROHA_USB_PHY_USB20_DISCTH_520 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x6) +#define AIROHA_USB_PHY_USB20_DISCTH_540 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x7) +#define AIROHA_USB_PHY_USB20_DISCTH_560 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x8) +#define AIROHA_USB_PHY_USB20_DISCTH_580 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x9) +#define AIROHA_USB_PHY_USB20_DISCTH_600 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xa) +#define AIROHA_USB_PHY_USB20_DISCTH_620 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xb) +#define AIROHA_USB_PHY_USB20_DISCTH_640 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xc) +#define AIROHA_USB_PHY_USB20_DISCTH_660 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xd) +#define AIROHA_USB_PHY_USB20_DISCTH_680 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xe) +#define AIROHA_USB_PHY_USB20_DISCTH_700 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xf) +#define AIROHA_USB_PHY_USB20_SQTH GENMASK(3, 0) +#define AIROHA_USB_PHY_USB20_SQTH_85 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x0) +#define AIROHA_USB_PHY_USB20_SQTH_90 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x1) +#define AIROHA_USB_PHY_USB20_SQTH_95 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x2) +#define AIROHA_USB_PHY_USB20_SQTH_100 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x3) +#define AIROHA_USB_PHY_USB20_SQTH_105 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x4) +#define AIROHA_USB_PHY_USB20_SQTH_110 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x5) +#define AIROHA_USB_PHY_USB20_SQTH_115 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x6) +#define AIROHA_USB_PHY_USB20_SQTH_120 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x7) +#define AIROHA_USB_PHY_USB20_SQTH_125 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x8) +#define AIROHA_USB_PHY_USB20_SQTH_130 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x9) +#define AIROHA_USB_PHY_USB20_SQTH_135 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xa) +#define AIROHA_USB_PHY_USB20_SQTH_140 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xb) +#define AIROHA_USB_PHY_USB20_SQTH_145 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xc) +#define AIROHA_USB_PHY_USB20_SQTH_150 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xd) +#define AIROHA_USB_PHY_USB20_SQTH_155 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xe) +#define AIROHA_USB_PHY_USB20_SQTH_160 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xf) + +#define AIROHA_USB_PHY_U2PHYACR3 0x31c +#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE GENMASK(25, 24) +#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_TOGGLE FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, 0x0) +#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_HS_TERM FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, 0x1) +#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_FORCE_DISABLE FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, 0x2) +#define AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_FORCE_ENABLE FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, 0x3) +#define AIROHA_USB_PHY_USB20_USB11_TMODE_EN BIT(19) +#define AIROHA_USB_PHY_USB20_TMODE_FS_LS_TX_EN BIT(18) +#define AIROHA_USB_PHY_USB20_PUPD_BIST_EN BIT(12) +#define AIROHA_USB_PHY_U2PHYDTM0 0x368 +#define AIROHA_USB_PHY_FORCE_XCVRSEL BIT(19) +#define AIROHA_USB_PHY_FORCE_SUSPENDDM BIT(18) +#define AIROHA_USB_PHY_FORCE_TERMSEL BIT(17) +#define AIROHA_USB_PHY_XCVRSEL GENMASK(5, 4) +#define AIROHA_USB_PHY_TERMSEL BIT(2) +#define AIROHA_USB_PHY_U2PHYDTM1 0x36c +#define AIROHA_USB_PHY_FORCE_IDDIG BIT(9) +#define AIROHA_USB_PHY_IDDIG BIT(1) + +#define AIROHA_USB_PHY_GPIO_CTLD 0x80c +#define AIROHA_USB_PHY_C60802_GPIO_CTLD GENMASK(31, 0) +#define AIROHA_USB_PHY_SSUSB_IP_SW_RST BIT(31) +#define AIROHA_USB_PHY_MCU_BUS_CK_GATE_EN BIT(30) +#define AIROHA_USB_PHY_FORCE_SSUSB_IP_SW_RST BIT(29) +#define AIROHA_USB_PHY_SSUSB_SW_RST BIT(28) + +#define AIROHA_USB_PHY_U3_PHYA_REG0 0xb00 +#define AIROHA_USB_PHY_SSUSB_BG_DIV GENMASK(29, 28) +#define AIROHA_USB_PHY_SSUSB_BG_DIV_2 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x0) +#define AIROHA_USB_PHY_SSUSB_BG_DIV_4 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x1) +#define AIROHA_USB_PHY_SSUSB_BG_DIV_8 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x2) +#define AIROHA_USB_PHY_SSUSB_BG_DIV_16 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x3) +#define AIROHA_USB_PHY_U3_PHYA_REG1 0xb04 +#define AIROHA_USB_PHY_SSUSB_XTAL_TOP_RESERVE GENMASK(25, 10) +#define AIROHA_USB_PHY_U3_PHYA_REG6 0xb18 +#define AIROHA_USB_PHY_SSUSB_CDR_RESERVE GENMASK(31, 24) +#define AIROHA_USB_PHY_U3_PHYA_REG8 0xb20 +#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY GENMASK(7, 6) +#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_32 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x0) +#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_64 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x1) +#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_128 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x2) +#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_216 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x3) + +#define AIROHA_USB_PHY_U3_PHYA_DA_REG19 0xc38 +#define AIROHA_USB_PHY_SSUSB_PLL_SSC_DELTA1_U3 GENMASK(15, 0) + +/* ANA */ +#define AIROHA_USB_ANA_RXAFE_RESERVE 0x4 +#define AIROHA_USB_ANA_CDR_PD_10B_EN BIT(11) +#define AIROHA_USB_ANA_CDR_PD_EDGE_DIS BIT(10) +#define AIROHA_USB_ANA_CDR_LPF_BOT_LIM 0x8 +#define AIROHA_USB_ANA_CDR_LPF_KP_GAIN GENMASK(26, 24) +#define AIROHA_USB_ANA_CDR_LPF_KI_GAIN GENMASK(22, 20) +#define AIROHA_USB_ANA_CDR_LPF_MJV_LIM 0xc +#define AIROHA_USB_ANA_CDR_LPF_RATIO GENMASK(5, 4) +#define AIROHA_USB_ANA_CDR_PR_CKREF_DIV1 0x18 +#define AIROHA_USB_ANA_CDR_PR_KBAND_DIV GENMASK(26, 24) +#define AIROHA_USB_ANA_CDR_PR_DAC_BAND GENMASK(12, 8) +#define AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG 0x1c +#define AIROHA_USB_ANA_CDR_PR_XFICK_EN BIT(30) +#define AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE BIT(6) +#define AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE GENMASK(5, 0) +#define AIROHA_USB_ANA_CDR_FORCE_IBANDLPF_R_OFF 0x20 +#define AIROHA_USB_ANA_CDR_PHYCK_RSTB BIT(13) +#define AIROHA_USB_ANA_QP_TX_MODE_16B_EN 0x28 +#define AIROHA_USB_QP_TX_RESERVE GENMASK(31, 16) +#define AIROHA_USB_ANA_TX_VLMON_EN BIT(2) +#define AIROHA_USB_ANA_TX_RESERVE_8 BIT(8) +#define AIROHA_USB_ANA_RXLBTX_EN 0x2c +#define AIROHA_USB_ANA_TX_DMEDGEGEN_EN BIT(27) +#define AIROHA_USB_ANA_TX_RXDET_METHOD BIT(25) +#define AIROHA_USB_ANA_SSUSB_BGR_EN 0x30 +#define AIROHA_USB_ANA_BIAS_V2V_CAL GENMASK(26, 21) +#define AIROHA_USB_ANA_SSUSB_BG_DIV GENMASK(3, 2) +#define AIROHA_USB_ANA_SSUSB_CHPEN BIT(1) +#define AIROHA_USB_ANA_CLKDRV_IMPSEL 0x34 +#define AIROHA_USB_ANA_PCIE_CLKDRV_AMP GENMASK(27, 25) +#define AIROHA_USB_ANA_PCIE_CLKDRV_FORCEIN GENMASK(24, 23) +#define AIROHA_USB_ANA_PCIE_CLKDRV_HZ BIT(14) +#define AIROHA_USB_ANA_PCIE_CLKDRV_RP GENMASK(13, 9) +#define AIROHA_USB_ANA_PCIE_CLKDRV_IMPSEL GENMASK(4, 0) +#define AIROHA_USB_ANA_TDC_FT_CK_EN 0x38 +#define AIROHA_USB_ANA_PLL_DEBUG_SEL BIT(19) +#define AIROHA_USB_ANA_VUSB10_ON BIT(8) +#define AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL 0x3c +#define AIROHA_USB_ANA_PLL_PREDIV GENMASK(26, 25) +#define AIROHA_USB_ANA_PLL_OSCAL_ENB BIT(19) +#define AIROHA_USB_ANA_PLL_MON_LDO_SEL GENMASK(18, 16) +#define AIROHA_USB_ANA_PLL_MONVC_EN BIT(14) +#define AIROHA_USB_ANA_PLL_LDOLPF_VSEL GENMASK(6, 5) +#define AIROHA_USB_ANA_PLL_SDM_ORD 0x40 +#define AIROHA_USB_ANA_PLL_SSC_TRI_EN BIT(4) +#define AIROHA_USB_ANA_PLL_SSC_PHASE_INI BIT(3) + +/* PMA */ +#define AIROHA_USB_PMA_TX_DA_CTRL_0 0x0 +#define AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER GENMASK(15, 12) +#define AIROHA_USB_PMA_RXDET_EN_WINDOW GENMASK(9, 4) +#define AIROHA_USB_PMA_TX_DA_CTRL_1 0x4 +#define AIROHA_USB_PMA_FORCE_TX_BIT_INVERSE BIT(7) +#define AIROHA_USB_PMA_TX_DA_CTRL_2 0x8 +#define AIROHA_USB_PMA_FORCE_TX_DEM_SEL BIT(27) +#define AIROHA_USB_PMA_TX_DA_CTRL_3 0xc +#define AIROHA_USB_PMA_TX_DATA_RATE_SEL GENMASK(30, 28) +#define AIROHA_USB_PMA_PON_RXFEDIG_CTRL_0 0x100 +#define AIROHA_USB_PMA_EQ_RX500M_CK_SEL BIT(12) +#define AIROHA_USB_PMA_PON_RXFEDIG_CTRL_8 0x120 +#define AIROHA_USB_PMA_QP_EQ_EYE_MASK GENMASK(9, 0) +#define AIROHA_USB_PMA_PON_RXFEDIG_CTRL_10 0x128 +#define AIROHA_USB_PMA_QP_EQ_PIEYE_INI GENMASK(22, 16) +#define AIROHA_USB_PMA_SS_LCPLL_PWCTL_SETTING_2 0x208 +#define AIROHA_USB_PMA_NCPO_ANA_MSB GENMASK(17, 16) +#define AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2 0x230 +#define AIROHA_USB_PMA_LCPLL_NCPO_VALUE GENMASK(30, 0) +#define AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_5 0x23c +#define AIROHA_USB_PMA_LCPLL_NCPO_CHG BIT(24) +#define AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1 0x248 +#define AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON GENMASK(30, 0) +#define AIROHA_USB_PMA_INTF_CTRL_5 0x314 +#define AIROHA_USB_PMA_RX_HZ_SEL BIT(5) +#define AIROHA_USB_PMA_RX_HZ_FORCE BIT(4) +#define AIROHA_USB_PMA_INTF_CTRL_6 0x318 +#define AIROHA_USB_PMA_TX_DATA_EN_SEL BIT(13) +#define AIROHA_USB_PMA_TX_DATA_EN_FORCE BIT(12) +#define AIROHA_USB_PMA_INTF_CTRL_7 0x31c +#define AIROHA_USB_PMA_PLL_EN_SEL BIT(5) +#define AIROHA_USB_PMA_PLL_EN_FORCE BIT(4) +#define AIROHA_USB_PMA_INTF_CTRL_8 0x320 +#define AIROHA_USB_PMA_XTAL_EXT_EN_SEL BIT(13) +#define AIROHA_USB_PMA_XTAL_EXT_EN_FORCE GENMASK(12, 11) +#define AIROHA_USB_PMA_TX_TERM_SEL_SEL BIT(7) +#define AIROHA_USB_PMA_TX_TERM_SEL_FORCE GENMASK(6, 5) +#define AIROHA_USB_PMA_INTF_STS_9 0x364 +#define AIROHA_USB_PMA_RX_IMP_SEL_SEL BIT(31) +#define AIROHA_USB_PMA_RX_IMP_SEL_FORCE GENMASK(30, 26) +#define AIROHA_USB_PMA_ADDR_INTF_STS_PLL_VCOCAL GENMASK(23, 16) +#define AIROHA_USB_PMA_PLL_CTRL_0 0x400 +#define AIROHA_USB_PMA_AUTO_INIT BIT(0) +#define AIROHA_USB_PMA_PLL_CTRL_1 0x404 +#define AIROHA_USB_PMA_PLL_SSC_EN BIT(30) +#define AIROHA_USB_PMA_PLL_CTRL_2 0x408 +#define AIROHA_USB_PMA_PLL_SDM_IFM_INTF BIT(30) +#define AIROHA_USB_PMA_PLL_RICO_SEL_INTF BIT(29) +#define AIROHA_USB_PMA_PLL_PHY_CK_EN_INTF BIT(27) +#define AIROHA_USB_PMA_PLL_PCK_SEL_INTF BIT(22) +#define AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF GENMASK(21, 20) +#define AIROHA_USB_PMA_PLL_IR_INTF GENMASK(19, 16) +#define AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF BIT(14) +#define AIROHA_USB_PMA_PLL_FBKSEL_INTF GENMASK(13, 12) +#define AIROHA_USB_PMA_PLL_BR_INTF GENMASK(10, 8) +#define AIROHA_USB_PMA_PLL_BPB_INTF GENMASK(7, 6) +#define AIROHA_USB_PMA_PLL_BPA_INTF GENMASK(4, 2) +#define AIROHA_USB_PMA_PLL_BC_INTF GENMASK(1, 0) +#define AIROHA_USB_PMA_PLL_CTRL_3 0x40c +#define AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF GENMASK(31, 16) +#define AIROHA_USB_PMA_PLL_SSC_DELTA_INTF GENMASK(15, 0) +#define AIROHA_USB_PMA_PLL_CTRL_4 0x410 +#define AIROHA_USB_PMA_PLL_SDM_HREN_INTF GENMASK(4, 3) +#define AIROHA_USB_PMA_PLL_ICOLP_EN_INTF BIT(2) +#define AIROHA_USB_PMA_PLL_CK_CTRL_0 0x414 +#define AIROHA_USB_PMA_PCIE_CLKTX_EN_INTF BIT(5) +#define AIROHA_USB_PMA_PCIE_CLKRX_EN_INTF BIT(4) +#define AIROHA_USB_PMA_PLL_CK_CTRL_1 0x418 +#define AIROHA_USB_PMA_PLL_FORCE_UNSTABLE BIT(19) +#define AIROHA_USB_PMA_PLL_FORCE_STABLE BIT(18) +#define AIROHA_USB_PMA_PLL_CK_CTRL_2 0x41c +#define AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_OFF_EN BIT(2) +#define AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_ON_EN BIT(1) +#define AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_EN BIT(0) +#define AIROHA_USB_PMA_RX_SYS_CTRL_0 0x600 +#define AIROHA_USB_PMA_ROC_CK_EN BIT(1) +#define AIROHA_USB_PMA_RX_DLY_0 0x614 +#define AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY GENMASK(7, 0) +#define AIROHA_USB_PMA_RX_CTRL_2 0x630 +#define AIROHA_USB_PMA_RX_EQ_EN_H_DLY GENMASK(28, 16) +#define AIROHA_USB_PMA_RX_CTRL_5 0x63c +#define AIROHA_USB_PMA_FREDET_CHK_CYCLE GENMASK(29, 10) +#define AIROHA_USB_PMA_RX_CTRL_6 0x640 +#define AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE GENMASK(19, 0) +#define AIROHA_USB_PMA_RX_CTRL_7 0x644 +#define AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE GENMASK(19, 0) +#define AIROHA_USB_PMA_RX_CTRL_10 0x650 +#define AIROHA_USB_PMA_CRSDET_RSTB BIT(1) +#define AIROHA_USB_PMA_RX_CTRL_11 0x654 +#define AIROHA_USB_PMA_FORCE_SIGDET_5G BIT(19) +#define AIROHA_USB_PMA_RX_CTRL_26 0x690 +#define AIROHA_USB_PMA_QP_EQ_RETRAIN_ONLY_EN BIT(26) +#define AIROHA_USB_PMA_LINK_ERRO_EN BIT(23) +#define AIROHA_USB_PMA_RX_CTRL_27 0x694 +#define AIROHA_USB_PMA_QP_LINK_ERRO_CNT GENMASK(31, 0) +#define AIROHA_USB_PMA_RX_CTRL_36 0x6b8 +#define AIROHA_USB_PMA_PCIE_USB_SYSTEM BIT(26) +#define AIROHA_USB_PMA_LCK2DATA_DLY_TIME GENMASK(23, 16) +#define AIROHA_USB_PMA_RX_CTRL_38 0x6C0 +#define AIROHA_USB_PMA_RESERVE_3 GENMASK(31, 24) +#define AIROHA_USB_PMA_RX_CTRL_45 0x6dc +#define AIROHA_USB_PMA_EQ_EN_DLY GENMASK(12, 0) +#define AIROHA_USB_PMA_RX_CTRL_46 0x6e0 +#define AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P3_TO_P0_EN BIT(29) +#define AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P2_TO_P0_EN BIT(28) +#define AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P1_TO_P0_EN BIT(27) +#define AIROHA_USB_PMA_REBACK_P0_LCK2REF_EN BIT(26) +#define AIROHA_USB_PMA_RX_CTRL_49 0x6ec +#define AIROHA_USB_PMA_LFPS_FINISH_TIME GENMASK(31, 21) +#define AIROHA_USB_PMA_RX_CTRL_50 0x6f0 +#define AIROHA_USB_PMA_P3_TO_P0_DO_EQ_USB BIT(28) +#define AIROHA_USB_PMA_P2_TO_P0_DO_EQ_USB BIT(27) +#define AIROHA_USB_PMA_P1_TO_P0_DO_EQ_USB BIT(26) +#define AIROHA_USB_PMA_EQ_EN_DLY_SHORT GENMASK(25, 13) +#define AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT GENMASK(12, 0) + +/* DIG */ +#define AIROHA_USB_DIG_CK_RST_CTRL_3 0x30c +#define AIROHA_USB_DIG_NS_CK_DIV_SEL BIT(25) +#define AIROHA_USB_DIG_US_CK_DIV_SEL BIT(24) +#define AIROHA_USB_DIG_MODE_CTRL_0 0x324 +#define AIROHA_USB_DIG_SGMII_AN_EN BIT(0) +#define AIROHA_USB_DIG_MODE_CTRL_1 0x330 +#define AIROHA_USB_DIG_TPHY_SPEED GENMASK(3, 2) +#define AIROHA_USB_DIG_CK_RST_CTRL_7 0x340 +#define AIROHA_USB_DIG_MULTI_USB2P5_EN BIT(26) +#define AIROHA_USB_DIG_MULTI_USB5_EN BIT(25) +#define AIROHA_USB_DIG_MULTI_PHY_USB_EN BIT(24) + +#define AIROHA_USB_PHY_U2_FM_DET_CYCLE_CNT 1024 +#define AIROHA_USB_PHY_REF_CK 20 +#define AIROHA_USB_PHY_U2_SR_COEF 28 +#define AIROHA_USB_PHY_U2_SR_COEF_DIVISOR 1000 + +#define AIROHA_USB_PHY_FREQDET_SLEEP 1000 /* 1ms */ +#define AIROHA_USB_PHY_FREQDET_TIMEOUT (AIROHA_USB_PHY_FREQDET_SLEEP * 10) + +#define AIROHA_USB_PHY_U3_MAX_CALIB_TRY 50 +#define AIROHA_USB_PHY_MAX_INSTANCE 3 +#define AIROHA_PCIE_PHY_MAX_INSTANCE 1 + +struct an7583_usb_phy_instance { + struct device_node *node; + u32 type; + + u32 offset; + unsigned int monclk_sel; + struct phy *serdes_phy; +}; + +enum an7583_usb_phy_regs { + AIROHA_USB_PHY_PHY, + AIROHA_USB_PHY_ANA, + AIROHA_USB_PHY_PMA, + AIROHA_USB_PHY_DIG, + + AIROHA_USB_PHY_REGS_MAX, +}; + +struct an7583_usb_phy_priv { + struct regmap *regs[AIROHA_USB_PHY_REGS_MAX]; + + struct phy *phys[AIROHA_USB_PHY_MAX_INSTANCE]; +}; + +struct an7583_usb_phy_match_data { + int max_instance; + const char * const *regs_name; + int regs_num; + int (*parse_subnode)(struct device *dev, + struct an7583_usb_phy_priv *priv, + int index, struct device_node *subnode); +}; + +static int an7583_usb_phy_u2_slew_rate_calibration(struct phy *phy) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + struct an7583_usb_phy_priv *priv; + struct device *dev; + u32 fm_out, srctrl; + u32 offset; + + dev = phy->dev.parent; + priv = dev_get_drvdata(dev); + offset = instance->offset; + + /* Enable HS TX SR calibration */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR5 + offset, + AIROHA_USB_PHY_USB20_HSTX_SRCAL_EN); + + usleep_range(1000, 1500); + + /* Enable Free run clock */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_FMMONR1 + offset, + AIROHA_USB_PHY_FRCK_EN); + + /* Select Monitor Clock */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_FMCR0 + offset, + AIROHA_USB_PHY_MONCLK_SEL, + FIELD_PREP(AIROHA_USB_PHY_MONCLK_SEL, + instance->monclk_sel)); + + /* Set cyclecnt */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_FMCR0 + offset, + AIROHA_USB_PHY_CYCLECNT, + FIELD_PREP(AIROHA_USB_PHY_CYCLECNT, + AIROHA_USB_PHY_U2_FM_DET_CYCLE_CNT)); + + /* Enable Frequency meter */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_FMCR0 + offset, + AIROHA_USB_PHY_FREQDET_EN); + + /* Timeout can happen and we will apply workaround at the end */ + regmap_read_poll_timeout(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_FMMONR0 + offset, + fm_out, fm_out, AIROHA_USB_PHY_FREQDET_SLEEP, + AIROHA_USB_PHY_FREQDET_TIMEOUT); + + /* Disable Frequency meter */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_FMCR0 + offset, + AIROHA_USB_PHY_FREQDET_EN); + + /* Disable Free run clock */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_FMMONR1 + offset, + AIROHA_USB_PHY_FRCK_EN); + + /* Disable HS TX SR calibration */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR5 + offset, + AIROHA_USB_PHY_USB20_HSTX_SRCAL_EN); + + usleep_range(1000, 1500); + + /* Frequency was not detected, use default SR calibration value */ + if (!fm_out) { + srctrl = 0x5; + dev_err(dev, "Frequency not detected, using default SR calibration.\n"); + /* (1024 / FM_OUT) * REF_CK * U2_SR_COEF (round to the nearest digits) */ + } else { + srctrl = AIROHA_USB_PHY_REF_CK * AIROHA_USB_PHY_U2_SR_COEF; + srctrl = (srctrl * AIROHA_USB_PHY_U2_FM_DET_CYCLE_CNT) / fm_out; + srctrl = DIV_ROUND_CLOSEST(srctrl, AIROHA_USB_PHY_U2_SR_COEF_DIVISOR); + dev_dbg(dev, "SR calibration applied: %x\n", srctrl); + } + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR5 + offset, + AIROHA_USB_PHY_USB20_HSTX_SRCTRL, + FIELD_PREP(AIROHA_USB_PHY_USB20_HSTX_SRCTRL, srctrl)); + + return 0; +} + +static bool an7583_usb_phy_u3_kband_is_calibrated(struct an7583_usb_phy_priv *priv) +{ + u32 val, res; + + /* Default ICO setting */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CTRL_4, + AIROHA_USB_PMA_PLL_ICOLP_EN_INTF); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_SSUSB_BGR_EN, + AIROHA_USB_ANA_BIAS_V2V_CAL, + FIELD_PREP(AIROHA_USB_ANA_BIAS_V2V_CAL, 0x15)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL, + AIROHA_USB_ANA_PLL_OSCAL_ENB | + AIROHA_USB_ANA_PLL_LDOLPF_VSEL, + AIROHA_USB_ANA_PLL_OSCAL_ENB | + FIELD_PREP(AIROHA_USB_ANA_PLL_LDOLPF_VSEL, 0x1)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_RICO_SEL_INTF); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_CTRL_8, + AIROHA_USB_PMA_XTAL_EXT_EN_SEL | + AIROHA_USB_PMA_XTAL_EXT_EN_FORCE); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF); + + /* Read KBand */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_TDC_FT_CK_EN, + AIROHA_USB_ANA_PLL_DEBUG_SEL); + + mdelay(5); + + regmap_read(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_STS_9, &val); + res = FIELD_GET(AIROHA_USB_PMA_ADDR_INTF_STS_PLL_VCOCAL, val) << 4; + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_TDC_FT_CK_EN, + AIROHA_USB_ANA_PLL_DEBUG_SEL); + + mdelay(5); + + regmap_read(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_STS_9, &val); + res |= FIELD_GET(AIROHA_USB_PMA_ADDR_INTF_STS_PLL_VCOCAL, val); + + /* + * KBand is calibrated if KBand Code is NOT 0xfff and + * KBand Done is set. + */ + return res != 0xfff && res & 0x800; +} + +static int an7583_usb_phy_u2_init(struct phy *phy) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + struct an7583_usb_phy_priv *priv; + struct device *dev; + u32 offset; + + dev = phy->dev.parent; + priv = dev_get_drvdata(dev); + offset = instance->offset; + + mdelay(1); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR4 + offset, + AIROHA_USB_PHY_USB20_FS_CR, + AIROHA_USB_PHY_USB20_FS_CR_MIN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR4 + offset, + AIROHA_USB_PHY_USB20_FS_SR, + AIROHA_USB_PHY_USB20_FS_SR_NORMAL); + + /* FIXME: evaluate if needed */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR6 + offset, + AIROHA_USB_PHY_USB20_SQTH, + AIROHA_USB_PHY_USB20_SQTH_125); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR6 + offset, + AIROHA_USB_PHY_USB20_DISCTH, + AIROHA_USB_PHY_USB20_DISCTH_580); + + /* Enable the USB port and then disable after calibration */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR6 + offset, + AIROHA_USB_PHY_USB20_BC11_SW_EN); + + an7583_usb_phy_u2_slew_rate_calibration(phy); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR6 + offset, + AIROHA_USB_PHY_USB20_BC11_SW_EN); + + usleep_range(1000, 1500); + + return 0; +} + +static int an7583_usb_phy_eth_init_sgmii(struct an7583_usb_phy_priv *priv) +{ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_27, + AIROHA_USB_PMA_QP_LINK_ERRO_CNT, + FIELD_PREP(AIROHA_USB_PMA_QP_LINK_ERRO_CNT, 0x100000)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1, + AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON, + FIELD_PREP(AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON, + 0x48000000)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_DIG], + AIROHA_USB_DIG_MODE_CTRL_1, + AIROHA_USB_DIG_TPHY_SPEED, + FIELD_PREP(AIROHA_USB_DIG_TPHY_SPEED, 0x0)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_PCK_SEL_INTF | + AIROHA_USB_PMA_PLL_IR_INTF, + AIROHA_USB_PMA_PLL_PCK_SEL_INTF | + FIELD_PREP(AIROHA_USB_PMA_PLL_IR_INTF, 0x4)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2, + AIROHA_USB_PMA_LCPLL_NCPO_VALUE, + FIELD_PREP(AIROHA_USB_PMA_LCPLL_NCPO_VALUE, 0x48000000)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_LPF_MJV_LIM, + AIROHA_USB_ANA_CDR_LPF_RATIO, + FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_RATIO, 0x2)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_CKREF_DIV1, + AIROHA_USB_ANA_CDR_PR_DAC_BAND, + FIELD_PREP(AIROHA_USB_ANA_CDR_PR_DAC_BAND, 0xc)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_LPF_BOT_LIM, + AIROHA_USB_ANA_CDR_LPF_KP_GAIN | + AIROHA_USB_ANA_CDR_LPF_KI_GAIN, + FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_KP_GAIN, 0x6) | + FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_KI_GAIN, 0x6)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_5, + AIROHA_USB_PMA_FREDET_CHK_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_CHK_CYCLE, 0x28)); + + return 0; +} + +static int an7583_usb_phy_eth_init_hsgmii(struct an7583_usb_phy_priv *priv) +{ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1, + AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON, + FIELD_PREP(AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON, + 0x7a000000)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_DIG], + AIROHA_USB_DIG_MODE_CTRL_1, + AIROHA_USB_DIG_TPHY_SPEED, + FIELD_PREP(AIROHA_USB_DIG_TPHY_SPEED, 0x1)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_PCK_SEL_INTF | + AIROHA_USB_PMA_PLL_IR_INTF, + AIROHA_USB_PMA_PLL_PCK_SEL_INTF | + FIELD_PREP(AIROHA_USB_PMA_PLL_IR_INTF, 0x6)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2, + AIROHA_USB_PMA_LCPLL_NCPO_VALUE, + FIELD_PREP(AIROHA_USB_PMA_LCPLL_NCPO_VALUE, 0x7a000000)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_LPF_MJV_LIM, + AIROHA_USB_ANA_CDR_LPF_RATIO, + FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_RATIO, 0x1)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_CKREF_DIV1, + AIROHA_USB_ANA_CDR_PR_DAC_BAND, + FIELD_PREP(AIROHA_USB_ANA_CDR_PR_DAC_BAND, 0xf)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_LPF_BOT_LIM, + AIROHA_USB_ANA_CDR_LPF_KP_GAIN | + AIROHA_USB_ANA_CDR_LPF_KI_GAIN, + FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_KP_GAIN, 0x5) | + FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_KI_GAIN, 0x5)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_5, + AIROHA_USB_PMA_FREDET_CHK_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_CHK_CYCLE, 0x10)); + + return 0; +} + +static int an7583_usb_phy_set_mode_eth(struct phy *phy, int submode) +{ + struct an7583_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent); + + /* TODO handle efuse */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_8, + AIROHA_USB_PMA_TX_TERM_SEL_SEL | + AIROHA_USB_PMA_TX_TERM_SEL_FORCE, + AIROHA_USB_PMA_TX_TERM_SEL_SEL | + FIELD_PREP(AIROHA_USB_PMA_TX_TERM_SEL_FORCE, 0x1)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_STS_9, + AIROHA_USB_PMA_RX_IMP_SEL_SEL | + AIROHA_USB_PMA_RX_IMP_SEL_FORCE, + AIROHA_USB_PMA_RX_IMP_SEL_SEL | + FIELD_PREP(AIROHA_USB_PMA_RX_IMP_SEL_FORCE, 0x1)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_26, + AIROHA_USB_PMA_QP_EQ_RETRAIN_ONLY_EN | + AIROHA_USB_PMA_LINK_ERRO_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_SSUSB_BGR_EN, + AIROHA_USB_ANA_SSUSB_BG_DIV, + FIELD_PREP(AIROHA_USB_ANA_SSUSB_BG_DIV, 0x1)); + + /* Digital CLK trigger reverse */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PON_RXFEDIG_CTRL_0, + AIROHA_USB_PMA_EQ_RX500M_CK_SEL); + + /* Common Setting */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_3, + AIROHA_USB_DIG_NS_CK_DIV_SEL | + AIROHA_USB_DIG_US_CK_DIV_SEL); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_1, + AIROHA_USB_PMA_FORCE_TX_BIT_INVERSE); + + /* TODO check they report 0x8400000 */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_2, + AIROHA_USB_PMA_FORCE_TX_DEM_SEL); + + /* PLL */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_BR_INTF | + AIROHA_USB_PMA_PLL_BPB_INTF | + AIROHA_USB_PMA_PLL_BPA_INTF | + AIROHA_USB_PMA_PLL_BC_INTF, + FIELD_PREP(AIROHA_USB_PMA_PLL_BR_INTF, 0x3) | + FIELD_PREP(AIROHA_USB_PMA_PLL_BPB_INTF, 0x0) | + FIELD_PREP(AIROHA_USB_PMA_PLL_BPA_INTF, 0x5) | + FIELD_PREP(AIROHA_USB_PMA_PLL_BC_INTF, 0x1)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL, + AIROHA_USB_ANA_PLL_PREDIV, + FIELD_PREP(AIROHA_USB_ANA_PLL_PREDIV, 0x1)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4, + AIROHA_USB_PMA_PLL_ICOLP_EN_INTF); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_MODE_CTRL_0, + AIROHA_USB_DIG_SGMII_AN_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXLBTX_EN, + AIROHA_USB_ANA_TX_DMEDGEGEN_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_QP_TX_MODE_16B_EN, + FIELD_PREP(AIROHA_USB_QP_TX_RESERVE, + AIROHA_USB_ANA_TX_RESERVE_8 | + AIROHA_USB_ANA_TX_VLMON_EN)); + + if (submode == PHY_INTERFACE_MODE_2500BASEX) + an7583_usb_phy_eth_init_hsgmii(priv); + else + an7583_usb_phy_eth_init_sgmii(priv); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_5, + AIROHA_USB_PMA_LCPLL_NCPO_CHG); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_5, + AIROHA_USB_PMA_LCPLL_NCPO_CHG); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_PWCTL_SETTING_2, + AIROHA_USB_PMA_NCPO_ANA_MSB, + FIELD_PREP(AIROHA_USB_PMA_NCPO_ANA_MSB, 0x1)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_RXAFE_RESERVE, + AIROHA_USB_ANA_CDR_PD_10B_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PON_RXFEDIG_CTRL_10, + AIROHA_USB_PMA_QP_EQ_PIEYE_INI, + FIELD_PREP(AIROHA_USB_PMA_QP_EQ_PIEYE_INI, 0x0)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PON_RXFEDIG_CTRL_8, + AIROHA_USB_PMA_QP_EQ_EYE_MASK, + FIELD_PREP(AIROHA_USB_PMA_QP_EQ_EYE_MASK, 0x2aa)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_6, + AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE, 0x64)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_7, + AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE, 0x2710)); + + /* PLL auto init */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0, + AIROHA_USB_PMA_AUTO_INIT); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0, + AIROHA_USB_PMA_AUTO_INIT); + + usleep_range(100, 200); + + return 0; +} + +static void an7583_usb_phy_tx_pll_enable(struct an7583_usb_phy_priv *priv) +{ + /* PLL Reset to default */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL, + AIROHA_USB_ANA_PLL_MON_LDO_SEL | + AIROHA_USB_ANA_PLL_MONVC_EN); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_CTRL_7, + AIROHA_USB_PMA_PLL_EN_SEL | + AIROHA_USB_PMA_PLL_EN_FORCE); + + /* PLL Auto Mode (For PMA) */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CK_CTRL_1, + AIROHA_USB_PMA_PLL_FORCE_UNSTABLE); + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CK_CTRL_1, + AIROHA_USB_PMA_PLL_FORCE_STABLE); + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CK_CTRL_1, + AIROHA_USB_PMA_PLL_FORCE_UNSTABLE); + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CK_CTRL_1, + AIROHA_USB_PMA_PLL_FORCE_STABLE); + + /* TX Auto Mode */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_6, + AIROHA_USB_PMA_TX_DATA_EN_FORCE); + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_6, + AIROHA_USB_PMA_TX_DATA_EN_SEL); + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_6, + AIROHA_USB_PMA_TX_DATA_EN_FORCE); +} + +static void an7583_usb_phy_kband_calibrate(struct an7583_usb_phy_priv *priv) +{ + /* PLL Disable */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_CTRL_8, + AIROHA_USB_PMA_XTAL_EXT_EN_SEL | + AIROHA_USB_PMA_XTAL_EXT_EN_FORCE, + AIROHA_USB_PMA_XTAL_EXT_EN_SEL | + FIELD_PREP(AIROHA_USB_PMA_XTAL_EXT_EN_FORCE, 0x3)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_CTRL_7, + AIROHA_USB_PMA_PLL_EN_SEL | + AIROHA_USB_PMA_PLL_EN_FORCE, + AIROHA_USB_PMA_PLL_EN_SEL); + + /* PLL Config for CPR */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CTRL_4, + AIROHA_USB_PMA_PLL_ICOLP_EN_INTF); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_SSUSB_BGR_EN, + AIROHA_USB_ANA_BIAS_V2V_CAL, + FIELD_PREP(AIROHA_USB_ANA_BIAS_V2V_CAL, 0x0)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL, + AIROHA_USB_ANA_PLL_OSCAL_ENB | + AIROHA_USB_ANA_PLL_LDOLPF_VSEL, + FIELD_PREP(AIROHA_USB_ANA_PLL_LDOLPF_VSEL, 0x3)); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_RICO_SEL_INTF | + AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL, + AIROHA_USB_ANA_PLL_MON_LDO_SEL | + AIROHA_USB_ANA_PLL_MONVC_EN, + FIELD_PREP(AIROHA_USB_ANA_PLL_MON_LDO_SEL, 0x3) | + AIROHA_USB_ANA_PLL_MONVC_EN); + + /* PLL Enable */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_CTRL_7, + AIROHA_USB_PMA_PLL_EN_SEL | + AIROHA_USB_PMA_PLL_EN_FORCE); +} + +static int an7583_usb_phy_u3_init(struct phy *phy) +{ + struct an7583_usb_phy_priv *priv; + struct device *dev; + + dev = phy->dev.parent; + priv = dev_get_drvdata(dev); + + /* Digital CLK trigger reverse */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PON_RXFEDIG_CTRL_0, + AIROHA_USB_PMA_EQ_RX500M_CK_SEL); + + /* RX USB PCIE enable */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_36, + AIROHA_USB_PMA_PCIE_USB_SYSTEM); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_SYS_CTRL_0, + AIROHA_USB_PMA_ROC_CK_EN); + + /* 50MHz XTAL */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_SSUSB_BGR_EN, + AIROHA_USB_ANA_SSUSB_BG_DIV | + AIROHA_USB_ANA_SSUSB_CHPEN, + FIELD_PREP(AIROHA_USB_ANA_SSUSB_BG_DIV, 0x1) | + AIROHA_USB_ANA_SSUSB_CHPEN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL, + AIROHA_USB_ANA_PLL_PREDIV, + FIELD_PREP(AIROHA_USB_ANA_PLL_PREDIV, 0x1)); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4, + AIROHA_USB_PMA_PLL_ICOLP_EN_INTF); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_7, + AIROHA_USB_DIG_MULTI_USB2P5_EN | + AIROHA_USB_DIG_MULTI_USB5_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_7, + AIROHA_USB_DIG_MULTI_USB2P5_EN | + AIROHA_USB_DIG_MULTI_USB5_EN | + AIROHA_USB_DIG_MULTI_PHY_USB_EN); + + /* PLL */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_PHY_CK_EN_INTF | + AIROHA_USB_PMA_PLL_PCK_SEL_INTF | + AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF | + AIROHA_USB_PMA_PLL_IR_INTF | + AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF | + AIROHA_USB_PMA_PLL_FBKSEL_INTF | + AIROHA_USB_PMA_PLL_BPB_INTF | + AIROHA_USB_PMA_PLL_BPA_INTF | + AIROHA_USB_PMA_PLL_BC_INTF, + AIROHA_USB_PMA_PLL_PHY_CK_EN_INTF | + AIROHA_USB_PMA_PLL_PCK_SEL_INTF | + FIELD_PREP(AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF, 0x0) | + FIELD_PREP(AIROHA_USB_PMA_PLL_IR_INTF, 0x4) | + AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF | + FIELD_PREP(AIROHA_USB_PMA_PLL_FBKSEL_INTF, 0x0) | + FIELD_PREP(AIROHA_USB_PMA_PLL_BPB_INTF, 0x1) | + FIELD_PREP(AIROHA_USB_PMA_PLL_BPA_INTF, 0x5) | + FIELD_PREP(AIROHA_USB_PMA_PLL_BC_INTF, 0x3)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4, + AIROHA_USB_PMA_PLL_SDM_HREN_INTF, + FIELD_PREP(AIROHA_USB_PMA_PLL_SDM_HREN_INTF, 0x1)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_SDM_IFM_INTF); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_3, + AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF | + AIROHA_USB_PMA_PLL_SSC_DELTA_INTF, + FIELD_PREP(AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF, 0x18c) | + FIELD_PREP(AIROHA_USB_PMA_PLL_SSC_DELTA_INTF, 0x21e)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_1, + AIROHA_USB_PMA_PLL_SSC_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1, + AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON, + FIELD_PREP(AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON, + 0x48000000)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_PWCTL_SETTING_2, + AIROHA_USB_PMA_NCPO_ANA_MSB, + FIELD_PREP(AIROHA_USB_PMA_NCPO_ANA_MSB, 0x1)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2, + AIROHA_USB_PMA_LCPLL_NCPO_VALUE, + FIELD_PREP(AIROHA_USB_PMA_LCPLL_NCPO_VALUE, 0x48000000)); + + /* RX 5G */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_LPF_MJV_LIM, + AIROHA_USB_ANA_CDR_LPF_RATIO, + FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_RATIO, 0x0)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_RXAFE_RESERVE, + AIROHA_USB_ANA_CDR_PD_10B_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_CKREF_DIV1, + AIROHA_USB_ANA_CDR_PR_DAC_BAND, + FIELD_PREP(AIROHA_USB_ANA_CDR_PR_DAC_BAND, 0xc)); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_FORCE_IBANDLPF_R_OFF, + AIROHA_USB_ANA_CDR_PHYCK_RSTB); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG, + AIROHA_USB_ANA_CDR_PR_XFICK_EN | + AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE, + AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_CKREF_DIV1, + AIROHA_USB_ANA_CDR_PR_KBAND_DIV, + FIELD_PREP(AIROHA_USB_ANA_CDR_PR_KBAND_DIV, 0x3)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG, + AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE, + FIELD_PREP(AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE, 0x19)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_46, + AIROHA_USB_PMA_REBACK_P0_LCK2REF_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_49, + AIROHA_USB_PMA_LFPS_FINISH_TIME, + FIELD_PREP(AIROHA_USB_PMA_LFPS_FINISH_TIME, 0x1f0)); + + /* EQ all */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_50, + AIROHA_USB_PMA_P3_TO_P0_DO_EQ_USB | + AIROHA_USB_PMA_P2_TO_P0_DO_EQ_USB | + AIROHA_USB_PMA_P1_TO_P0_DO_EQ_USB); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_46, + AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P3_TO_P0_EN | + AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P2_TO_P0_EN | + AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P1_TO_P0_EN); + + /* FIXME: ask Airoha why reserve7 is at 6c4 NOT 6c0 */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_38, + FIELD_PREP(AIROHA_USB_PMA_RESERVE_3, BIT(7))); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_11, + AIROHA_USB_PMA_FORCE_SIGDET_5G); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_36, + AIROHA_USB_PMA_LCK2DATA_DLY_TIME, + FIELD_PREP(AIROHA_USB_PMA_LCK2DATA_DLY_TIME, 0x2)); + + /* PI Cal */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_DLY_0, + AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY, + FIELD_PREP(AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY, 0x10)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_PLL_SDM_ORD, + AIROHA_USB_ANA_PLL_SSC_TRI_EN | + AIROHA_USB_ANA_PLL_SSC_PHASE_INI); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_3, + AIROHA_USB_PMA_TX_DATA_RATE_SEL); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXAFE_RESERVE, + AIROHA_USB_ANA_CDR_PD_EDGE_DIS); + + /* Common Setting */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_3, + AIROHA_USB_DIG_NS_CK_DIV_SEL | + AIROHA_USB_DIG_US_CK_DIV_SEL); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_0, + AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER | + AIROHA_USB_PMA_RXDET_EN_WINDOW, + FIELD_PREP(AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER, 0x4) | + FIELD_PREP(AIROHA_USB_PMA_RXDET_EN_WINDOW, 0xa)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXLBTX_EN, + AIROHA_USB_ANA_TX_DMEDGEGEN_EN | + AIROHA_USB_ANA_TX_RXDET_METHOD, + AIROHA_USB_ANA_TX_DMEDGEGEN_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CK_CTRL_2, + AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_OFF_EN | + AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_ON_EN | + AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_EN); + + /* RX Speed Up */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_5, + AIROHA_USB_PMA_FREDET_CHK_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_CHK_CYCLE, 0x28)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_6, + AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE, 0x64)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_7, + AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE, 0x2710)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_2, + AIROHA_USB_PMA_RX_EQ_EN_H_DLY, + FIELD_PREP(AIROHA_USB_PMA_RX_EQ_EN_H_DLY, 0x9c4)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_45, + AIROHA_USB_PMA_EQ_EN_DLY, + FIELD_PREP(AIROHA_USB_PMA_EQ_EN_DLY, 0x9c4)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_50, + AIROHA_USB_PMA_EQ_EN_DLY_SHORT | + AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT, + FIELD_PREP(AIROHA_USB_PMA_EQ_EN_DLY_SHORT, 0x9c4) | + FIELD_PREP(AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT, 0x9c4)); + + /* TCL avoid LT noice impact */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_QP_TX_MODE_16B_EN, + AIROHA_USB_ANA_TX_RESERVE_8); + + /* PLL auto init */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0, + AIROHA_USB_PMA_AUTO_INIT); + + usleep_range(100, 300); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CK_CTRL_2, + AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_EN); + + if (!an7583_usb_phy_u3_kband_is_calibrated(priv)) { + int i; + + /* TX Force Disable */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_CTRL_6, + AIROHA_USB_PMA_TX_DATA_EN_SEL | + AIROHA_USB_PMA_TX_DATA_EN_FORCE, + AIROHA_USB_PMA_TX_DATA_EN_SEL); + + /* PLL Force Unstable */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CK_CTRL_1, + AIROHA_USB_PMA_PLL_FORCE_UNSTABLE); + + for (i = 0; i < AIROHA_USB_PHY_U3_MAX_CALIB_TRY; i++) { + an7583_usb_phy_kband_calibrate(priv); + + /* Exit as soon as we manage to calibrate */ + if (an7583_usb_phy_u3_kband_is_calibrated(priv)) + break; + } + } + + an7583_usb_phy_tx_pll_enable(priv); + + return !an7583_usb_phy_u3_kband_is_calibrated(priv) ? -EINVAL : 0; +} + +static int an7583_usb_phy_pcie_init(struct phy *phy) +{ + struct an7583_usb_phy_priv *priv; + struct device *dev; + int i; + + dev = phy->dev.parent; + priv = dev_get_drvdata(dev); + + /* TX Force Disable */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_CTRL_6, + AIROHA_USB_PMA_TX_DATA_EN_SEL | + AIROHA_USB_PMA_TX_DATA_EN_FORCE, + AIROHA_USB_PMA_TX_DATA_EN_SEL); + + /* PLL Force Unstable */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_PLL_CK_CTRL_1, + AIROHA_USB_PMA_PLL_FORCE_UNSTABLE); + + /* PLL Disable */ + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0, + AIROHA_USB_PMA_AUTO_INIT); + + usleep_range(1000, 1500); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0, + AIROHA_USB_PMA_AUTO_INIT); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_CTRL_7, + AIROHA_USB_PMA_PLL_EN_SEL | + AIROHA_USB_PMA_PLL_EN_FORCE, + AIROHA_USB_PMA_PLL_EN_SEL); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_36, + AIROHA_USB_PMA_PCIE_USB_SYSTEM); + + /* 50MHz XTAL */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_SSUSB_BGR_EN, + AIROHA_USB_ANA_SSUSB_BG_DIV, + FIELD_PREP(AIROHA_USB_ANA_SSUSB_BG_DIV, 0x1)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_PLL_IPLL_DIG_PWR_SEL, + AIROHA_USB_ANA_PLL_PREDIV, + FIELD_PREP(AIROHA_USB_ANA_PLL_PREDIV, 0x1)); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4, + AIROHA_USB_PMA_PLL_ICOLP_EN_INTF); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_7, + AIROHA_USB_DIG_MULTI_USB2P5_EN | + AIROHA_USB_DIG_MULTI_USB5_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_7, + AIROHA_USB_DIG_MULTI_USB2P5_EN | + AIROHA_USB_DIG_MULTI_USB5_EN | + AIROHA_USB_DIG_MULTI_PHY_USB_EN); + + /* PLL RG */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_PHY_CK_EN_INTF | + AIROHA_USB_PMA_PLL_PCK_SEL_INTF | + AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF | + AIROHA_USB_PMA_PLL_IR_INTF | + AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF | + AIROHA_USB_PMA_PLL_FBKSEL_INTF | + AIROHA_USB_PMA_PLL_BPB_INTF | + AIROHA_USB_PMA_PLL_BPA_INTF | + AIROHA_USB_PMA_PLL_BC_INTF, + AIROHA_USB_PMA_PLL_PCK_SEL_INTF | + FIELD_PREP(AIROHA_USB_PMA_PLL_KBAND_PREDIV_INTF, 0x0) | + FIELD_PREP(AIROHA_USB_PMA_PLL_IR_INTF, 0x4) | + AIROHA_USB_PMA_PLL_ICOIQ_EN_INTF | + FIELD_PREP(AIROHA_USB_PMA_PLL_FBKSEL_INTF, 0x0) | + FIELD_PREP(AIROHA_USB_PMA_PLL_BPB_INTF, 0x1) | + FIELD_PREP(AIROHA_USB_PMA_PLL_BPA_INTF, 0x5) | + FIELD_PREP(AIROHA_USB_PMA_PLL_BC_INTF, 0x3)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_4, + AIROHA_USB_PMA_PLL_SDM_HREN_INTF, + FIELD_PREP(AIROHA_USB_PMA_PLL_SDM_HREN_INTF, 0x1)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_2, + AIROHA_USB_PMA_PLL_SDM_IFM_INTF); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_3, + AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF | + AIROHA_USB_PMA_PLL_SSC_DELTA_INTF, + FIELD_PREP(AIROHA_USB_PMA_PLL_SSC_PERIOD_INTF, 0x91c) | + FIELD_PREP(AIROHA_USB_PMA_PLL_SSC_DELTA_INTF, 0x1fd)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_1, + AIROHA_USB_PMA_PLL_SSC_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_TDC_PCW_1, + AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON, + FIELD_PREP(AIROHA_USB_PMA_LCPLL_PON_HRDDS_PCW_NCPO_GPON, + 0x48000000)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_PWCTL_SETTING_2, + AIROHA_USB_PMA_NCPO_ANA_MSB, + FIELD_PREP(AIROHA_USB_PMA_NCPO_ANA_MSB, 0x1)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_SS_LCPLL_TDC_FLT_2, + AIROHA_USB_PMA_LCPLL_NCPO_VALUE, + FIELD_PREP(AIROHA_USB_PMA_LCPLL_NCPO_VALUE, 0x48000000)); + + /* RX RG */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_LPF_MJV_LIM, + AIROHA_USB_ANA_CDR_LPF_RATIO, + FIELD_PREP(AIROHA_USB_ANA_CDR_LPF_RATIO, 0x1)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_RXAFE_RESERVE, + AIROHA_USB_ANA_CDR_PD_10B_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_CKREF_DIV1, + AIROHA_USB_ANA_CDR_PR_DAC_BAND, + FIELD_PREP(AIROHA_USB_ANA_CDR_PR_DAC_BAND, 0xc)); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_FORCE_IBANDLPF_R_OFF, + AIROHA_USB_ANA_CDR_PHYCK_RSTB); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG, + AIROHA_USB_ANA_CDR_PR_XFICK_EN | + AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE, + AIROHA_USB_ANA_CDR_PR_KBAND_PCIE_MODE); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_CKREF_DIV1, + AIROHA_USB_ANA_CDR_PR_KBAND_DIV, + FIELD_PREP(AIROHA_USB_ANA_CDR_PR_KBAND_DIV, 0x3)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], + AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE_REG, + AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE, + FIELD_PREP(AIROHA_USB_ANA_CDR_PR_KBAND_DIV_PCIE, 0x19)); + + /* Init L0/L0S U0/U1 */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_46, + AIROHA_USB_PMA_REBACK_P0_LCK2REF_EN | + AIROHA_USB_PMA_PCIE_USB_BYPASS_EQ_P1_TO_P0_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_11, + AIROHA_USB_PMA_FORCE_SIGDET_5G); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_36, + AIROHA_USB_PMA_LCK2DATA_DLY_TIME, + FIELD_PREP(AIROHA_USB_PMA_LCK2DATA_DLY_TIME, 0x2)); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXAFE_RESERVE, + AIROHA_USB_ANA_CDR_PD_EDGE_DIS); + + /* PI Calibration */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_DLY_0, + AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY, + FIELD_PREP(AIROHA_USB_PMA_RX_PI_CAL_EN_H_DLY, 0x10)); + + /* CRS detect and CLK TRX Control */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_10, + AIROHA_USB_PMA_CRSDET_RSTB); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_PLL_SDM_ORD, + AIROHA_USB_ANA_PLL_SSC_TRI_EN | + AIROHA_USB_ANA_PLL_SSC_PHASE_INI); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CK_CTRL_0, + AIROHA_USB_PMA_PCIE_CLKTX_EN_INTF | + AIROHA_USB_PMA_PCIE_CLKRX_EN_INTF, + AIROHA_USB_PMA_PCIE_CLKTX_EN_INTF); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_CLKDRV_IMPSEL, + AIROHA_USB_ANA_PCIE_CLKDRV_AMP | + AIROHA_USB_ANA_PCIE_CLKDRV_FORCEIN | + AIROHA_USB_ANA_PCIE_CLKDRV_HZ | + AIROHA_USB_ANA_PCIE_CLKDRV_RP | + AIROHA_USB_ANA_PCIE_CLKDRV_IMPSEL, + FIELD_PREP(AIROHA_USB_ANA_PCIE_CLKDRV_AMP, 0x4) | + FIELD_PREP(AIROHA_USB_ANA_PCIE_CLKDRV_FORCEIN, 0x1) | + FIELD_PREP(AIROHA_USB_ANA_PCIE_CLKDRV_RP, 0xc) | + FIELD_PREP(AIROHA_USB_ANA_PCIE_CLKDRV_IMPSEL, 0x12)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_3, + AIROHA_USB_PMA_TX_DATA_RATE_SEL, + FIELD_PREP(AIROHA_USB_PMA_TX_DATA_RATE_SEL, 0x1)); + + /* Common Setting */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_DIG], AIROHA_USB_DIG_CK_RST_CTRL_3, + AIROHA_USB_DIG_NS_CK_DIV_SEL | + AIROHA_USB_DIG_US_CK_DIV_SEL); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_TX_DA_CTRL_0, + AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER | + AIROHA_USB_PMA_RXDET_EN_WINDOW, + FIELD_PREP(AIROHA_USB_PMA_RXDET_RD_WAIT_TIMER, 0x4) | + FIELD_PREP(AIROHA_USB_PMA_RXDET_EN_WINDOW, 0xa)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_RXLBTX_EN, + AIROHA_USB_ANA_TX_DMEDGEGEN_EN | + AIROHA_USB_ANA_TX_RXDET_METHOD, + AIROHA_USB_ANA_TX_DMEDGEGEN_EN); + + /* PLL auto ON/OFF at L2/U3 state */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CK_CTRL_2, + AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_OFF_EN | + AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_ON_EN | + AIROHA_USB_PMA_PCIE_MODE_PLL_AUTO_EN); + + /* RX speed up */ + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_5, + AIROHA_USB_PMA_FREDET_CHK_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_CHK_CYCLE, 0x28)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_6, + AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_GOLDEN_CYCLE, 0x64)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_7, + AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE, + FIELD_PREP(AIROHA_USB_PMA_FREDET_TOLERATE_CYCLE, 0x2710)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_2, + AIROHA_USB_PMA_RX_EQ_EN_H_DLY, + FIELD_PREP(AIROHA_USB_PMA_RX_EQ_EN_H_DLY, 0x9c4)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_45, + AIROHA_USB_PMA_EQ_EN_DLY, + FIELD_PREP(AIROHA_USB_PMA_EQ_EN_DLY, 0x9c4)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_RX_CTRL_50, + AIROHA_USB_PMA_EQ_EN_DLY_SHORT | + AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT, + FIELD_PREP(AIROHA_USB_PMA_EQ_EN_DLY_SHORT, 0x9c4) | + FIELD_PREP(AIROHA_USB_PMA_RX_EQ_EN_H_DLY_SHORT, 0x9c4)); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_QP_TX_MODE_16B_EN, + AIROHA_USB_ANA_TX_RESERVE_8); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PON_RXFEDIG_CTRL_0, + AIROHA_USB_PMA_EQ_RX500M_CK_SEL); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_PLL_CTRL_0, + AIROHA_USB_PMA_AUTO_INIT); + + /* Select PLL_EN to Force mode */ + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], + AIROHA_USB_PMA_INTF_CTRL_7, + AIROHA_USB_PMA_PLL_EN_SEL | + AIROHA_USB_PMA_PLL_EN_FORCE); + + /* Try to calibrate KBand up to AIROHA_USB_PHY_U3_MAX_CALIB_TRY times */ + for (i = 0; i < AIROHA_USB_PHY_U3_MAX_CALIB_TRY; i++) { + /* Check if KBand is calibrated */ + if (an7583_usb_phy_u3_kband_is_calibrated(priv)) + break; + + /* Trigger KBand calibration */ + an7583_usb_phy_kband_calibrate(priv); + } + + an7583_usb_phy_tx_pll_enable(priv); + + return !an7583_usb_phy_u3_kband_is_calibrated(priv) ? -EINVAL : 0; +} + +static int an7583_usb_phy_init(struct phy *phy) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + + switch (instance->type) { + case PHY_TYPE_USB2: + an7583_usb_phy_u2_init(phy); + break; + case PHY_TYPE_USB3: + if (phy_get_mode(phy) == PHY_MODE_ETHERNET) + return 0; + + an7583_usb_phy_u3_init(phy); + break; + case PHY_TYPE_PCIE: + if (phy_get_mode(phy) == PHY_MODE_ETHERNET) + return 0; + + an7583_usb_phy_pcie_init(phy); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int an7583_usb_phy_exit(struct phy *phy) +{ + return 0; +} + +static int an7583_usb_phy_u2_power_on(struct phy *phy) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + struct an7583_usb_phy_priv *priv; + struct device *dev; + u32 offset; + + dev = phy->dev.parent; + priv = dev_get_drvdata(dev); + offset = instance->offset; + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR6 + offset, + AIROHA_USB_PHY_USB20_BC11_SW_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR2 + offset, + AIROHA_USB_PHY_SIFSLV_MAC_BANDGAP_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYACR3 + offset, + AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, + AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_TOGGLE); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYDTM0 + offset, + AIROHA_USB_PHY_FORCE_XCVRSEL | + AIROHA_USB_PHY_XCVRSEL); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR6 + offset, + AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, + AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_NO_ENPLL_FS_BIAS_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR5 + offset, + AIROHA_USB_PHY_USB20_DISC_FIT_EN); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYDTM0 + offset, + AIROHA_USB_PHY_FORCE_SUSPENDDM); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYACR3 + offset, + AIROHA_USB_PHY_USB20_USB11_TMODE_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYACR3 + offset, + AIROHA_USB_PHY_USB20_TMODE_FS_LS_TX_EN); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYDTM0 + offset, + AIROHA_USB_PHY_FORCE_TERMSEL | + AIROHA_USB_PHY_TERMSEL); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYACR3 + offset, + AIROHA_USB_PHY_USB20_PUPD_BIST_EN); + + return 0; +} + +static int an7583_usb_phy_u3_power_on(struct phy *phy) +{ + struct an7583_usb_phy_priv *priv; + struct device *dev; + + dev = phy->dev.parent; + priv = dev_get_drvdata(dev); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_TDC_FT_CK_EN, + AIROHA_USB_ANA_VUSB10_ON); + + usleep_range(1000, 1500); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], AIROHA_USB_PHY_GPIO_CTLD, + AIROHA_USB_PHY_SSUSB_IP_SW_RST); + + usleep_range(1000, 1500); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], AIROHA_USB_PHY_GPIO_CTLD, + AIROHA_USB_PHY_FORCE_SSUSB_IP_SW_RST); + + usleep_range(1000, 1500); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_5, + AIROHA_USB_PMA_RX_HZ_FORCE); + + usleep_range(1000, 1500); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_5, + AIROHA_USB_PMA_RX_HZ_SEL); + + return 0; +} + +static int an7583_usb_phy_power_on(struct phy *phy) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + + switch (instance->type) { + case PHY_TYPE_USB2: + return an7583_usb_phy_u2_power_on(phy); + case PHY_TYPE_USB3: + return an7583_usb_phy_u3_power_on(phy); + case PHY_TYPE_PCIE: + return 0; + default: + return -EINVAL; + } +} + +static int an7583_usb_phy_u2_power_off(struct phy *phy) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + struct an7583_usb_phy_priv *priv; + struct device *dev; + u32 offset; + + dev = phy->dev.parent; + priv = dev_get_drvdata(dev); + offset = instance->offset; + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYACR3 + offset, + AIROHA_USB_PHY_USB20_PUPD_BIST_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYDTM0 + offset, + AIROHA_USB_PHY_FORCE_TERMSEL | + AIROHA_USB_PHY_TERMSEL); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYACR3 + offset, + AIROHA_USB_PHY_USB20_TMODE_FS_LS_TX_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYACR3 + offset, + AIROHA_USB_PHY_USB20_USB11_TMODE_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYDTM0 + offset, + AIROHA_USB_PHY_FORCE_SUSPENDDM); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR5 + offset, + AIROHA_USB_PHY_USB20_DISC_FIT_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR6 + offset, + AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL, + AIROHA_USB_PHY_USB20_HSRX_BIAS_EN_SEL_USB20_HSRX_TMODE_EN); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYDTM0 + offset, + AIROHA_USB_PHY_FORCE_XCVRSEL | + AIROHA_USB_PHY_XCVRSEL, + AIROHA_USB_PHY_FORCE_XCVRSEL | + FIELD_PREP(AIROHA_USB_PHY_XCVRSEL, 0x1)); + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_U2PHYACR3 + offset, + AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE, + AIROHA_USB_PHY_USB20_HSTX_I_EN_MODE_FORCE_DISABLE); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR2 + offset, + AIROHA_USB_PHY_SIFSLV_MAC_BANDGAP_EN); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], + AIROHA_USB_PHY_USBPHYACR6 + offset, + AIROHA_USB_PHY_USB20_BC11_SW_EN); + + return 0; +} + +static int an7583_usb_phy_u3_power_off(struct phy *phy) +{ + struct an7583_usb_phy_priv *priv; + struct device *dev; + + dev = phy->dev.parent; + priv = dev_get_drvdata(dev); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], AIROHA_USB_PHY_GPIO_CTLD, + AIROHA_USB_PHY_FORCE_SSUSB_IP_SW_RST); + + usleep_range(1000, 1500); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PHY], AIROHA_USB_PHY_GPIO_CTLD, + AIROHA_USB_PHY_SSUSB_IP_SW_RST); + + usleep_range(1000, 1500); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_5, + AIROHA_USB_PMA_RX_HZ_FORCE); + + usleep_range(1000, 1500); + + regmap_set_bits(priv->regs[AIROHA_USB_PHY_PMA], AIROHA_USB_PMA_INTF_CTRL_5, + AIROHA_USB_PMA_RX_HZ_SEL); + + usleep_range(1000, 1500); + + regmap_clear_bits(priv->regs[AIROHA_USB_PHY_ANA], AIROHA_USB_ANA_TDC_FT_CK_EN, + AIROHA_USB_ANA_VUSB10_ON); + + return 0; +} + +static int an7583_usb_phy_power_off(struct phy *phy) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + + switch (instance->type) { + case PHY_TYPE_USB2: + return an7583_usb_phy_u2_power_off(phy); + case PHY_TYPE_USB3: + return an7583_usb_phy_u3_power_off(phy); + case PHY_TYPE_PCIE: + return 0; + default: + return -EINVAL; + } +} + +static int an7583_usb_phy_u2_set_mode(struct phy *phy, enum phy_mode mode) +{ + struct an7583_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent); + u32 val = 0; + + /* + * For Device and Host mode, enable force IDDIG. + * For Device set IDDIG, for Host clear IDDIG. + * For OTG disable force and clear IDDIG bit while at it. + */ + switch (mode) { + case PHY_MODE_USB_DEVICE: + val |= AIROHA_USB_PHY_IDDIG; + fallthrough; + case PHY_MODE_USB_HOST: + val |= AIROHA_USB_PHY_FORCE_IDDIG; + break; + case PHY_MODE_USB_OTG: + break; + default: + return 0; + } + + regmap_update_bits(priv->regs[AIROHA_USB_PHY_PHY], AIROHA_USB_PHY_U2PHYDTM1, + AIROHA_USB_PHY_FORCE_IDDIG | + AIROHA_USB_PHY_IDDIG, val); + + return 0; +} + +static int an7583_usb_phy_u3_set_mode(struct phy *phy, enum phy_mode mode, + int submode) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + int ret; + + switch (mode) { + case PHY_MODE_ETHERNET: + if (submode != PHY_INTERFACE_MODE_SGMII && + submode != PHY_INTERFACE_MODE_1000BASEX && + submode != PHY_INTERFACE_MODE_2500BASEX) + return -EOPNOTSUPP; + case PHY_MODE_USB_DEVICE_SS: + break; + default: + return -EOPNOTSUPP; + } + + ret = phy_set_mode_ext(instance->serdes_phy, mode, submode); + if (ret) + return ret; + + if (mode == PHY_MODE_ETHERNET) + an7583_usb_phy_set_mode_eth(phy, submode); + + return 0; +} + +static int an7583_usb_phy_pcie_set_mode(struct phy *phy, enum phy_mode mode, + int submode) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + int ret; + + switch (mode) { + case PHY_MODE_ETHERNET: + if (submode != PHY_INTERFACE_MODE_SGMII && + submode != PHY_INTERFACE_MODE_1000BASEX && + submode != PHY_INTERFACE_MODE_2500BASEX) + return -EOPNOTSUPP; + case PHY_MODE_PCIE: + break; + default: + return -EOPNOTSUPP; + } + + ret = phy_set_mode_ext(instance->serdes_phy, mode, submode); + if (ret) + return ret; + + if (mode == PHY_MODE_ETHERNET) + an7583_usb_phy_set_mode_eth(phy, submode); + + return 0; +} + +static int an7583_usb_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct an7583_usb_phy_instance *instance = phy_get_drvdata(phy); + + switch (instance->type) { + case PHY_TYPE_USB2: + return an7583_usb_phy_u2_set_mode(phy, mode); + case PHY_TYPE_USB3: + return an7583_usb_phy_u3_set_mode(phy, mode, submode); + case PHY_TYPE_PCIE: + return an7583_usb_phy_pcie_set_mode(phy, mode, submode); + default: + return 0; + } +} + +static struct phy *an7583_usb_phy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct an7583_usb_phy_priv *priv = dev_get_drvdata(dev); + const struct an7583_usb_phy_match_data *data; + struct device_node *phy_np = args->np; + struct phy *phy = NULL; + int type, index; + + data = of_device_get_match_data(dev); + + if (args->args_count != 1) { + dev_err(dev, "invalid number of cells in 'phy' property\n"); + return ERR_PTR(-EINVAL); + } + + for (index = 0; index < data->max_instance; index++) { + if (!priv->phys[index]) + continue; + + if (phy_np == priv->phys[index]->dev.of_node) { + phy = priv->phys[index]; + break; + } + } + + if (!phy) { + dev_err(dev, "failed to find appropriate phy\n"); + return ERR_PTR(-EINVAL); + } + + type = args->args[0]; + if (!(type == PHY_TYPE_USB2 || type == PHY_TYPE_USB3 || + type == PHY_TYPE_PCIE)) { + dev_err(dev, "unsupported device type: %d\n", type); + return ERR_PTR(-EINVAL); + } + + return phy; +} + +static const struct phy_ops airoha_phy = { + .init = an7583_usb_phy_init, + .exit = an7583_usb_phy_exit, + .power_on = an7583_usb_phy_power_on, + .power_off = an7583_usb_phy_power_off, + .set_mode = an7583_usb_phy_set_mode, + .owner = THIS_MODULE, +}; + +static const char * const an7583_usb_phy_regs_name[AIROHA_USB_PHY_REGS_MAX] = { + [AIROHA_USB_PHY_PHY] = "phy", + [AIROHA_USB_PHY_ANA] = "ana", + [AIROHA_USB_PHY_PMA] = "pma", + [AIROHA_USB_PHY_DIG] = "dig", +}; + +static const char * const airoha_pcie_phy_regs_name[AIROHA_USB_PHY_REGS_MAX] = { + [AIROHA_USB_PHY_ANA] = "ana", + [AIROHA_USB_PHY_PMA] = "pma", + [AIROHA_USB_PHY_DIG] = "dig", +}; + +static int an7583_usb_phy_parse_subnode(struct device *dev, + struct an7583_usb_phy_priv *priv, + int index, struct device_node *subnode) +{ + const struct an7583_usb_phy_match_data *data; + struct an7583_usb_phy_instance *instance; + struct phy *phy; + int ret; + + data = of_device_get_match_data(dev); + + if (index > data->max_instance) + return -EINVAL; + + if (!of_device_is_available(subnode)) + return 0; + + instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL); + if (!instance) + return -ENOMEM; + + instance->serdes_phy = devm_phy_optional_get(dev, NULL); + if (IS_ERR(instance->serdes_phy)) + return dev_err_probe(dev, PTR_ERR(instance->serdes_phy), "error on serdes phy for USB 3.0\n"); + + if (!instance->serdes_phy && + !of_property_present(subnode, "airoha,usb2-monitor-clk-sel")) + return dev_err_probe(dev, ret, "monitor clock selection or serdes PHY is mandatory for USB PHY\n"); + + if (instance->serdes_phy) { + instance->type = PHY_TYPE_USB3; + } else { + ret = of_property_read_u32(subnode, "airoha,usb2-monitor-clk-sel", + &instance->monclk_sel); + if (ret) + return dev_err_probe(dev, ret, "failed to parse Monitor clock selection\n"); + + ret = of_property_read_u32(subnode, "reg", + &instance->offset); + if (ret) + return dev_err_probe(dev, ret, "missing reg for U2 PHY\n"); + + instance->type = PHY_TYPE_USB2; + } + + phy = devm_phy_create(dev, subnode, &airoha_phy); + if (IS_ERR(phy)) + return dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n"); + + priv->phys[index] = phy; + phy_set_drvdata(phy, instance); + + return 0; +} + +static int airoha_pcie_phy_parse_subnode(struct device *dev, + struct an7583_usb_phy_priv *priv, + int index, struct device_node *subnode) +{ + const struct an7583_usb_phy_match_data *data; + struct an7583_usb_phy_instance *instance; + struct phy *phy; + + data = of_device_get_match_data(dev); + + if (index > data->max_instance) + return -EINVAL; + + if (!of_device_is_available(subnode)) + return 0; + + instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL); + if (!instance) + return -ENOMEM; + + instance->serdes_phy = devm_phy_get(dev, NULL); + if (IS_ERR(instance->serdes_phy)) + return dev_err_probe(dev, PTR_ERR(instance->serdes_phy), "error on serdes phy for PCIe PHY\n"); + + instance->type = PHY_TYPE_PCIE; + + phy = devm_phy_create(dev, subnode, &airoha_phy); + if (IS_ERR(phy)) + return dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n"); + + priv->phys[index] = phy; + phy_set_drvdata(phy, instance); + + return 0; +} + +static int an7583_usb_phy_probe(struct platform_device *pdev) +{ + const struct an7583_usb_phy_match_data *data; + struct phy_provider *phy_provider; + struct an7583_usb_phy_priv *priv; + struct device *dev = &pdev->dev; + struct device_node *child_np; + int i, ret; + u8 port; + + data = of_device_get_match_data(dev); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + for (i = 0; i < AIROHA_USB_PHY_REGS_MAX; i++) { + struct regmap_config conf = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + }; + void *base; + + if (!data->regs_name[i]) + continue; + + conf.name = data->regs_name[i]; + base = devm_platform_ioremap_resource_byname(pdev, + data->regs_name[i]); + if (IS_ERR(base)) + return PTR_ERR(base); + + priv->regs[i] = devm_regmap_init_mmio(dev, base, &conf); + if (IS_ERR(priv->regs[i])) + return PTR_ERR(priv->regs[i]); + } + + platform_set_drvdata(pdev, priv); + + port = 0; + for_each_child_of_node(dev->of_node, child_np) { + ret = data->parse_subnode(dev, priv, port, child_np); + if (ret) { + of_node_put(child_np); + return ret; + } + + port++; + } + + phy_provider = devm_of_phy_provider_register(dev, an7583_usb_phy_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct an7583_usb_phy_match_data an7583_usb_phy = { + .max_instance = AIROHA_USB_PHY_MAX_INSTANCE, + .regs_name = an7583_usb_phy_regs_name, + .parse_subnode = an7583_usb_phy_parse_subnode, +}; + +static const struct an7583_usb_phy_match_data an7583_pcie_phy = { + .max_instance = AIROHA_PCIE_PHY_MAX_INSTANCE, + .regs_name = airoha_pcie_phy_regs_name, + .parse_subnode = airoha_pcie_phy_parse_subnode, +}; + +static const struct of_device_id airoha_phy_id_table[] = { + { .compatible = "airoha,an7583-usb-phy", .data = &an7583_usb_phy }, + { .compatible = "airoha,an7583-pcie-phy", .data = &an7583_pcie_phy }, + { }, +}; +MODULE_DEVICE_TABLE(of, airoha_phy_id_table); + +static struct platform_driver an7583_usb_driver = { + .probe = an7583_usb_phy_probe, + .driver = { + .name = "airoha-an7583-usb-phy", + .of_match_table = airoha_phy_id_table, + }, +}; + +module_platform_driver(an7583_usb_driver); + +MODULE_DESCRIPTION("Airoha AN7583 USB PHY driver"); +MODULE_AUTHOR("Christian Marangi "); +MODULE_LICENSE("GPL"); -- 2.53.0