From patchwork Wed Jan 20 07:34:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: JC Kuo X-Patchwork-Id: 368427 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.9 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A7852C433DB for ; Wed, 20 Jan 2021 07:35:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7DA4323109 for ; Wed, 20 Jan 2021 07:35:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728992AbhATHfo (ORCPT ); Wed, 20 Jan 2021 02:35:44 -0500 Received: from hqnvemgate24.nvidia.com ([216.228.121.143]:16042 "EHLO hqnvemgate24.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728866AbhATHfW (ORCPT ); Wed, 20 Jan 2021 02:35:22 -0500 Received: from hqmail.nvidia.com (Not Verified[216.228.121.13]) by hqnvemgate24.nvidia.com (using TLS: TLSv1.2, AES256-SHA) id ; Tue, 19 Jan 2021 23:34:39 -0800 Received: from HQMAIL101.nvidia.com (172.20.187.10) by HQMAIL105.nvidia.com (172.20.187.12) with Microsoft SMTP Server (TLS) id 15.0.1473.3; Wed, 20 Jan 2021 07:34:37 +0000 Received: from jckuo-lt.nvidia.com (172.20.145.6) by mail.nvidia.com (172.20.187.10) with Microsoft SMTP Server id 15.0.1473.3 via Frontend Transport; Wed, 20 Jan 2021 07:34:33 +0000 From: JC Kuo To: , , , , , , CC: , , , , , , JC Kuo , Thierry Reding Subject: [PATCH v7 04/14] phy: tegra: xusb: Rearrange UPHY init on Tegra210 Date: Wed, 20 Jan 2021 15:34:04 +0800 Message-ID: <20210120073414.69208-5-jckuo@nvidia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210120073414.69208-1-jckuo@nvidia.com> References: <20210120073414.69208-1-jckuo@nvidia.com> MIME-Version: 1.0 X-NVConfidentiality: public DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1611128079; bh=gA2uAD75PgJMzQq8dTM6/MeR6ebR0mtLRVYx8h4bngk=; h=From:To:CC:Subject:Date:Message-ID:X-Mailer:In-Reply-To: References:MIME-Version:X-NVConfidentiality: Content-Transfer-Encoding:Content-Type; b=Oy8fY0HzK50a9iDPTr87MSoYMshJWl2PsUrBKewKAvprniyak6iCqZdbATHJTnRYP BALIkopvPEbsB2/TxWzIifQ5Vo2pFXKVgxyDgt7XJAweHzJ1pS4SzBvKt8FaoDBtEj OHHY9QVp5DsyoSwp+/eTFz5xUFNPBjBfv3IQrw+6zLVKch62tEhoyXu2TEpVg1YU0q MLkkfhJkTreZYDXwaDqiKjsvQsyZBmEWG1DpQIq1TeJLSjbVfCPAGKFqe8Xuz0wpN7 hPyLDPD26dpUS8F4q9JNzqKNFFBnuYO4GCKmzjZbz2Jtuh4iRFfFqZwIzFnL8PLdoI gJ7tp2Z8wNMug== Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org This commit is a preparation for enabling XUSB SC7 support. It rearranges Tegra210 XUSB PADCTL UPHY initialization sequence, for the following reasons: 1. PLLE hardware power sequencer has to be enabled only after both PEX UPHY PLL and SATA UPHY PLL are initialized. tegra210_uphy_init() -> tegra210_pex_uphy_enable() -> tegra210_sata_uphy_enable() -> tegra210_plle_hw_sequence_start() -> tegra210_aux_mux_lp0_clamp_disable() 2. At cold boot and SC7 exit, the following bits must be cleared after PEX/SATA lanes are out of IDDQ (IDDQ_DISABLE=1). a. XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN, b. XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY c. XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN tegra210_pex_uphy_enable() and tegra210_sata_uphy_enable() are in charge of bringing lanes out of IDDQ, and then AUX_MUX_LP0_* bits will be cleared by tegra210_aux_mux_lp0_clamp_disable(). 3. Once UPHY PLL hardware power sequencer is enabled, do not assert reset to PEX/SATA PLLs, otherwise UPHY PLL operation will be broken. Signed-off-by: JC Kuo Acked-by: Thierry Reding --- v7: merge v5 [04/15] phy: tegra: xusb: tegra210: Do not reset UPHY PLL v6: no change v5: no change v4: no change v3: make separate changes use "unsigned int" instead "int" type for PHY index add blank line for better readability drivers/phy/tegra/xusb-tegra210.c | 197 +++++++++++++++--------------- drivers/phy/tegra/xusb.h | 4 +- 2 files changed, 103 insertions(+), 98 deletions(-) diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c index 4dc9286ec1b8..faacb866cd1f 100644 --- a/drivers/phy/tegra/xusb-tegra210.c +++ b/drivers/phy/tegra/xusb-tegra210.c @@ -288,17 +288,19 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie); unsigned long timeout; u32 value; + unsigned int i; int err; - if (pcie->enable > 0) { - pcie->enable++; + if (pcie->enable) return 0; - } err = clk_prepare_enable(pcie->pll); if (err < 0) return err; + if (tegra210_plle_hw_sequence_is_enabled()) + goto skip_pll_init; + err = reset_control_deassert(pcie->rst); if (err < 0) goto disable; @@ -481,7 +483,14 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) tegra210_xusb_pll_hw_sequence_start(); - pcie->enable++; +skip_pll_init: + pcie->enable = true; + + for (i = 0; i < padctl->pcie->soc->num_lanes; i++) { + value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); + value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i); + padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); + } return 0; @@ -495,29 +504,44 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl) { struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie); + u32 value; + unsigned int i; - if (WARN_ON(pcie->enable == 0)) + if (WARN_ON(!pcie->enable)) return; - if (--pcie->enable > 0) - return; + pcie->enable = false; + + for (i = 0; i < padctl->pcie->soc->num_lanes; i++) { + value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); + value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i); + padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); + } - reset_control_assert(pcie->rst); clk_disable_unprepare(pcie->pll); } /* must be called under padctl->lock */ -static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb) +static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl) { struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata); + struct tegra_xusb_lane *lane = tegra_xusb_find_lane(padctl, "sata", 0); unsigned long timeout; u32 value; + unsigned int i; int err; + bool usb; - if (sata->enable > 0) { - sata->enable++; + if (sata->enable) + return 0; + + if (IS_ERR(lane)) return 0; - } + + if (tegra210_plle_hw_sequence_is_enabled()) + goto skip_pll_init; + + usb = tegra_xusb_lane_check(lane, "usb3-ss"); err = clk_prepare_enable(sata->pll); if (err < 0) @@ -718,7 +742,14 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb) tegra210_sata_pll_hw_sequence_start(); - sata->enable++; +skip_pll_init: + sata->enable = true; + + for (i = 0; i < padctl->sata->soc->num_lanes; i++) { + value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); + value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i); + padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); + } return 0; @@ -732,26 +763,27 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb) static void tegra210_sata_uphy_disable(struct tegra_xusb_padctl *padctl) { struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata); + u32 value; + unsigned int i; - if (WARN_ON(sata->enable == 0)) + if (WARN_ON(!sata->enable)) return; - if (--sata->enable > 0) - return; + sata->enable = false; + + for (i = 0; i < padctl->sata->soc->num_lanes; i++) { + value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); + value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i); + padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); + } - reset_control_assert(sata->rst); clk_disable_unprepare(sata->pll); } -static int tegra210_xusb_padctl_enable(struct tegra_xusb_padctl *padctl) +static void tegra210_aux_mux_lp0_clamp_disable(struct tegra_xusb_padctl *padctl) { u32 value; - mutex_lock(&padctl->lock); - - if (padctl->enable++ > 0) - goto out; - value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN; padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); @@ -767,24 +799,12 @@ static int tegra210_xusb_padctl_enable(struct tegra_xusb_padctl *padctl) value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN; padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); - -out: - mutex_unlock(&padctl->lock); - return 0; } -static int tegra210_xusb_padctl_disable(struct tegra_xusb_padctl *padctl) +static void tegra210_aux_mux_lp0_clamp_enable(struct tegra_xusb_padctl *padctl) { u32 value; - mutex_lock(&padctl->lock); - - if (WARN_ON(padctl->enable == 0)) - goto out; - - if (--padctl->enable > 0) - goto out; - value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN; padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); @@ -800,12 +820,38 @@ static int tegra210_xusb_padctl_disable(struct tegra_xusb_padctl *padctl) value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN; padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); +} + +static int tegra210_uphy_init(struct tegra_xusb_padctl *padctl) +{ + if (padctl->pcie) + tegra210_pex_uphy_enable(padctl); + + if (padctl->sata) + tegra210_sata_uphy_enable(padctl); + + if (!tegra210_plle_hw_sequence_is_enabled()) + tegra210_plle_hw_sequence_start(); + else + dev_dbg(padctl->dev, "PLLE is already in HW control\n"); + + tegra210_aux_mux_lp0_clamp_disable(padctl); -out: - mutex_unlock(&padctl->lock); return 0; } +static void __maybe_unused +tegra210_uphy_deinit(struct tegra_xusb_padctl *padctl) +{ + tegra210_aux_mux_lp0_clamp_enable(padctl); + + if (padctl->sata) + tegra210_sata_uphy_disable(padctl); + + if (padctl->pcie) + tegra210_pex_uphy_disable(padctl); +} + static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl, unsigned int index, bool idle) { @@ -942,14 +988,12 @@ static int tegra210_usb2_phy_init(struct phy *phy) XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT; padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); - return tegra210_xusb_padctl_enable(padctl); + return 0; } static int tegra210_usb2_phy_exit(struct phy *phy) { - struct tegra_xusb_lane *lane = phy_get_drvdata(phy); - - return tegra210_xusb_padctl_disable(lane->pad->padctl); + return 0; } static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl, @@ -1407,14 +1451,12 @@ static int tegra210_hsic_phy_init(struct phy *phy) XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT; padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); - return tegra210_xusb_padctl_enable(padctl); + return 0; } static int tegra210_hsic_phy_exit(struct phy *phy) { - struct tegra_xusb_lane *lane = phy_get_drvdata(phy); - - return tegra210_xusb_padctl_disable(lane->pad->padctl); + return 0; } static int tegra210_hsic_phy_power_on(struct phy *phy) @@ -1778,38 +1820,28 @@ static const struct tegra_xusb_lane_ops tegra210_pcie_lane_ops = { static int tegra210_pcie_phy_init(struct phy *phy) { struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; - return tegra210_xusb_padctl_enable(lane->pad->padctl); -} + mutex_lock(&padctl->lock); -static int tegra210_pcie_phy_exit(struct phy *phy) -{ - struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + tegra210_uphy_init(padctl); + + mutex_unlock(&padctl->lock); - return tegra210_xusb_padctl_disable(lane->pad->padctl); + return 0; } static int tegra210_pcie_phy_power_on(struct phy *phy) { struct tegra_xusb_lane *lane = phy_get_drvdata(phy); struct tegra_xusb_padctl *padctl = lane->pad->padctl; - u32 value; - int err; + int err = 0; mutex_lock(&padctl->lock); - err = tegra210_pex_uphy_enable(padctl); - if (err < 0) - goto unlock; - - value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); - value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index); - padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); - if (tegra_xusb_lane_check(lane, "usb3-ss")) err = tegra210_usb3_phy_power_on(phy); -unlock: mutex_unlock(&padctl->lock); return err; } @@ -1819,16 +1851,9 @@ static int tegra210_pcie_phy_power_off(struct phy *phy) struct tegra_xusb_lane *lane = phy_get_drvdata(phy); struct tegra_xusb_padctl *padctl = lane->pad->padctl; int err = 0; - u32 value; mutex_lock(&padctl->lock); - value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); - value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index); - padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); - - tegra210_pex_uphy_disable(padctl); - if (tegra_xusb_lane_check(lane, "usb3-ss")) err = tegra210_usb3_phy_power_off(phy); @@ -1838,7 +1863,6 @@ static int tegra210_pcie_phy_power_off(struct phy *phy) static const struct phy_ops tegra210_pcie_phy_ops = { .init = tegra210_pcie_phy_init, - .exit = tegra210_pcie_phy_exit, .power_on = tegra210_pcie_phy_power_on, .power_off = tegra210_pcie_phy_power_off, .owner = THIS_MODULE, @@ -1959,38 +1983,27 @@ static const struct tegra_xusb_lane_ops tegra210_sata_lane_ops = { static int tegra210_sata_phy_init(struct phy *phy) { struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; - return tegra210_xusb_padctl_enable(lane->pad->padctl); -} + mutex_lock(&padctl->lock); -static int tegra210_sata_phy_exit(struct phy *phy) -{ - struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + tegra210_uphy_init(padctl); - return tegra210_xusb_padctl_disable(lane->pad->padctl); + mutex_unlock(&padctl->lock); + return 0; } static int tegra210_sata_phy_power_on(struct phy *phy) { struct tegra_xusb_lane *lane = phy_get_drvdata(phy); struct tegra_xusb_padctl *padctl = lane->pad->padctl; - u32 value; - int err; + int err = 0; mutex_lock(&padctl->lock); - err = tegra210_sata_uphy_enable(padctl, false); - if (err < 0) - goto unlock; - - value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); - value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index); - padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); - if (tegra_xusb_lane_check(lane, "usb3-ss")) err = tegra210_usb3_phy_power_on(phy); -unlock: mutex_unlock(&padctl->lock); return err; } @@ -2000,16 +2013,9 @@ static int tegra210_sata_phy_power_off(struct phy *phy) struct tegra_xusb_lane *lane = phy_get_drvdata(phy); struct tegra_xusb_padctl *padctl = lane->pad->padctl; int err = 0; - u32 value; mutex_lock(&padctl->lock); - value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); - value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index); - padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); - - tegra210_sata_uphy_disable(lane->pad->padctl); - if (tegra_xusb_lane_check(lane, "usb3-ss")) err = tegra210_usb3_phy_power_off(phy); @@ -2019,7 +2025,6 @@ static int tegra210_sata_phy_power_off(struct phy *phy) static const struct phy_ops tegra210_sata_phy_ops = { .init = tegra210_sata_phy_init, - .exit = tegra210_sata_phy_exit, .power_on = tegra210_sata_phy_power_on, .power_off = tegra210_sata_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h index 37a5550a84ac..ccb5dc9b1220 100644 --- a/drivers/phy/tegra/xusb.h +++ b/drivers/phy/tegra/xusb.h @@ -232,7 +232,7 @@ struct tegra_xusb_pcie_pad { struct reset_control *rst; struct clk *pll; - unsigned int enable; + bool enable; }; static inline struct tegra_xusb_pcie_pad * @@ -247,7 +247,7 @@ struct tegra_xusb_sata_pad { struct reset_control *rst; struct clk *pll; - unsigned int enable; + bool enable; }; static inline struct tegra_xusb_sata_pad *