Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp2474534pxj; Mon, 10 May 2021 04:00:51 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxrfIq814Doul20KDzAeXQEkx+Cj2TkgQwWDpVmGYA5D1dE8z73XAuMO00RGVLVby/pVjBD X-Received: by 2002:a02:cac6:: with SMTP id f6mr20779539jap.118.1620644451643; Mon, 10 May 2021 04:00:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1620644451; cv=none; d=google.com; s=arc-20160816; b=cVXjZPtQxPCuYDKO0AxIGrC3HGVcB7tf7/HTr1+0BD/20Udwbrutt9QeACQLgwGedd faRoCZS1kTRwkcIR/DhcWPZzKFvO4pyfd9bvhjphUNl1TjCIHjglZCJwzAm87GAN49rJ iXeV/JPHEizg8tUeDt5BahbQcymKKBmG/ms6gVKBett/w6W56jsRxQLkscf79XS+xRlw rbLGXyboX2iBpR/eCDxzMAqGv/4aplCJyP3K2QQ8On+QxufUDZH/wGymhJlPvZL3p4J5 y0ZbhOH+pA44ZYXA0bm2EcDSkmqTcRoQnG1ntflp2dYD5Der3+oB6HsnLQBSqrfbjrf1 2YMg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=pHbSXj2y2cF56fDXTGhZvF+yU5ToFEaSebZiP4LN9h8=; b=hrpAGoKWTt1CbCOfw0aCS15Y8/2XkAOI9K6IEdo8cWrtbYE696XWN/I/4Fkx2XRwyt Df4SzGo0poFUVW/JhcisrI99A1Xwl1J3laW5Bz+VkLtEMsFT4JFdr8DmbsdyH0sNWviZ pqQ7kZ0UxMTXMrZrIq0Hz5lXe1h3BWkf55jsKjkVv2BKQp2hvjoaLCffUFbWBvA3B9Cg h990qOmEQUp7MmZ9G9UNJY26WIRa9KofLD6ARqQx6fEc4L9I8bm5YlN6sUnpCwQgb9+8 NlY579OtwCbTzCcnzQ6En4TE3WzrMw1LCMUsJu5M82tCo/0NW3VG/MqEGzfAJlIEn3bt hRfQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="Xy6oK/a4"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id s18si16509636ilh.102.2021.05.10.04.00.39; Mon, 10 May 2021 04:00:51 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="Xy6oK/a4"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234746AbhEJK47 (ORCPT + 99 others); Mon, 10 May 2021 06:56:59 -0400 Received: from mail.kernel.org ([198.145.29.99]:59364 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232918AbhEJKos (ORCPT ); Mon, 10 May 2021 06:44:48 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 6828461490; Mon, 10 May 2021 10:34:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1620642849; bh=wI1dsvOOauyYQKFpCjEHM1QSg0+agMfdoJoT1LE5Xrg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Xy6oK/a4yGR/jbNbudgZ5LzQtCvSSuOsx9kwe0FEpZmDHbysTmztrMdZ2SVVNMUfQ xLxWNXfBkvYVYMzgCZoto2STJXvrhQuI/rizHjCOzEEfLUqeTpqmQhfY1T6akxm9qq rgC27Ci5zaTd/CuAbYgCU/mdJXEbzQy2N7CAUMho= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Dmitry Osipenko , Thierry Reding , Sasha Levin , Peter Geis , Nicolas Chauvet , Matt Merhar Subject: [PATCH 5.10 076/299] soc/tegra: pmc: Fix completion of power-gate toggling Date: Mon, 10 May 2021 12:17:53 +0200 Message-Id: <20210510102007.436198951@linuxfoundation.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210510102004.821838356@linuxfoundation.org> References: <20210510102004.821838356@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Dmitry Osipenko [ Upstream commit c45e66a6b9f40f2e95bc6d97fbf3daa1ebe88c6b ] The SW-initiated power gate toggling is dropped by PMC if there is contention with a HW-initiated toggling, i.e. when one of CPU cores is gated by cpuidle driver. Software should retry the toggling after 10 microseconds on Tegra20/30 SoCs, hence add the retrying. On Tegra114+ the toggling method was changed in hardware, the TOGGLE_START bit indicates whether PMC is busy or could accept the command to toggle, hence handle that bit properly. The problem pops up after enabling dynamic power gating of 3D hardware, where 3D power domain fails to turn on/off "randomly". The programming sequence and quirks are documented in TRMs, but PMC driver obliviously re-used the Tegra20 logic for Tegra30+, which strikes back now. The 10 microseconds and other timeouts aren't documented in TRM, they are taken from downstream kernel. Link: https://nv-tegra.nvidia.com/gitweb/?p=linux-2.6.git;a=commit;h=311dd1c318b70e93bcefec15456a10ff2b9eb0ff Link: https://nv-tegra.nvidia.com/gitweb/?p=linux-3.10.git;a=commit;h=7f36693c47cb23730a6b2822e0975be65fb0c51d Tested-by: Peter Geis # Ouya T30 Tested-by: Nicolas Chauvet # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar # Ouya T30 Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin --- drivers/soc/tegra/pmc.c | 70 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index df9a5ca8c99c..0118bd986f90 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -317,6 +317,8 @@ struct tegra_pmc_soc { bool invert); int (*irq_set_wake)(struct irq_data *data, unsigned int on); int (*irq_set_type)(struct irq_data *data, unsigned int type); + int (*powergate_set)(struct tegra_pmc *pmc, unsigned int id, + bool new_state); const char * const *reset_sources; unsigned int num_reset_sources; @@ -517,6 +519,63 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) return -ENODEV; } +static int tegra20_powergate_set(struct tegra_pmc *pmc, unsigned int id, + bool new_state) +{ + unsigned int retries = 100; + bool status; + int ret; + + /* + * As per TRM documentation, the toggle command will be dropped by PMC + * if there is contention with a HW-initiated toggling (i.e. CPU core + * power-gated), the command should be retried in that case. + */ + do { + tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); + + /* wait for PMC to execute the command */ + ret = readx_poll_timeout(tegra_powergate_state, id, status, + status == new_state, 1, 10); + } while (ret == -ETIMEDOUT && retries--); + + return ret; +} + +static inline bool tegra_powergate_toggle_ready(struct tegra_pmc *pmc) +{ + return !(tegra_pmc_readl(pmc, PWRGATE_TOGGLE) & PWRGATE_TOGGLE_START); +} + +static int tegra114_powergate_set(struct tegra_pmc *pmc, unsigned int id, + bool new_state) +{ + bool status; + int err; + + /* wait while PMC power gating is contended */ + err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status, + status == true, 1, 100); + if (err) + return err; + + tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); + + /* wait for PMC to accept the command */ + err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status, + status == true, 1, 100); + if (err) + return err; + + /* wait for PMC to execute the command */ + err = readx_poll_timeout(tegra_powergate_state, id, status, + status == new_state, 10, 100000); + if (err) + return err; + + return 0; +} + /** * tegra_powergate_set() - set the state of a partition * @pmc: power management controller @@ -526,7 +585,6 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) static int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id, bool new_state) { - bool status; int err; if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) @@ -539,10 +597,7 @@ static int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id, return 0; } - tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); - - err = readx_poll_timeout(tegra_powergate_state, id, status, - status == new_state, 10, 100000); + err = pmc->soc->powergate_set(pmc, id, new_state); mutex_unlock(&pmc->powergates_lock); @@ -2699,6 +2754,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra20_powergate_set, .reset_sources = NULL, .num_reset_sources = 0, .reset_levels = NULL, @@ -2757,6 +2813,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra20_powergate_set, .reset_sources = tegra30_reset_sources, .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, @@ -2811,6 +2868,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra114_powergate_set, .reset_sources = tegra30_reset_sources, .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, @@ -2925,6 +2983,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra114_powergate_set, .reset_sources = tegra30_reset_sources, .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, @@ -3048,6 +3107,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra114_powergate_set, .irq_set_wake = tegra210_pmc_irq_set_wake, .irq_set_type = tegra210_pmc_irq_set_type, .reset_sources = tegra210_reset_sources, -- 2.30.2