From: BH Hsieh Date: Thu, 8 Jun 2017 02:47:42 +0000 (+0800) Subject: uphy: t210: clean up PLLs deinit functions X-Git-Url: https://rtime.felk.cvut.cz/gitweb/hercules2020/nv-tegra/linux-4.4.git/commitdiff_plain/b767582bf0425bdeab4b99af6739e0ad629bff9c uphy: t210: clean up PLLs deinit functions UPHY driver should not assert reset or update regs of PLLE and PEX/SATA PLLs when they're in HW control. Removed PLLs deinit functions to avoid it. Invoking clk_disable_unprepare(uphy->plle) in suspend_noirq only updates PLLE enable_count as clk_plle_tegra210_enable won't update PLLE regs if it's in HW control. PLLE enable_count is not balanced if system didn't reach SC7, added check in tegra21x_padctl_uphy_resume to hadle it properly. Bug 200305623 Bug 200305881 Change-Id: I6e1726beeba8e361e8556c91ab70e661b8b9b529 Signed-off-by: BH Hsieh (cherry picked from commit 116565fcc2af8262c834cc80d59e891df435f4af) Reviewed-on: http://git-master/r/1499128 Reviewed-by: Hans Yang Tested-by: Hans Yang Reviewed-by: WK Tsai Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: ChihMin Cheng GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- diff --git a/drivers/pinctrl/pinctrl-tegra21x-padctl-uphy.c b/drivers/pinctrl/pinctrl-tegra21x-padctl-uphy.c index 4f37269cbdd4..7e1ce806564e 100644 --- a/drivers/pinctrl/pinctrl-tegra21x-padctl-uphy.c +++ b/drivers/pinctrl/pinctrl-tegra21x-padctl-uphy.c @@ -307,12 +307,14 @@ enum tegra21x_function { TEGRA21x_FUNC_PCIE, TEGRA21x_FUNC_USB3, TEGRA21x_FUNC_SATA, + TEGRA21x_FUNC_INVALID, }; enum tegra21xb01_function { TEGRA21xB01_FUNC_XUSB, TEGRA21xB01_FUNC_PCIE, TEGRA21xB01_FUNC_USB3, + TEGRA21xB01_FUNC_INVALID, }; struct tegra_padctl_uphy_function { @@ -491,11 +493,9 @@ struct tegra_padctl_uphy { struct regulator *vbus[TEGRA_UTMI_PHYS]; struct regulator *vddio_hsic; - unsigned long uphy_pll_users[T21x_UPHY_PLLS]; enum uphy_pll_state uphy_pll_state[T21x_UPHY_PLLS]; enum source_pll_state plle_state; - int uphy_pll_clients[T21x_UPHY_PLLS]; struct reset_control *uphy_pll_rst[T21x_UPHY_PLLS]; /* vbus/id based OTG */ @@ -616,7 +616,7 @@ static inline int is_chip_t210b01(struct tegra_padctl_uphy *uphy) if (!compatible) { dev_err(uphy->dev, "Unable to find compatible property\n"); - return -ENODEV; + return 0; } if (strstr(compatible, "tegra21xb01") != NULL) @@ -646,24 +646,22 @@ static int get_function(struct tegra_padctl_uphy *uphy, char *func) int ret; ret = is_chip_t210b01(uphy); - if (ret < 0) - return ret; switch (str_to_func(func)) { case TEGRA21x_FUNC_HSIC: - return ret ? -1 : TEGRA21x_FUNC_HSIC; + return ret ? TEGRA21xB01_FUNC_INVALID : TEGRA21x_FUNC_HSIC; case TEGRA21x_FUNC_XUSB: return ret ? TEGRA21xB01_FUNC_XUSB : TEGRA21x_FUNC_XUSB; case TEGRA21x_FUNC_PCIE: return ret ? TEGRA21xB01_FUNC_PCIE : TEGRA21x_FUNC_PCIE; case TEGRA21x_FUNC_SATA: - return ret ? -1 : TEGRA21x_FUNC_SATA; + return ret ? TEGRA21xB01_FUNC_INVALID : TEGRA21x_FUNC_SATA; case TEGRA21x_FUNC_USB3: return ret ? TEGRA21xB01_FUNC_USB3 : TEGRA21x_FUNC_USB3; default: dev_err(uphy->dev, "Invalid function\n"); } - return -1; + return ret ? TEGRA21xB01_FUNC_INVALID : TEGRA21x_FUNC_INVALID; } static int tegra21x_padctl_uphy_regulators_init(struct tegra_padctl_uphy *uphy) @@ -781,33 +779,6 @@ static int uphy_pll_source_clk_enable(struct tegra_padctl_uphy *uphy) return 0; } -/* caller must hold uphy->lock */ -static int uphy_pll_source_clk_disable(struct tegra_padctl_uphy *uphy, int pll, - enum tegra21x_function func) -{ - struct device *dev = uphy->dev; - int rc = 0; - - rc = uphy_pll_source_clk_state_check(uphy); - if (rc) - return rc; - - /* Both UPHY PLLs are powered down, power down PLLE. - * Note that clk_disable_unprepare(PLLE) is still - * invoked even PLLE is in HW in order to sync - * enable_cnt/prepare_cnt of PLLE. - * clk_plle_tegra210_disable doesn't really disable - * PLLE if it's in HW. - */ - if (uphy->plle_state >= PLL_POWER_UP_SW_CTL) { - clk_disable_unprepare(uphy->plle); - uphy->plle_state = PLL_POWER_DOWN; - TRACE(dev, "done disable PLLE\n"); - } - - return rc; -} - /* caller must hold uphy->lock */ static int uphy_pll_resistor_calibration(struct tegra_padctl_uphy *uphy, int pll) @@ -829,10 +800,8 @@ static int uphy_pll_resistor_calibration(struct tegra_padctl_uphy *uphy, usleep_range(5, 10); value = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_8); - if (!(value & RCAL_DONE)) { + if (!(value & RCAL_DONE)) dev_err(dev, "PLL%d start resistor calibration timeout\n", pll); - return -ETIMEDOUT; - } /* stop resistor calibration */ value = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_8); @@ -842,10 +811,8 @@ static int uphy_pll_resistor_calibration(struct tegra_padctl_uphy *uphy, usleep_range(5, 10); value = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_8); - if (value & RCAL_DONE) { + if (value & RCAL_DONE) dev_err(dev, "PLL%d stop resistor calibration timeout\n", pll); - return -ETIMEDOUT; - } value = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_8); value &= ~RCAL_CLK_EN; @@ -862,8 +829,8 @@ static int uphy_pll_hw_sequencer_enable(struct tegra_padctl_uphy *uphy, int pll, u32 value; unsigned int uphy_lane; - TRACE(dev, "enable PLL%d HW power sequencer by function %d\n", - pll, func); + TRACE(dev, "enable PLL%d HW power sequencer by function %s\n", + pll, uphy->soc->functions[func].name); if (func == get_function(uphy, "sata")) { for_each_set_bit(uphy_lane, &uphy->sata_lanes, @@ -902,8 +869,8 @@ static int uphy_pll_hw_sequencer_enable(struct tegra_padctl_uphy *uphy, int pll, tegra210_xusb_pll_hw_sequence_start(); uphy->uphy_pll_state[pll] = UPHY_PLL_POWER_UP_HW_SEQ; - TRACE(dev, "done enable PLL%d in HW by function %d\n", - pll, func); + TRACE(dev, "done enable PLL%d in HW by function %s\n", + pll, uphy->soc->functions[func].name); /* enable PLLE Power sequencer */ if ((uphy->uphy_pll_state[0] == UPHY_PLL_POWER_UP_HW_SEQ) && @@ -916,53 +883,6 @@ static int uphy_pll_hw_sequencer_enable(struct tegra_padctl_uphy *uphy, int pll, return 0; } -/* caller must hold uphy->lock */ -static int uphy_pll_power_down(struct tegra_padctl_uphy *uphy, int pll - , enum tegra21x_function func) -{ - struct device *dev = uphy->dev; - u32 value; - - if ((pll == 0 && tegra210_xusb_pll_hw_sequence_is_enabled()) || - (pll == 1 && tegra210_sata_pll_hw_sequence_is_enabled())) { - TRACE(dev, "PLL%d is in HW, skip powering down\n", pll); - uphy->uphy_pll_state[pll] = UPHY_PLL_POWER_DOWN; - return 0; - } - - if (uphy->uphy_pll_state[pll] == UPHY_PLL_POWER_DOWN) { - TRACE(dev, "PLL%d was already powered down", pll); - return 0; - } - - value = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_1); - value &= ~PLL_ENABLE; - uphy_pll_writel(uphy, pll, value, UPHY_PLL_CTL_1); - - usleep_range(20, 25); - - value = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_1); - if (value & LOCKDET_STATUS) { - dev_err(dev, "disable PLL%d timeout\n", pll); - return -ETIMEDOUT; - } - - /* enter sleep state = 3 */ - value = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_1); - value &= ~PLL_SLEEP(~0); - value |= PLL_SLEEP(3); - uphy_pll_writel(uphy, pll, value, UPHY_PLL_CTL_1); - - /* apply IDDQ */ - value = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_1); - value |= PLL_IDDQ; - uphy_pll_writel(uphy, pll, value, UPHY_PLL_CTL_1); - uphy->uphy_pll_state[pll] = UPHY_PLL_POWER_DOWN; - TRACE(dev, "done powering down PLL%d\n", pll); - - return 0; -} - /* caller must hold uphy->lock */ static int uphy_pll_calibration(struct tegra_padctl_uphy *uphy, int pll) { @@ -983,10 +903,8 @@ static int uphy_pll_calibration(struct tegra_padctl_uphy *uphy, int pll) break; usleep_range(10, 15); } - if (!(value & CAL_DONE)) { + if (!(value & CAL_DONE)) dev_err(dev, "start PLL%d calibration timeout\n", pll); - return -EPROBE_DEFER; - } /* stop PLL calibration */ value = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_2); @@ -999,10 +917,8 @@ static int uphy_pll_calibration(struct tegra_padctl_uphy *uphy, int pll) break; usleep_range(10, 15); } - if (value & CAL_DONE) { + if (value & CAL_DONE) dev_err(dev, "stop PLL%d calibration timeout\n", pll); - return -EPROBE_DEFER; - } return 0; } @@ -1012,7 +928,6 @@ static int uphy_pll_init_full(struct tegra_padctl_uphy *uphy, int pll, enum tegra21x_function func) { struct device *dev = uphy->dev; - int rc = 0; u32 reg; if (pll < 0 || pll >= T21x_UPHY_PLLS) @@ -1034,12 +949,13 @@ static int uphy_pll_init_full(struct tegra_padctl_uphy *uphy, int pll, if (uphy->uphy_pll_state[pll] >= UPHY_PLL_POWER_UP_SW_CTL) { TRACE(dev, - "PLL%d was already enabled in SW/HW, current function is %d", - pll, func); + "PLL%d was already enabled in SW/HW, current function is %s", + pll, uphy->soc->functions[func].name); return 0; /* already done */ } - TRACE(dev, "PLL%d full init by function %d\n", pll, func); + TRACE(dev, "PLL%d full init by function %s\n", + pll, uphy->soc->functions[func].name); reg = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_2); reg &= ~CAL_CTRL(~0); @@ -1084,9 +1000,7 @@ static int uphy_pll_init_full(struct tegra_padctl_uphy *uphy, int pll, ndelay(100); - rc = uphy_pll_calibration(uphy, pll); - if (rc) - return rc; + uphy_pll_calibration(uphy, pll); /* enable PLL and wait for lock */ reg = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_1); @@ -1096,19 +1010,15 @@ static int uphy_pll_init_full(struct tegra_padctl_uphy *uphy, int pll, usleep_range(65, 70); reg = uphy_pll_readl(uphy, pll, UPHY_PLL_CTL_1); - if (!(reg & LOCKDET_STATUS)) { + if (!(reg & LOCKDET_STATUS)) dev_err(dev, "enable PLL%d timeout\n", pll); - return -EPROBE_DEFER; - } - if (uphy->uphy_pll_state[pll] == UPHY_PLL_POWER_DOWN) { - rc = uphy_pll_resistor_calibration(uphy, pll); - if (rc) - return -EPROBE_DEFER; - } + if (uphy->uphy_pll_state[pll] == UPHY_PLL_POWER_DOWN) + uphy_pll_resistor_calibration(uphy, pll); uphy->uphy_pll_state[pll] = UPHY_PLL_POWER_UP_SW_CTL; - TRACE(dev, "done enable PLL%d in SW by function %d\n", pll, func); + TRACE(dev, "done enable PLL%d in SW by function %s\n", + pll, uphy->soc->functions[func].name); return uphy_pll_hw_sequencer_enable(uphy, pll, func); } @@ -1119,9 +1029,9 @@ static int uphy_pll_init(struct tegra_padctl_uphy *uphy, { struct device *dev = uphy->dev; int rc = 0; - int i; - TRACE(dev, "PLL init by function %d\n", func); + TRACE(dev, "PLL init by function %s\n", + uphy->soc->functions[func].name); rc = uphy_pll_source_clk_enable(uphy); if (rc) @@ -1162,63 +1072,9 @@ static int uphy_pll_init(struct tegra_padctl_uphy *uphy, } } - if (rc == 0) { - if (func == get_function(uphy, "pcie")) { - uphy->uphy_pll_users[0] |= BIT(func); - } else if (func == get_function(uphy, "sata")) { - uphy->uphy_pll_users[1] |= BIT(func); - } else if (func == get_function(uphy, "usb3")) { - uphy->uphy_pll_users[0] |= BIT(func); - if (uphy->usb3_lanes & SATA_LANE_MASK) - uphy->uphy_pll_users[1] |= BIT(func); - } - for (i = 0; i < T21x_UPHY_PLLS; i++) { - TRACE(dev, "PLL%d users 0x%lx\n", i, - uphy->uphy_pll_users[i]); - } - } - return rc; } -/* caller must hold uphy->lock */ -int uphy_pll_deinit(struct tegra_padctl_uphy *uphy, - enum tegra21x_function func) -{ - struct device *dev = uphy->dev; - int rc; - int i; - - if (func == get_function(uphy, "pcie")) { - uphy->uphy_pll_users[0] &= ~BIT(func); - } else if (func == get_function(uphy, "sata")) { - uphy->uphy_pll_users[1] &= ~BIT(func); - } else if (func == get_function(uphy, "usb3")) { - uphy->uphy_pll_users[0] &= ~BIT(func); - uphy->uphy_pll_users[1] &= ~BIT(func); - } else - return -EINVAL; - - for (i = T21x_UPHY_PLLS - 1; i >= 0; i--) { - TRACE(dev, "PLL%d users 0x%lx\n", i, uphy->uphy_pll_users[i]); - if (uphy->uphy_pll_users[i] == 0) { - /* TODO error handling */ - rc = uphy_pll_power_down(uphy, i, func); - if (rc) - return rc; - } - } - - if ((uphy->uphy_pll_state[0] == UPHY_PLL_POWER_DOWN) && - (uphy->uphy_pll_state[1] == UPHY_PLL_POWER_DOWN)) { - rc = uphy_pll_source_clk_disable(uphy, i, func); - if (rc) - return rc; - } - - return 0; -} - /* caller must hold uphy->lock */ static int uphy_pll_reset_deassert(struct tegra_padctl_uphy *uphy, int pll) { @@ -1228,22 +1084,12 @@ static int uphy_pll_reset_deassert(struct tegra_padctl_uphy *uphy, int pll) if (pll < 0 || pll >= T21x_UPHY_PLLS) return -EINVAL; - TRACE(dev, "PLL%d clients %d\n", pll, uphy->uphy_pll_clients[pll]); - - if (WARN_ON(uphy->uphy_pll_clients[pll] < 0)) - return -EINVAL; - - if (uphy->uphy_pll_clients[pll]++ > 0) - goto out; - TRACE(dev, "deassert reset to PLL%d\n", pll); rc = reset_control_deassert(uphy->uphy_pll_rst[pll]); if (rc) { - uphy->uphy_pll_clients[pll]--; dev_err(dev, "failed to deassert reset PLL%d %d\n", pll, rc); } -out: return rc; } @@ -1256,21 +1102,12 @@ static int uphy_pll_reset_assert(struct tegra_padctl_uphy *uphy, int pll) if (pll < 0 || pll >= T21x_UPHY_PLLS) return -EINVAL; - TRACE(dev, "PLL%d clients %d\n", pll, uphy->uphy_pll_clients[pll]); - - if (WARN_ON(uphy->uphy_pll_clients[pll] == 0)) - return -EINVAL; - - if (--uphy->uphy_pll_clients[pll] > 0) - goto out; - TRACE(dev, "assert reset to PLL%d\n", pll); rc = reset_control_assert(uphy->uphy_pll_rst[pll]); if (rc) { - uphy->uphy_pll_clients[pll]++; dev_err(dev, "failed to assert reset for PLL%d %d\n", pll, rc); } -out: + return rc; } @@ -2111,35 +1948,6 @@ unlock_out: return rc; } -static int tegra21x_pcie_uphy_pll_deinit(struct tegra_padctl_uphy *uphy) -{ - int rc; - - TRACE(uphy->dev, "%s PCIE controller uphy-lanes 0x%lx\n", - __func__, uphy->pcie_lanes); - - mutex_lock(&uphy->lock); - - rc = uphy_pll_reset_assert(uphy, 0); - if (rc) - goto unlock_out; - - rc = uphy_pll_deinit(uphy, get_function(uphy, "pcie")); - if (rc) - goto deassert_pll0_reset; - - mutex_unlock(&uphy->lock); - - return 0; - -deassert_pll0_reset: - uphy_pll_reset_deassert(uphy, 0); -unlock_out: - mutex_unlock(&uphy->lock); - - return rc; -} - static int tegra21x_pcie_phy_init(struct phy *phy) { struct tegra_padctl_uphy *uphy = phy_get_drvdata(phy); @@ -2306,35 +2114,6 @@ unlock_out: return rc; } -static int tegra21x_sata_uphy_pll_deinit(struct tegra_padctl_uphy *uphy) -{ - struct device *dev = uphy->dev; - int rc; - - TRACE(dev, "SATA uphy-lanes 0x%lx\n", uphy->sata_lanes); - - mutex_lock(&uphy->lock); - - rc = uphy_pll_reset_assert(uphy, 1); - if (rc) - goto unlock_out; - - rc = uphy_pll_deinit(uphy, get_function(uphy, "sata")); - if (rc) - goto deassert_pll1_reset; - - mutex_unlock(&uphy->lock); - - return 0; - -deassert_pll1_reset: - uphy_pll_reset_deassert(uphy, 1); -unlock_out: - mutex_unlock(&uphy->lock); - - return rc; -} - static int tegra21x_sata_phy_init(struct phy *phy) { struct tegra_padctl_uphy *uphy = phy_get_drvdata(phy); @@ -2525,43 +2304,6 @@ unlock_out: return rc; } -static int tegra21x_usb3_uphy_pll_deinit(struct tegra_padctl_uphy *uphy) -{ - unsigned long uphy_lane_bitmap; - int rc; - - uphy_lane_bitmap = uphy->usb3_lanes; - TRACE(uphy->dev, "XUSB controller uphy-lanes 0x%lx\n", - uphy_lane_bitmap); - - mutex_lock(&uphy->lock); - - rc = uphy_pll_reset_assert(uphy, 0); - if (rc) - goto unlock_out; - - rc = uphy_pll_reset_assert(uphy, 1); - if (rc) - goto deassert_pll0_reset; - - rc = uphy_pll_deinit(uphy, get_function(uphy, "usb3")); - if (rc) - goto deassert_pll1_reset; - - mutex_unlock(&uphy->lock); - - return 0; - -deassert_pll1_reset: - uphy_pll_reset_deassert(uphy, 1); -deassert_pll0_reset: - uphy_pll_reset_deassert(uphy, 0); -unlock_out: - mutex_unlock(&uphy->lock); - - return rc; -} - static int tegra21x_usb3_phy_init(struct phy *phy) { struct tegra_padctl_uphy *uphy = phy_get_drvdata(phy); @@ -4179,7 +3921,10 @@ static int tegra21x_uphy_pll_init(struct tegra_padctl_uphy *uphy) return rc; } - if (uphy->sata_lanes) { + /* always enable SATA PLL HW sequencer to ensure PLLE could + * enable HW sequencer, set SATA PLL to SATA as default + */ + if (!(uphy->usb3_lanes & SATA_LANE_MASK)) { rc = tegra21x_sata_uphy_pll_init(uphy); if (rc) return rc; @@ -4188,31 +3933,6 @@ static int tegra21x_uphy_pll_init(struct tegra_padctl_uphy *uphy) return 0; } -static int tegra21x_uphy_pll_deinit(struct tegra_padctl_uphy *uphy) -{ - int rc; - - if (uphy->pcie_lanes) { - rc = tegra21x_pcie_uphy_pll_deinit(uphy); - if (rc) - return rc; - } - - if (uphy->usb3_lanes) { - rc = tegra21x_usb3_uphy_pll_deinit(uphy); - if (rc) - return rc; - } - - if (uphy->sata_lanes) { - rc = tegra21x_sata_uphy_pll_deinit(uphy); - if (rc) - return rc; - } - - return 0; -} - static void tegra21x_padctl_save(struct tegra_padctl_uphy *uphy) { uphy->padctl_context.vbus_id = @@ -4241,7 +3961,12 @@ static int tegra21x_padctl_uphy_suspend(struct device *dev) tegra21x_padctl_save(uphy); - return tegra21x_uphy_pll_deinit(uphy); + clk_disable_unprepare(uphy->plle); + uphy->plle_state = PLL_POWER_DOWN; + uphy->uphy_pll_state[0] = UPHY_PLL_POWER_DOWN; + uphy->uphy_pll_state[1] = UPHY_PLL_POWER_DOWN; + + return 0; } static int tegra21x_padctl_uphy_resume(struct device *dev) @@ -4252,7 +3977,20 @@ static int tegra21x_padctl_uphy_resume(struct device *dev) tegra21x_padctl_restore(uphy); - return tegra21x_uphy_pll_init(uphy); + if (tegra210_plle_hw_sequence_is_enabled()) { + /* PLLE in HW when .resume_noirq being called indicated system + * didn't reach SC7. Hence skip PLL init and invoke + * clk_prepare_enable(uphy->plle) to update PLLE enable_count. + * Please note that clk_plle_tegra210_enable won't update PLLE + * regs if PLLE is in HW. + */ + TRACE(dev, "skip PLL init as PLLE in HW"); + uphy->uphy_pll_state[0] = UPHY_PLL_POWER_UP_HW_SEQ; + uphy->uphy_pll_state[1] = UPHY_PLL_POWER_UP_HW_SEQ; + uphy->plle_state = PLL_POWER_UP_HW_SEQ; + return clk_prepare_enable(uphy->plle); + } else + return tegra21x_uphy_pll_init(uphy); } static const struct dev_pm_ops tegra21x_padctl_uphy_pm_ops = { @@ -4497,7 +4235,6 @@ static int tegra21x_padctl_uphy_remove(struct platform_device *pdev) mbox_free_channel(uphy->mbox_chan); } - tegra21x_uphy_pll_deinit(uphy); pinctrl_unregister(uphy->pinctrl); reset_control_assert(uphy->padctl_rst); regulator_bulk_disable(uphy->soc->num_supplies, uphy->supplies);