Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: tegra: Add PLLE HW power sequencer control

PLLE has a hardware power sequencer logic which is a state machine
that can power on/off PLLE without any software intervention. The
sequencer has two inputs, one from XUSB UPHY PLL and the other from
SATA UPHY PLL. PLLE provides reference clock to XUSB and SATA UPHY
PLLs. When both of the downstream PLLs are powered-off, PLLE hardware
power sequencer will automatically power off PLLE for power saving.

XUSB and SATA UPHY PLLs also have their own hardware power sequencer
logic. XUSB UPHY PLL is shared between XUSB SuperSpeed ports and PCIE
controllers. The XUSB UPHY PLL hardware power sequencer has inputs
from XUSB and PCIE. When all of the XUSB SuperSpeed ports and PCIE
controllers are in low power state, XUSB UPHY PLL hardware power
sequencer automatically power off PLL and flags idle to PLLE hardware
power sequencer. Similar applies to SATA UPHY PLL.

PLLE hardware power sequencer has to be enabled after both downstream
sequencers are enabled.

This commit adds two helper functions:
1. tegra210_plle_hw_sequence_start() for XUSB PADCTL driver to enable
PLLE hardware sequencer at proper time.

2. tegra210_plle_hw_sequence_is_enabled() for XUSB PADCTL driver to
check whether PLLE hardware sequencer has been enabled or not.

Signed-off-by: JC Kuo <jckuo@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Acked-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

JC Kuo and committed by
Thierry Reding
54443ef6 a38fd874

+55 -2
+52 -1
drivers/clk/tegra/clk-tegra210.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 - * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved. 3 + * Copyright (c) 2012-2020 NVIDIA CORPORATION. All rights reserved. 4 4 */ 5 5 6 6 #include <linux/io.h> ··· 403 403 #define PLLRE_BASE_DEFAULT_MASK 0x1c000000 404 404 #define PLLRE_MISC0_WRITE_MASK 0x67ffffff 405 405 406 + /* PLLE */ 407 + #define PLLE_MISC_IDDQ_SW_CTRL (1 << 14) 408 + #define PLLE_AUX_USE_LOCKDET (1 << 3) 409 + #define PLLE_AUX_SS_SEQ_INCLUDE (1 << 31) 410 + #define PLLE_AUX_ENABLE_SWCTL (1 << 4) 411 + #define PLLE_AUX_SS_SWCTL (1 << 6) 412 + #define PLLE_AUX_SEQ_ENABLE (1 << 24) 413 + 406 414 /* PLLX */ 407 415 #define PLLX_USE_DYN_RAMP 1 408 416 #define PLLX_BASE_LOCK (1 << 27) ··· 496 488 497 489 #define PLLU_MISC0_WRITE_MASK 0xbfffffff 498 490 #define PLLU_MISC1_WRITE_MASK 0x00000007 491 + 492 + bool tegra210_plle_hw_sequence_is_enabled(void) 493 + { 494 + u32 value; 495 + 496 + value = readl_relaxed(clk_base + PLLE_AUX); 497 + if (value & PLLE_AUX_SEQ_ENABLE) 498 + return true; 499 + 500 + return false; 501 + } 502 + EXPORT_SYMBOL_GPL(tegra210_plle_hw_sequence_is_enabled); 503 + 504 + int tegra210_plle_hw_sequence_start(void) 505 + { 506 + u32 value; 507 + 508 + if (tegra210_plle_hw_sequence_is_enabled()) 509 + return 0; 510 + 511 + /* skip if PLLE is not enabled yet */ 512 + value = readl_relaxed(clk_base + PLLE_MISC0); 513 + if (!(value & PLLE_MISC_LOCK)) 514 + return -EIO; 515 + 516 + value &= ~PLLE_MISC_IDDQ_SW_CTRL; 517 + writel_relaxed(value, clk_base + PLLE_MISC0); 518 + 519 + value = readl_relaxed(clk_base + PLLE_AUX); 520 + value |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SS_SEQ_INCLUDE); 521 + value &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL); 522 + writel_relaxed(value, clk_base + PLLE_AUX); 523 + 524 + fence_udelay(1, clk_base); 525 + 526 + value |= PLLE_AUX_SEQ_ENABLE; 527 + writel_relaxed(value, clk_base + PLLE_AUX); 528 + 529 + fence_udelay(1, clk_base); 530 + 531 + return 0; 532 + } 533 + EXPORT_SYMBOL_GPL(tegra210_plle_hw_sequence_start); 499 534 500 535 void tegra210_xusb_pll_hw_control_enable(void) 501 536 {
+3 -1
include/linux/clk/tegra.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 2 /* 3 - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 3 + * Copyright (c) 2012-2020, NVIDIA CORPORATION. All rights reserved. 4 4 */ 5 5 6 6 #ifndef __LINUX_CLK_TEGRA_H_ ··· 123 123 } 124 124 #endif 125 125 126 + extern int tegra210_plle_hw_sequence_start(void); 127 + extern bool tegra210_plle_hw_sequence_is_enabled(void); 126 128 extern void tegra210_xusb_pll_hw_control_enable(void); 127 129 extern void tegra210_xusb_pll_hw_sequence_start(void); 128 130 extern void tegra210_sata_pll_hw_control_enable(void);