Received: by 2002:a05:6a10:af89:0:0:0:0 with SMTP id iu9csp3583851pxb; Mon, 24 Jan 2022 12:49:21 -0800 (PST) X-Google-Smtp-Source: ABdhPJxKotC3WVNB7I2XueYKUuyVF/XBsEToGieH4Y97VRWMhWp5PwXaZ1hgIQ4UrUOjs1+k15XM X-Received: by 2002:a05:6a00:181a:b0:4c1:3c75:9c54 with SMTP id y26-20020a056a00181a00b004c13c759c54mr15566876pfa.6.1643057361732; Mon, 24 Jan 2022 12:49:21 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1643057361; cv=none; d=google.com; s=arc-20160816; b=G9+Ouzs7ScIjNz+zlJows+X40zJOI5v5rhYpFSOkJPkfiRSlixY7izCTMl8+tdL6lC yKHdWAbkzRCgW0L0e0EWggEGBkyoKhIb908OUmMgvCYDVplAPsO7KiIRRdh7rwzlT5S1 ShzY+jXnUHXwXKFbK+gb4x+DrNcwO2qsqaazgdSvRCqHKMk3oO/uJlR9q+R5uYEdDxO7 pZxa1Lz9UucTW59vHENiOmlHtjrKzd0Q0NNh0SGI6Jg5Jiqmh0D2UyuUUzx/GgJp9gUM zuT9cI3flbPTMxdvuSlRCl5bkl6LXQwvIQ5aLsQsnMSIebEPvzYXx9p8HJ6/y5tDdcc3 9nMQ== 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=G/KiMjXVXhPz0gvrfbXP//pSV6tdHLc4JtVBOjmtg6I=; b=h0Z7v8zXY7tbp+vQuS4ySKeJFZDFz+hFipzn7v8UmnvRELFIEmGkEwXG7wqO5EvXb1 4ORzIjoAe3Yw1Vq/MMXV/ejmJHvUCxc2L7UAXRzZAJfwdwvL68w82DyMZSg3tcZ3r4rI RTs9W0M4BFkVFCCwXm207180gzCdg2ru8Z5ub2vbtqw6beS9PtFDEMbrOf6cBX/5Hmlr +guA05Kga9/JV507fqfGwtK9jyNN/4XY7vg2CwIXkaqoFJx4IHs/18S5+ZET5cTFwM0G oIVAOu4HtDDTx2HMBJySYQ8mv4rDjMl1Y7A9Y9qn8Poz+IQn2bu7zCFI/6ITgg87D1pR I31A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=XgE7S6a8; 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 o3si5568058plg.446.2022.01.24.12.49.10; Mon, 24 Jan 2022 12:49:21 -0800 (PST) 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=XgE7S6a8; 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 S1376957AbiAXUEl (ORCPT + 99 others); Mon, 24 Jan 2022 15:04:41 -0500 Received: from ams.source.kernel.org ([145.40.68.75]:37244 "EHLO ams.source.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356567AbiAXTql (ORCPT ); Mon, 24 Jan 2022 14:46:41 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 930DDB81229; Mon, 24 Jan 2022 19:46:40 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id DB5A9C340E7; Mon, 24 Jan 2022 19:46:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1643053599; bh=GSPw2tC2/aZH08CgCYUriKjqTe1XdPeZhekrHeV1OJU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XgE7S6a8Z6NGVc9R2SfmGrjYos9ly1WslKonY0uKj3cuE4+JhOjeQqIXlCordyxHM h6OrBSaBXsWI6ERYpryvLd87AJ5zemirUbX2+D5f9lBo0ThfqOL5oKQJKUGn6GSe4V SM6JGiieQPIYovwE1NDIOXj30zzCYg9dCHPQtTUE= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Oleksij Rempel , =?UTF-8?q?Petr=20Bene=C5=A1?= , Daniel Lezcano , Sasha Levin Subject: [PATCH 5.10 117/563] thermal/drivers/imx: Implement runtime PM support Date: Mon, 24 Jan 2022 19:38:02 +0100 Message-Id: <20220124184028.461979914@linuxfoundation.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220124184024.407936072@linuxfoundation.org> References: <20220124184024.407936072@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: Oleksij Rempel [ Upstream commit 4cf2ddf16e175ee18c5c29865c32da7d6269cf44 ] Starting with commit d92ed2c9d3ff ("thermal: imx: Use driver's local data to decide whether to run a measurement") this driver stared using irq_enabled flag to make decision to power on/off the thermal core. This triggered a regression, where after reaching critical temperature, alarm IRQ handler set irq_enabled to false, disabled thermal core and was not able read temperature and disable cooling sequence. In case the cooling device is "CPU/GPU freq", the system will run with reduce performance until next reboot. To solve this issue, we need to move all parts implementing hand made runtime power management and let it handle actual runtime PM framework. Fixes: d92ed2c9d3ff ("thermal: imx: Use driver's local data to decide whether to run a measurement") Signed-off-by: Oleksij Rempel Tested-by: Petr Beneš Link: https://lore.kernel.org/r/20211117103426.81813-1-o.rempel@pengutronix.de Signed-off-by: Daniel Lezcano Signed-off-by: Sasha Levin --- drivers/thermal/imx_thermal.c | 145 +++++++++++++++++++++------------- 1 file changed, 91 insertions(+), 54 deletions(-) diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 2c7473d86a59b..16663373b6829 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -15,6 +15,7 @@ #include #include #include +#include #define REG_SET 0x4 #define REG_CLR 0x8 @@ -194,6 +195,7 @@ static struct thermal_soc_data thermal_imx7d_data = { }; struct imx_thermal_data { + struct device *dev; struct cpufreq_policy *policy; struct thermal_zone_device *tz; struct thermal_cooling_device *cdev; @@ -252,44 +254,15 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp) const struct thermal_soc_data *soc_data = data->socdata; struct regmap *map = data->tempmon; unsigned int n_meas; - bool wait, run_measurement; u32 val; + int ret; - run_measurement = !data->irq_enabled; - if (!run_measurement) { - /* Check if a measurement is currently in progress */ - regmap_read(map, soc_data->temp_data, &val); - wait = !(val & soc_data->temp_valid_mask); - } else { - /* - * Every time we measure the temperature, we will power on the - * temperature sensor, enable measurements, take a reading, - * disable measurements, power off the temperature sensor. - */ - regmap_write(map, soc_data->sensor_ctrl + REG_CLR, - soc_data->power_down_mask); - regmap_write(map, soc_data->sensor_ctrl + REG_SET, - soc_data->measure_temp_mask); - - wait = true; - } - - /* - * According to the temp sensor designers, it may require up to ~17us - * to complete a measurement. - */ - if (wait) - usleep_range(20, 50); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; regmap_read(map, soc_data->temp_data, &val); - if (run_measurement) { - regmap_write(map, soc_data->sensor_ctrl + REG_CLR, - soc_data->measure_temp_mask); - regmap_write(map, soc_data->sensor_ctrl + REG_SET, - soc_data->power_down_mask); - } - if ((val & soc_data->temp_valid_mask) == 0) { dev_dbg(&tz->device, "temp measurement never finished\n"); return -EAGAIN; @@ -328,6 +301,8 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp) enable_irq(data->irq); } + pm_runtime_put(data->dev); + return 0; } @@ -335,24 +310,16 @@ static int imx_change_mode(struct thermal_zone_device *tz, enum thermal_device_mode mode) { struct imx_thermal_data *data = tz->devdata; - struct regmap *map = data->tempmon; - const struct thermal_soc_data *soc_data = data->socdata; if (mode == THERMAL_DEVICE_ENABLED) { - regmap_write(map, soc_data->sensor_ctrl + REG_CLR, - soc_data->power_down_mask); - regmap_write(map, soc_data->sensor_ctrl + REG_SET, - soc_data->measure_temp_mask); + pm_runtime_get(data->dev); if (!data->irq_enabled) { data->irq_enabled = true; enable_irq(data->irq); } } else { - regmap_write(map, soc_data->sensor_ctrl + REG_CLR, - soc_data->measure_temp_mask); - regmap_write(map, soc_data->sensor_ctrl + REG_SET, - soc_data->power_down_mask); + pm_runtime_put(data->dev); if (data->irq_enabled) { disable_irq(data->irq); @@ -393,6 +360,11 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip, int temp) { struct imx_thermal_data *data = tz->devdata; + int ret; + + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; /* do not allow changing critical threshold */ if (trip == IMX_TRIP_CRITICAL) @@ -406,6 +378,8 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip, imx_set_alarm_temp(data, temp); + pm_runtime_put(data->dev); + return 0; } @@ -681,6 +655,8 @@ static int imx_thermal_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + data->dev = &pdev->dev; + map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon"); if (IS_ERR(map)) { ret = PTR_ERR(map); @@ -800,6 +776,16 @@ static int imx_thermal_probe(struct platform_device *pdev) data->socdata->power_down_mask); regmap_write(map, data->socdata->sensor_ctrl + REG_SET, data->socdata->measure_temp_mask); + /* After power up, we need a delay before first access can be done. */ + usleep_range(20, 50); + + /* the core was configured and enabled just before */ + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(data->dev); + + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + goto disable_runtime_pm; data->irq_enabled = true; ret = thermal_zone_device_enable(data->tz); @@ -814,10 +800,15 @@ static int imx_thermal_probe(struct platform_device *pdev) goto thermal_zone_unregister; } + pm_runtime_put(data->dev); + return 0; thermal_zone_unregister: thermal_zone_device_unregister(data->tz); +disable_runtime_pm: + pm_runtime_put_noidle(data->dev); + pm_runtime_disable(data->dev); clk_disable: clk_disable_unprepare(data->thermal_clk); legacy_cleanup: @@ -829,13 +820,9 @@ legacy_cleanup: static int imx_thermal_remove(struct platform_device *pdev) { struct imx_thermal_data *data = platform_get_drvdata(pdev); - struct regmap *map = data->tempmon; - /* Disable measurements */ - regmap_write(map, data->socdata->sensor_ctrl + REG_SET, - data->socdata->power_down_mask); - if (!IS_ERR(data->thermal_clk)) - clk_disable_unprepare(data->thermal_clk); + pm_runtime_put_noidle(data->dev); + pm_runtime_disable(data->dev); thermal_zone_device_unregister(data->tz); imx_thermal_unregister_legacy_cooling(data); @@ -858,29 +845,79 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev) ret = thermal_zone_device_disable(data->tz); if (ret) return ret; + + return pm_runtime_force_suspend(data->dev); +} + +static int __maybe_unused imx_thermal_resume(struct device *dev) +{ + struct imx_thermal_data *data = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(data->dev); + if (ret) + return ret; + /* Enabled thermal sensor after resume */ + return thermal_zone_device_enable(data->tz); +} + +static int __maybe_unused imx_thermal_runtime_suspend(struct device *dev) +{ + struct imx_thermal_data *data = dev_get_drvdata(dev); + const struct thermal_soc_data *socdata = data->socdata; + struct regmap *map = data->tempmon; + int ret; + + ret = regmap_write(map, socdata->sensor_ctrl + REG_CLR, + socdata->measure_temp_mask); + if (ret) + return ret; + + ret = regmap_write(map, socdata->sensor_ctrl + REG_SET, + socdata->power_down_mask); + if (ret) + return ret; + clk_disable_unprepare(data->thermal_clk); return 0; } -static int __maybe_unused imx_thermal_resume(struct device *dev) +static int __maybe_unused imx_thermal_runtime_resume(struct device *dev) { struct imx_thermal_data *data = dev_get_drvdata(dev); + const struct thermal_soc_data *socdata = data->socdata; + struct regmap *map = data->tempmon; int ret; ret = clk_prepare_enable(data->thermal_clk); if (ret) return ret; - /* Enabled thermal sensor after resume */ - ret = thermal_zone_device_enable(data->tz); + + ret = regmap_write(map, socdata->sensor_ctrl + REG_CLR, + socdata->power_down_mask); + if (ret) + return ret; + + ret = regmap_write(map, socdata->sensor_ctrl + REG_SET, + socdata->measure_temp_mask); if (ret) return ret; + /* + * According to the temp sensor designers, it may require up to ~17us + * to complete a measurement. + */ + usleep_range(20, 50); + return 0; } -static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops, - imx_thermal_suspend, imx_thermal_resume); +static const struct dev_pm_ops imx_thermal_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(imx_thermal_suspend, imx_thermal_resume) + SET_RUNTIME_PM_OPS(imx_thermal_runtime_suspend, + imx_thermal_runtime_resume, NULL) +}; static struct platform_driver imx_thermal = { .driver = { -- 2.34.1