From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-lf1-f52.google.com (mail-lf1-f52.google.com [209.85.167.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 863C76D19 for ; Tue, 17 Aug 2021 01:30:36 +0000 (UTC) Received: by mail-lf1-f52.google.com with SMTP id p38so38354037lfa.0 for ; Mon, 16 Aug 2021 18:30:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Ao2JLfYPSHHhEgaGHBXF51D99ohQhpgr3//KrDL4XpQ=; b=uZ5fJP5Fm54nU+vvAkJbEQxeHZQIUFPbGLg/dS7NUGAkOu1ZqEf9VpiHOFtfecrXZI tTrtZ4dAa1UWo1lHFKhNl/EMUzN0mP7e6yJNy3bCUUYB7WnbrjOqGLEBtBMx4oISIyfk TkMpSOVGMlCO4hB9V1CdIIcRqOpEjJ3fqEDOCyjvUcFCmxzn5JLikTI7H+G1sUstYmcd j0JmV6zn6m13AS3+1+VlQ4CRZfq2D1xyWoBuKcRxt6eet1fVzuR8jV/quGAn9nLkz5AS YhSS8PvqeM7JDPrZqeFpb9OGNXxDosW8tZ0Un5wAHYm25FvW7AKwa/0Qu7K7r/kEZo/V N8MA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Ao2JLfYPSHHhEgaGHBXF51D99ohQhpgr3//KrDL4XpQ=; b=ZAJDz+kykZ7AmNkqVbFsH5a11lPKfZdt+VVxUNMKzv7cdEuiLrTWaDh3T0yQzIG1fP GAy6hXPNbm7ZDNkg40LhzZeyBtYMRW22LSTTJ2CBAi7sMQe1qkyGkkvFPEfO6HiqQDZZ YEawARs/f310C1Zsih/bwigi1rlPIXWtqzVDFuxp4teXRnTB8YAdX8r2FZDtPgn+YwUK ghnblpHOlazZty8o5DxHtOUOzltJglfXJjH6vrxT1YfW5K2wc1TfHMO0u3xu+M9HGwEL POrepLmjVvrbMGwqU1yRrJy65bopZOoMQnOmsVqRVoczxmS7YzTL7oT9bmLgtJVbW8XN R1Rg== X-Gm-Message-State: AOAM531cRqPJnVNgKFUVhRjKo7qowJn4GXl0d4W97/1Usr+sL350S5Fv ySndYWuES+LWPZ3O17m7UH4= X-Google-Smtp-Source: ABdhPJxEPMv3pBMrZvDnxLqyqEGWzhHmjNIWiVXkcPQuvhYSVN0NUXWVnAaHZUNdp8KzOuF0xPfC2Q== X-Received: by 2002:ac2:5542:: with SMTP id l2mr496723lfk.551.1629163834738; Mon, 16 Aug 2021 18:30:34 -0700 (PDT) Received: from localhost.localdomain (46-138-85-91.dynamic.spd-mgts.ru. [46.138.85.91]) by smtp.gmail.com with ESMTPSA id g30sm46607lfj.298.2021.08.16.18.30.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Aug 2021 18:30:34 -0700 (PDT) From: Dmitry Osipenko To: Thierry Reding , Jonathan Hunter , Ulf Hansson , Viresh Kumar , Stephen Boyd , Peter De Schrijver , Mikko Perttunen , Peter Chen , Mark Brown , Lee Jones , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , Nishanth Menon , Vignesh Raghavendra , Richard Weinberger , Miquel Raynal , Lucas Stach , Stefan Agner , Adrian Hunter , Mauro Carvalho Chehab , Rob Herring , Michael Turquette Cc: linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-staging@lists.linux.dev, linux-spi@vger.kernel.org, linux-pwm@vger.kernel.org, linux-mtd@lists.infradead.org, linux-mmc@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-clk@vger.kernel.org Subject: [PATCH v8 28/34] soc/tegra: regulators: Prepare for suspend Date: Tue, 17 Aug 2021 04:27:48 +0300 Message-Id: <20210817012754.8710-29-digetx@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210817012754.8710-1-digetx@gmail.com> References: <20210817012754.8710-1-digetx@gmail.com> Precedence: bulk X-Mailing-List: linux-staging@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Depending on hardware version, Tegra SoC may require a higher voltages during resume from system suspend, otherwise hardware will crash. Set SoC voltages to a nominal levels during suspend. Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/regulators-tegra20.c | 99 ++++++++++++++++++++ drivers/soc/tegra/regulators-tegra30.c | 122 +++++++++++++++++++++++++ 2 files changed, 221 insertions(+) diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c index b8ce9fd0650d..6a2f90ab9d3e 100644 --- a/drivers/soc/tegra/regulators-tegra20.c +++ b/drivers/soc/tegra/regulators-tegra20.c @@ -16,7 +16,9 @@ #include #include #include +#include +#include #include struct tegra_regulator_coupler { @@ -25,9 +27,12 @@ struct tegra_regulator_coupler { struct regulator_dev *cpu_rdev; struct regulator_dev *rtc_rdev; struct notifier_block reboot_notifier; + struct notifier_block suspend_notifier; int core_min_uV, cpu_min_uV; bool sys_reboot_mode_req; bool sys_reboot_mode; + bool sys_suspend_mode_req; + bool sys_suspend_mode; }; static inline struct tegra_regulator_coupler * @@ -105,6 +110,28 @@ static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev, return 150000; } +static int tegra20_cpu_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + case 0: + return 1100000; + case 1: + return 1025000; + default: + return 1125000; + } +} + +static int tegra20_core_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + default: + return 1225000; + case 2: + return 1300000; + } +} + static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, struct regulator_dev *core_rdev, struct regulator_dev *rtc_rdev, @@ -144,6 +171,11 @@ static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, if (err) return err; + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + core_min_uV = clamp(tegra20_core_nominal_uV(), + core_min_uV, core_max_uV); + core_uV = regulator_get_voltage_rdev(core_rdev); if (core_uV < 0) return core_uV; @@ -279,6 +311,11 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, if (tegra->sys_reboot_mode) cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + cpu_min_uV = clamp(tegra20_cpu_nominal_uV(), + cpu_min_uV, cpu_max_uV); + if (cpu_min_uV > cpu_uV) { err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev, cpu_uV, cpu_min_uV); @@ -320,6 +357,7 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, } tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req); if (rdev == cpu_rdev) return tegra20_cpu_voltage_update(tegra, cpu_rdev, @@ -334,6 +372,63 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, return -EPERM; } +static int tegra20_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra, + bool sys_suspend_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev) + return 0; + + /* + * All power domains are enabled early during resume from suspend + * by GENPD core. Domains like VENC may require a higher voltage + * when enabled during resume from suspend. This also prepares + * hardware for resuming from LP0. + */ + + WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode); + + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + return 0; +} + +static int tegra20_regulator_suspend(struct notifier_block *notifier, + unsigned long mode, void *arg) +{ + struct tegra_regulator_coupler *tegra; + int ret = 0; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + suspend_notifier); + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + case PM_SUSPEND_PREPARE: + ret = tegra20_regulator_prepare_suspend(tegra, true); + break; + + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + ret = tegra20_regulator_prepare_suspend(tegra, false); + break; + } + + if (ret) + pr_err("failed to prepare regulators: %d\n", ret); + + return notifier_from_errno(ret); +} + static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, bool sys_reboot_mode) { @@ -444,6 +539,7 @@ static struct tegra_regulator_coupler tegra20_coupler = { .balance_voltage = tegra20_regulator_balance_voltage, }, .reboot_notifier.notifier_call = tegra20_regulator_reboot, + .suspend_notifier.notifier_call = tegra20_regulator_suspend, }; static int __init tegra_regulator_coupler_init(void) @@ -456,6 +552,9 @@ static int __init tegra_regulator_coupler_init(void) err = register_reboot_notifier(&tegra20_coupler.reboot_notifier); WARN_ON(err); + err = register_pm_notifier(&tegra20_coupler.suspend_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra20_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c index e74bbc9c7859..8fd43c689134 100644 --- a/drivers/soc/tegra/regulators-tegra30.c +++ b/drivers/soc/tegra/regulators-tegra30.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,9 +26,12 @@ struct tegra_regulator_coupler { struct regulator_dev *core_rdev; struct regulator_dev *cpu_rdev; struct notifier_block reboot_notifier; + struct notifier_block suspend_notifier; int core_min_uV, cpu_min_uV; bool sys_reboot_mode_req; bool sys_reboot_mode; + bool sys_suspend_mode_req; + bool sys_suspend_mode; }; static inline struct tegra_regulator_coupler * @@ -113,6 +117,52 @@ static int tegra30_core_cpu_limit(int cpu_uV) return -EINVAL; } +static int tegra30_cpu_nominal_uV(void) +{ + switch (tegra_sku_info.cpu_speedo_id) { + case 10 ... 11: + return 850000; + + case 9: + return 912000; + + case 1 ... 3: + case 7 ... 8: + return 1050000; + + default: + return 1125000; + + case 4 ... 6: + case 12 ... 13: + return 1237000; + } +} + +static int tegra30_core_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + case 0: + return 1200000; + + case 1: + if (tegra_sku_info.cpu_speedo_id != 7 && + tegra_sku_info.cpu_speedo_id != 8) + return 1200000; + + fallthrough; + + case 2: + if (tegra_sku_info.cpu_speedo_id != 13) + return 1300000; + + return 1350000; + + default: + return 1250000; + } +} + static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, struct regulator_dev *cpu_rdev, struct regulator_dev *core_rdev) @@ -168,6 +218,11 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (err) return err; + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + core_min_uV = clamp(tegra30_core_nominal_uV(), + core_min_uV, core_max_uV); + core_uV = regulator_get_voltage_rdev(core_rdev); if (core_uV < 0) return core_uV; @@ -223,6 +278,11 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (tegra->sys_reboot_mode) cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + cpu_min_uV = clamp(tegra30_cpu_nominal_uV(), + cpu_min_uV, cpu_max_uV); + if (core_min_limited_uV > core_uV) { pr_err("core voltage constraint violated: %d %d %d\n", core_uV, core_min_limited_uV, cpu_uV); @@ -292,10 +352,68 @@ static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler, } tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req); return tegra30_voltage_update(tegra, cpu_rdev, core_rdev); } +static int tegra30_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra, + bool sys_suspend_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->cpu_rdev) + return 0; + + /* + * All power domains are enabled early during resume from suspend + * by GENPD core. Domains like VENC may require a higher voltage + * when enabled during resume from suspend. This also prepares + * hardware for resuming from LP0. + */ + + WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode); + + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + return 0; +} + +static int tegra30_regulator_suspend(struct notifier_block *notifier, + unsigned long mode, void *arg) +{ + struct tegra_regulator_coupler *tegra; + int ret = 0; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + suspend_notifier); + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + case PM_SUSPEND_PREPARE: + ret = tegra30_regulator_prepare_suspend(tegra, true); + break; + + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + ret = tegra30_regulator_prepare_suspend(tegra, false); + break; + } + + if (ret) + pr_err("failed to prepare regulators: %d\n", ret); + + return notifier_from_errno(ret); +} + static int tegra30_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, bool sys_reboot_mode) { @@ -395,6 +513,7 @@ static struct tegra_regulator_coupler tegra30_coupler = { .balance_voltage = tegra30_regulator_balance_voltage, }, .reboot_notifier.notifier_call = tegra30_regulator_reboot, + .suspend_notifier.notifier_call = tegra30_regulator_suspend, }; static int __init tegra_regulator_coupler_init(void) @@ -407,6 +526,9 @@ static int __init tegra_regulator_coupler_init(void) err = register_reboot_notifier(&tegra30_coupler.reboot_notifier); WARN_ON(err); + err = register_pm_notifier(&tegra30_coupler.suspend_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra30_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); -- 2.32.0 From mboxrd@z Thu Jan 1 00:00:00 1970 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=-10.9 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, UNWANTED_LANGUAGE_BODY,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 27491C4338F for ; Tue, 17 Aug 2021 02:30:12 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DC15460184 for ; Tue, 17 Aug 2021 02:30:11 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org DC15460184 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=IsQG2n1F0oUaeFoOOGYc40dLuF6pOS5suMm7vOFy1HY=; b=leojicsxP70y3y W8oHfiuZXde2DOHKnxLTnjWk0BRvkCiicQ2vNnklkrxIzb/PHYKLJPz1crLND08/yFBj4hteh3lOt euyHcGBcQSiagb5zQKhJPBGsg0NR+ahxiLeqMfsArn4taxkms+y55bH4cwVOoAqPgIWcdmDdDtxzZ SI17KArEkOEBQ3VzjHMVLwNpVCEJ+gMpGW2lmp8V7oHaCkDIqhO66usnqvv1WkUQyfZ7fqXG6dFje RLEm/lHegvHXjRr2TknXK3v2lmYnMufmL+EFhHcXELN4YRYlIBoaFcQOElgWP3d85oyhlily+GOSk xGrtFmvCiMfB7Q0gqKKw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mFor0-000pPm-Ms; Tue, 17 Aug 2021 02:29:27 +0000 Received: from mail-lf1-x12b.google.com ([2a00:1450:4864:20::12b]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mFnw5-000h1L-Ds for linux-mtd@lists.infradead.org; Tue, 17 Aug 2021 01:30:42 +0000 Received: by mail-lf1-x12b.google.com with SMTP id d4so38105193lfk.9 for ; Mon, 16 Aug 2021 18:30:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Ao2JLfYPSHHhEgaGHBXF51D99ohQhpgr3//KrDL4XpQ=; b=uZ5fJP5Fm54nU+vvAkJbEQxeHZQIUFPbGLg/dS7NUGAkOu1ZqEf9VpiHOFtfecrXZI tTrtZ4dAa1UWo1lHFKhNl/EMUzN0mP7e6yJNy3bCUUYB7WnbrjOqGLEBtBMx4oISIyfk TkMpSOVGMlCO4hB9V1CdIIcRqOpEjJ3fqEDOCyjvUcFCmxzn5JLikTI7H+G1sUstYmcd j0JmV6zn6m13AS3+1+VlQ4CRZfq2D1xyWoBuKcRxt6eet1fVzuR8jV/quGAn9nLkz5AS YhSS8PvqeM7JDPrZqeFpb9OGNXxDosW8tZ0Un5wAHYm25FvW7AKwa/0Qu7K7r/kEZo/V N8MA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Ao2JLfYPSHHhEgaGHBXF51D99ohQhpgr3//KrDL4XpQ=; b=fxtUXV61u48W1OpYRrDx9JXdVRkJJQ5Irebh5OjYLLswJ8gSqdSb+8iXtN6Peq3x2A /CEVSW8LI4BReNsWgAP5gyWDFeGB82uG1MjSk1gZzPv1Bat/JubYyGB0KmDBm/60I4WD ucMASsDn1gyzwxNBRY6CBbBHYvlH4fI4+8pZ71CQDUkqvAtNbQ0OkeCIqV/12kB9trUg 8Qfb8DAqYLrpJki2m2ak0YXPG4wA0KQpv5ZIt0QxDdChtC2p11CCvV4//x48cBwFnVwJ mC+4TSRGT+cTPbC3WHHh1wPocm/u9y6lddp853F4ftc8Lv03/4rvQ5bejc/vRu1+T1EW YVrQ== X-Gm-Message-State: AOAM5327q6h6WKFD/lDMm5a32crU3cKbKcsTfWOVIRDJMJHXTTXwurgB Hr+Yai1r2SQX9/iIxuBc2Ic= X-Google-Smtp-Source: ABdhPJxEPMv3pBMrZvDnxLqyqEGWzhHmjNIWiVXkcPQuvhYSVN0NUXWVnAaHZUNdp8KzOuF0xPfC2Q== X-Received: by 2002:ac2:5542:: with SMTP id l2mr496723lfk.551.1629163834738; Mon, 16 Aug 2021 18:30:34 -0700 (PDT) Received: from localhost.localdomain (46-138-85-91.dynamic.spd-mgts.ru. [46.138.85.91]) by smtp.gmail.com with ESMTPSA id g30sm46607lfj.298.2021.08.16.18.30.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Aug 2021 18:30:34 -0700 (PDT) From: Dmitry Osipenko To: Thierry Reding , Jonathan Hunter , Ulf Hansson , Viresh Kumar , Stephen Boyd , Peter De Schrijver , Mikko Perttunen , Peter Chen , Mark Brown , Lee Jones , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , Nishanth Menon , Vignesh Raghavendra , Richard Weinberger , Miquel Raynal , Lucas Stach , Stefan Agner , Adrian Hunter , Mauro Carvalho Chehab , Rob Herring , Michael Turquette Cc: linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-staging@lists.linux.dev, linux-spi@vger.kernel.org, linux-pwm@vger.kernel.org, linux-mtd@lists.infradead.org, linux-mmc@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-clk@vger.kernel.org Subject: [PATCH v8 28/34] soc/tegra: regulators: Prepare for suspend Date: Tue, 17 Aug 2021 04:27:48 +0300 Message-Id: <20210817012754.8710-29-digetx@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210817012754.8710-1-digetx@gmail.com> References: <20210817012754.8710-1-digetx@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210816_183037_564360_D19F07EF X-CRM114-Status: GOOD ( 20.87 ) X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-mtd" Errors-To: linux-mtd-bounces+linux-mtd=archiver.kernel.org@lists.infradead.org Depending on hardware version, Tegra SoC may require a higher voltages during resume from system suspend, otherwise hardware will crash. Set SoC voltages to a nominal levels during suspend. Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/regulators-tegra20.c | 99 ++++++++++++++++++++ drivers/soc/tegra/regulators-tegra30.c | 122 +++++++++++++++++++++++++ 2 files changed, 221 insertions(+) diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c index b8ce9fd0650d..6a2f90ab9d3e 100644 --- a/drivers/soc/tegra/regulators-tegra20.c +++ b/drivers/soc/tegra/regulators-tegra20.c @@ -16,7 +16,9 @@ #include #include #include +#include +#include #include struct tegra_regulator_coupler { @@ -25,9 +27,12 @@ struct tegra_regulator_coupler { struct regulator_dev *cpu_rdev; struct regulator_dev *rtc_rdev; struct notifier_block reboot_notifier; + struct notifier_block suspend_notifier; int core_min_uV, cpu_min_uV; bool sys_reboot_mode_req; bool sys_reboot_mode; + bool sys_suspend_mode_req; + bool sys_suspend_mode; }; static inline struct tegra_regulator_coupler * @@ -105,6 +110,28 @@ static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev, return 150000; } +static int tegra20_cpu_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + case 0: + return 1100000; + case 1: + return 1025000; + default: + return 1125000; + } +} + +static int tegra20_core_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + default: + return 1225000; + case 2: + return 1300000; + } +} + static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, struct regulator_dev *core_rdev, struct regulator_dev *rtc_rdev, @@ -144,6 +171,11 @@ static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, if (err) return err; + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + core_min_uV = clamp(tegra20_core_nominal_uV(), + core_min_uV, core_max_uV); + core_uV = regulator_get_voltage_rdev(core_rdev); if (core_uV < 0) return core_uV; @@ -279,6 +311,11 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, if (tegra->sys_reboot_mode) cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + cpu_min_uV = clamp(tegra20_cpu_nominal_uV(), + cpu_min_uV, cpu_max_uV); + if (cpu_min_uV > cpu_uV) { err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev, cpu_uV, cpu_min_uV); @@ -320,6 +357,7 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, } tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req); if (rdev == cpu_rdev) return tegra20_cpu_voltage_update(tegra, cpu_rdev, @@ -334,6 +372,63 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, return -EPERM; } +static int tegra20_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra, + bool sys_suspend_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev) + return 0; + + /* + * All power domains are enabled early during resume from suspend + * by GENPD core. Domains like VENC may require a higher voltage + * when enabled during resume from suspend. This also prepares + * hardware for resuming from LP0. + */ + + WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode); + + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + return 0; +} + +static int tegra20_regulator_suspend(struct notifier_block *notifier, + unsigned long mode, void *arg) +{ + struct tegra_regulator_coupler *tegra; + int ret = 0; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + suspend_notifier); + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + case PM_SUSPEND_PREPARE: + ret = tegra20_regulator_prepare_suspend(tegra, true); + break; + + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + ret = tegra20_regulator_prepare_suspend(tegra, false); + break; + } + + if (ret) + pr_err("failed to prepare regulators: %d\n", ret); + + return notifier_from_errno(ret); +} + static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, bool sys_reboot_mode) { @@ -444,6 +539,7 @@ static struct tegra_regulator_coupler tegra20_coupler = { .balance_voltage = tegra20_regulator_balance_voltage, }, .reboot_notifier.notifier_call = tegra20_regulator_reboot, + .suspend_notifier.notifier_call = tegra20_regulator_suspend, }; static int __init tegra_regulator_coupler_init(void) @@ -456,6 +552,9 @@ static int __init tegra_regulator_coupler_init(void) err = register_reboot_notifier(&tegra20_coupler.reboot_notifier); WARN_ON(err); + err = register_pm_notifier(&tegra20_coupler.suspend_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra20_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c index e74bbc9c7859..8fd43c689134 100644 --- a/drivers/soc/tegra/regulators-tegra30.c +++ b/drivers/soc/tegra/regulators-tegra30.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,9 +26,12 @@ struct tegra_regulator_coupler { struct regulator_dev *core_rdev; struct regulator_dev *cpu_rdev; struct notifier_block reboot_notifier; + struct notifier_block suspend_notifier; int core_min_uV, cpu_min_uV; bool sys_reboot_mode_req; bool sys_reboot_mode; + bool sys_suspend_mode_req; + bool sys_suspend_mode; }; static inline struct tegra_regulator_coupler * @@ -113,6 +117,52 @@ static int tegra30_core_cpu_limit(int cpu_uV) return -EINVAL; } +static int tegra30_cpu_nominal_uV(void) +{ + switch (tegra_sku_info.cpu_speedo_id) { + case 10 ... 11: + return 850000; + + case 9: + return 912000; + + case 1 ... 3: + case 7 ... 8: + return 1050000; + + default: + return 1125000; + + case 4 ... 6: + case 12 ... 13: + return 1237000; + } +} + +static int tegra30_core_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + case 0: + return 1200000; + + case 1: + if (tegra_sku_info.cpu_speedo_id != 7 && + tegra_sku_info.cpu_speedo_id != 8) + return 1200000; + + fallthrough; + + case 2: + if (tegra_sku_info.cpu_speedo_id != 13) + return 1300000; + + return 1350000; + + default: + return 1250000; + } +} + static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, struct regulator_dev *cpu_rdev, struct regulator_dev *core_rdev) @@ -168,6 +218,11 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (err) return err; + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + core_min_uV = clamp(tegra30_core_nominal_uV(), + core_min_uV, core_max_uV); + core_uV = regulator_get_voltage_rdev(core_rdev); if (core_uV < 0) return core_uV; @@ -223,6 +278,11 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (tegra->sys_reboot_mode) cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + cpu_min_uV = clamp(tegra30_cpu_nominal_uV(), + cpu_min_uV, cpu_max_uV); + if (core_min_limited_uV > core_uV) { pr_err("core voltage constraint violated: %d %d %d\n", core_uV, core_min_limited_uV, cpu_uV); @@ -292,10 +352,68 @@ static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler, } tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req); return tegra30_voltage_update(tegra, cpu_rdev, core_rdev); } +static int tegra30_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra, + bool sys_suspend_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->cpu_rdev) + return 0; + + /* + * All power domains are enabled early during resume from suspend + * by GENPD core. Domains like VENC may require a higher voltage + * when enabled during resume from suspend. This also prepares + * hardware for resuming from LP0. + */ + + WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode); + + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + return 0; +} + +static int tegra30_regulator_suspend(struct notifier_block *notifier, + unsigned long mode, void *arg) +{ + struct tegra_regulator_coupler *tegra; + int ret = 0; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + suspend_notifier); + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + case PM_SUSPEND_PREPARE: + ret = tegra30_regulator_prepare_suspend(tegra, true); + break; + + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + ret = tegra30_regulator_prepare_suspend(tegra, false); + break; + } + + if (ret) + pr_err("failed to prepare regulators: %d\n", ret); + + return notifier_from_errno(ret); +} + static int tegra30_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, bool sys_reboot_mode) { @@ -395,6 +513,7 @@ static struct tegra_regulator_coupler tegra30_coupler = { .balance_voltage = tegra30_regulator_balance_voltage, }, .reboot_notifier.notifier_call = tegra30_regulator_reboot, + .suspend_notifier.notifier_call = tegra30_regulator_suspend, }; static int __init tegra_regulator_coupler_init(void) @@ -407,6 +526,9 @@ static int __init tegra_regulator_coupler_init(void) err = register_reboot_notifier(&tegra30_coupler.reboot_notifier); WARN_ON(err); + err = register_pm_notifier(&tegra30_coupler.suspend_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra30_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); -- 2.32.0 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/