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