From a545441b50cdbff4d46257c840b987ce1b07f5fe Mon Sep 17 00:00:00 2001 From: Hareesh Gundu Date: Tue, 20 Oct 2020 19:07:46 +0530 Subject: [PATCH] msm: kgsl: Add support for voting vdd parent supply voltage For RPM based targets which have the dedicated GFX rails requires voting of vdd parent supply. Hence add support to vote for vdd parent supply. Change-Id: I3301b9b5f07d8e928a64b7013ec40b7c54e596ca Signed-off-by: Hareesh Gundu --- drivers/gpu/msm/adreno.c | 7 +++++++ drivers/gpu/msm/kgsl_pwrctrl.c | 30 ++++++++++++++++++++++++++++-- drivers/gpu/msm/kgsl_pwrctrl.h | 4 ++++ drivers/gpu/msm/kgsl_util.c | 16 ++++++++++++++++ drivers/gpu/msm/kgsl_util.h | 12 +++++++++++- 5 files changed, 66 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index a775f66ed3a1..c8ec944fb47e 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -3574,9 +3574,16 @@ static void adreno_regulator_disable_poll(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; + /* Set the parent in retention voltage to disable CPR interrupts */ + kgsl_regulator_set_voltage(device->dev, pwr->gx_gdsc_parent, + pwr->gx_gdsc_parent_min_corner); + if (!kgsl_regulator_disable_wait(pwr->gx_gdsc, 200)) dev_err(device->dev, "Regulator vdd is stuck on\n"); + /* Remove the vote for the vdd parent supply */ + kgsl_regulator_set_voltage(device->dev, pwr->gx_gdsc_parent, 0); + if (!kgsl_regulator_disable_wait(pwr->cx_gdsc, 200)) dev_err(device->dev, "Regulator vddcx is stuck on\n"); } diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index ee8ddcd04042..9269a8ee99b4 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -14,6 +14,7 @@ #include "kgsl_pwrscale.h" #include "kgsl_sysfs.h" #include "kgsl_trace.h" +#include "kgsl_util.h" #define UPDATE_BUSY_VAL 1000000 @@ -1329,8 +1330,15 @@ static int enable_regulators(struct kgsl_device *device) return 0; ret = enable_regulator(&device->pdev->dev, pwr->cx_gdsc, "vddcx"); - if (!ret) - ret = enable_regulator(&device->pdev->dev, pwr->gx_gdsc, "vdd"); + if (!ret) { + /* Set parent in retention voltage to power up vdd supply */ + ret = kgsl_regulator_set_voltage(device->dev, + pwr->gx_gdsc_parent, + pwr->gx_gdsc_parent_min_corner); + if (!ret) + ret = enable_regulator(&device->pdev->dev, + pwr->gx_gdsc, "vdd"); + } if (ret) { clear_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->power_flags); @@ -1573,6 +1581,24 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) if (of_property_read_bool(pdev->dev.of_node, "vdd-supply")) pwr->gx_gdsc = devm_regulator_get(&pdev->dev, "vdd"); + if (of_property_read_bool(pdev->dev.of_node, "vdd-parent-supply")) { + pwr->gx_gdsc_parent = devm_regulator_get(&pdev->dev, + "vdd-parent"); + if (IS_ERR(pwr->gx_gdsc_parent)) { + dev_err(device->dev, + "Failed to get vdd-parent regulator:%d\n", + PTR_ERR(pwr->gx_gdsc_parent)); + return -ENODEV; + } + if (of_property_read_u32(pdev->dev.of_node, + "vdd-parent-min-corner", + &pwr->gx_gdsc_parent_min_corner)) { + dev_err(device->dev, + "vdd-parent-min-corner not found\n"); + return -ENODEV; + } + } + pwr->power_flags = 0; pm_runtime_enable(&pdev->dev); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 3489d79eeca6..c848455dfeed 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -120,6 +120,10 @@ struct kgsl_pwrctrl { struct regulator *cx_gdsc; /** @gx_gdsc: Pointer to the GX domain regulator if applicable */ struct regulator *gx_gdsc; + /** @gx_gdsc: Pointer to the GX domain parent supply */ + struct regulator *gx_gdsc_parent; + /** @gx_gdsc_parent_min_corner: Minimum supply voltage for GX parent */ + u32 gx_gdsc_parent_min_corner; int isense_clk_indx; int isense_clk_on_level; unsigned long power_flags; diff --git a/drivers/gpu/msm/kgsl_util.c b/drivers/gpu/msm/kgsl_util.c index d7ddc602f0d4..220304b6e0ed 100644 --- a/drivers/gpu/msm/kgsl_util.c +++ b/drivers/gpu/msm/kgsl_util.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -44,3 +45,18 @@ struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count, return NULL; } + +int kgsl_regulator_set_voltage(struct device *dev, + struct regulator *reg, u32 voltage) +{ + int ret; + + if (IS_ERR_OR_NULL(reg)) + return 0; + + ret = regulator_set_voltage(reg, voltage, INT_MAX); + if (ret) + dev_err(dev, "Regulator set voltage:%d failed:%d\n", voltage, ret); + + return ret; +} diff --git a/drivers/gpu/msm/kgsl_util.h b/drivers/gpu/msm/kgsl_util.h index 839c04ffc44d..f0490baf8fd9 100644 --- a/drivers/gpu/msm/kgsl_util.h +++ b/drivers/gpu/msm/kgsl_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _KGSL_UTIL_H_ @@ -32,4 +32,14 @@ bool kgsl_regulator_disable_wait(struct regulator *reg, u32 timeout); */ struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count, const char *id); +/** + * kgsl_regulator_set_voltage - Set voltage level for regulator + * @dev: A &struct device pointer + * @reg: A &struct regulator handle + * @voltage: Voltage value to set regulator + * + * Return: 0 on success and negative error on failure. + */ +int kgsl_regulator_set_voltage(struct device *dev, + struct regulator *reg, u32 voltage); #endif