All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ye Li <ye.li@nxp.com>
To: u-boot@lists.denx.de
Subject: [PATCH 1/4] phy: phy-imx8mq-usb: Add USB PHY driver for i.MX8MQ
Date: Sun, 21 Feb 2021 08:26:21 -0800	[thread overview]
Message-ID: <1613924784-63219-1-git-send-email-ye.li@nxp.com> (raw)

Add the USB PHY driver for i.MX8MQ to work with DWC3 USB controller.

Signed-off-by: Ye Li <ye.li@nxp.com>
---
 drivers/phy/Kconfig          |   7 ++
 drivers/phy/Makefile         |   1 +
 drivers/phy/phy-imx8mq-usb.c | 197 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 205 insertions(+)
 create mode 100644 drivers/phy/phy-imx8mq-usb.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 008186a..09cb744 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -268,5 +268,12 @@ config PHY_MTK_TPHY
 	  multi-ports is first version, otherwise is second veriosn,
 	  so you can easily distinguish them by banks layout.
 
+config PHY_IMX8MQ_USB
+	bool "NXP i.MX8MQ USB PHY Driver"
+	depends on PHY
+	depends on IMX8MQ
+	help
+	  Support the USB3.0 PHY in NXP i.MX8MQ SoC
+
 source "drivers/phy/rockchip/Kconfig"
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 3c4a673..c6ad3b1 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -31,3 +31,4 @@ 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
+obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
diff --git a/drivers/phy/phy-imx8mq-usb.c b/drivers/phy/phy-imx8mq-usb.c
new file mode 100644
index 0000000..afbc7ad
--- /dev/null
+++ b/drivers/phy/phy-imx8mq-usb.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 NXP
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <clk.h>
+
+#define PHY_CTRL0			0x0
+#define PHY_CTRL0_REF_SSP_EN		BIT(2)
+#define PHY_CTRL0_FSEL_MASK		GENMASK(10, 5)
+#define PHY_CTRL0_FSEL_24M		0x2a
+#define PHY_CTRL0_FSEL_100M		0x27
+#define PHY_CTRL0_SSC_RANGE_MASK	GENMASK(23, 21)
+#define PHY_CTRL0_SSC_RANGE_4003PPM	(0x2 << 21)
+
+#define PHY_CTRL1			0x4
+#define PHY_CTRL1_RESET			BIT(0)
+#define PHY_CTRL1_COMMONONN		BIT(1)
+#define PHY_CTRL1_ATERESET		BIT(3)
+#define PHY_CTRL1_DCDENB		BIT(17)
+#define PHY_CTRL1_CHRGSEL		BIT(18)
+#define PHY_CTRL1_VDATSRCENB0		BIT(19)
+#define PHY_CTRL1_VDATDETENB0		BIT(20)
+
+#define PHY_CTRL2			0x8
+#define PHY_CTRL2_TXENABLEN0		BIT(8)
+#define PHY_CTRL2_OTG_DISABLE		BIT(9)
+
+#define PHY_CTRL3			0xc
+#define PHY_CTRL3_COMPDISTUNE_MASK	GENMASK(2, 0)
+#define PHY_CTRL3_TXPREEMP_TUNE_MASK	GENMASK(16, 15)
+#define PHY_CTRL3_TXPREEMP_TUNE_SHIFT	15
+#define PHY_CTRL3_TXRISE_TUNE_MASK	GENMASK(21, 20)
+#define PHY_CTRL3_TXRISE_TUNE_SHIFT	20
+/* 1111: +24% ... 0000: -6% step: 2% */
+#define PHY_CTRL3_TXVREF_TUNE_MASK	GENMASK(25, 22)
+#define PHY_CTRL3_TXVREF_TUNE_SHIFT	22
+#define PHY_CTRL3_TX_VBOOST_LEVEL_MASK	GENMASK(31, 29)
+#define PHY_CTRL3_TX_VBOOST_LEVEL_SHIFT	29
+
+#define PHY_CTRL4			0x10
+#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK	GENMASK(20, 15)
+#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_SHIFT	15
+
+#define PHY_CTRL5			0x14
+#define PHY_CTRL5_DMPWD_OVERRIDE_SEL	BIT(23)
+#define PHY_CTRL5_DMPWD_OVERRIDE	BIT(22)
+#define PHY_CTRL5_DPPWD_OVERRIDE_SEL	BIT(21)
+#define PHY_CTRL5_DPPWD_OVERRIDE	BIT(20)
+#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK	GENMASK(6, 0)
+
+#define PHY_CTRL6			0x18
+#define PHY_CTRL6_RXTERM_OVERRIDE_SEL	BIT(29)
+#define PHY_CTRL6_ALT_CLK_EN		BIT(1)
+#define PHY_CTRL6_ALT_CLK_SEL		BIT(0)
+
+#define PHY_STS0			0x40
+#define PHY_STS0_OTGSESSVLD		BIT(7)
+#define PHY_STS0_CHGDET			BIT(4)
+#define PHY_STS0_FSVPLUS		BIT(3)
+#define PHY_STS0_FSVMINUS		BIT(2)
+
+struct imx8mq_usb_phy {
+#if CONFIG_IS_ENABLED(CLK)
+	struct clk phy_clk;
+#endif
+	void __iomem *base;
+};
+
+static const struct udevice_id imx8mq_usb_phy_of_match[] = {
+	{
+		.compatible = "fsl,imx8mq-usb-phy",
+	},
+	{},
+};
+
+static int imx8mq_usb_phy_init(struct phy *usb_phy)
+{
+	struct udevice *dev = usb_phy->dev;
+	struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
+	u32 value;
+
+	value = readl(imx_phy->base + PHY_CTRL1);
+	value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
+		   PHY_CTRL1_COMMONONN);
+	value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
+	writel(value, imx_phy->base + PHY_CTRL1);
+
+	value = readl(imx_phy->base + PHY_CTRL0);
+	value |= PHY_CTRL0_REF_SSP_EN;
+	value &= ~PHY_CTRL0_SSC_RANGE_MASK;
+	value |= PHY_CTRL0_SSC_RANGE_4003PPM;
+	writel(value, imx_phy->base + PHY_CTRL0);
+
+	value = readl(imx_phy->base + PHY_CTRL2);
+	value |= PHY_CTRL2_TXENABLEN0;
+	writel(value, imx_phy->base + PHY_CTRL2);
+
+	value = readl(imx_phy->base + PHY_CTRL1);
+	value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
+	writel(value, imx_phy->base + PHY_CTRL1);
+
+	return 0;
+}
+
+static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
+{
+	struct udevice *dev = usb_phy->dev;
+	struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
+	u32 value;
+
+#if CONFIG_IS_ENABLED(CLK)
+	int ret;
+	ret = clk_enable(&imx_phy->phy_clk);
+	if (ret) {
+		printf("Failed to enable usb phy clock\n");
+		return ret;
+	}
+#endif
+
+	/* Disable rx term override */
+	value = readl(imx_phy->base + PHY_CTRL6);
+	value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+	writel(value, imx_phy->base + PHY_CTRL6);
+
+	return 0;
+}
+
+static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
+{
+	struct udevice *dev = usb_phy->dev;
+	struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
+	u32 value;
+
+	/* Override rx term to be 0 */
+	value = readl(imx_phy->base + PHY_CTRL6);
+	value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+	writel(value, imx_phy->base + PHY_CTRL6);
+
+#if CONFIG_IS_ENABLED(CLK)
+	clk_disable(&imx_phy->phy_clk);
+#endif
+
+	return 0;
+}
+
+static int imx8mq_usb_phy_exit(struct phy *usb_phy)
+{
+	return imx8mq_usb_phy_power_off(usb_phy);
+}
+
+struct phy_ops imx8mq_usb_phy_ops = {
+	.init = imx8mq_usb_phy_init,
+	.power_on = imx8mq_usb_phy_power_on,
+	.power_off = imx8mq_usb_phy_power_off,
+	.exit = imx8mq_usb_phy_exit,
+};
+
+int imx8mq_usb_phy_probe(struct udevice *dev)
+{
+	struct imx8mq_usb_phy *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev);
+
+	if (!priv->base)
+		return -EINVAL;
+
+#if CONFIG_IS_ENABLED(CLK)
+	int ret;
+
+	/* Assigned clock already set clock */
+	ret = clk_get_by_name(dev, "phy", &priv->phy_clk);
+	if (ret) {
+		printf("Failed to get usb phy clock\n");
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
+U_BOOT_DRIVER(nxp_imx8mq_usb_phy) = {
+	.name = "nxp_imx8mq_usb_phy",
+	.id = UCLASS_PHY,
+	.of_match = imx8mq_usb_phy_of_match,
+	.probe = imx8mq_usb_phy_probe,
+	.ops = &imx8mq_usb_phy_ops,
+	.priv_auto	= sizeof(struct imx8mq_usb_phy),
+};
-- 
2.7.4

             reply	other threads:[~2021-02-21 16:26 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-21 16:26 Ye Li [this message]
2021-02-21 16:26 ` [PATCH 2/4] arm: dts: imx8mq: Add alias for two usb controllers Ye Li
2021-07-12 14:30   ` Patrick Wildt
2021-02-21 16:26 ` [PATCH 3/4] arm: imx8mq: Add USB clock init function Ye Li
2021-07-12 14:33   ` Patrick Wildt
2021-02-21 16:26 ` [PATCH 4/4] imx8mq_evk: Enable the USB3.0 host port Ye Li
2021-02-25 11:01   ` Fabio Estevam
2021-02-25 13:34     ` [EXT] " Ye Li
2021-02-25 13:49       ` Fabio Estevam
2021-02-27  6:04         ` Ye Li
2021-02-27 13:46           ` Fabio Estevam
2021-03-03  8:53           ` Bough Chen
2021-07-10 23:34             ` Patrick Wildt
2021-07-12 13:28               ` Fabio Estevam
2021-07-12 14:23                 ` Patrick Wildt
2021-07-12 14:33   ` Patrick Wildt
2021-07-12 14:27 ` [PATCH 1/4] phy: phy-imx8mq-usb: Add USB PHY driver for i.MX8MQ Patrick Wildt
2021-07-12 21:31   ` Fabio Estevam
2021-07-13  5:53     ` Stefano Babic
2021-07-13 10:39       ` Marek Vasut
2021-07-13 10:46         ` Stefano Babic
2021-07-13 11:22           ` Patrick Wildt
2021-07-13 11:53             ` Marek Vasut
2021-07-13 11:54               ` Stefano Babic

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1613924784-63219-1-git-send-email-ye.li@nxp.com \
    --to=ye.li@nxp.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.