Skip to content
Snippets Groups Projects
Commit 42db2fed authored by Boris Brezillon's avatar Boris Brezillon
Browse files

soc/rockchip: Add a regulator coupler for the Mali GPU on rk3588


G610 Mali normally takes 2 regulators, but the devfreq implementation
can only deal with one. Let's add a regulator coupler as done for
mtk8183.

Signed-off-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
parent bd77c13e
No related branches found
No related tags found
No related merge requests found
......@@ -22,6 +22,11 @@ config ROCKCHIP_IODOMAIN
necessary for the io domain setting of the SoC to match the
voltage supplied by the regulators.
config ROCKCHIP_REGULATOR_COUPLER
bool "MediaTek SoC Regulator Coupler" if COMPILE_TEST
default ARCH_ROCKCHIP
depends on REGULATOR
config ROCKCHIP_DTPM
tristate "Rockchip DTPM hierarchy"
depends on DTPM && m
......
......@@ -4,4 +4,5 @@
#
obj-$(CONFIG_ROCKCHIP_GRF) += grf.o
obj-$(CONFIG_ROCKCHIP_IODOMAIN) += io-domain.o
obj-$(CONFIG_ROCKCHIP_REGULATOR_COUPLER) += rockchip-regulator-coupler.o
obj-$(CONFIG_ROCKCHIP_DTPM) += dtpm.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* Voltage regulators coupler for Rockchip SoCs
*
* Copied from drivers/soc/rockchip/mtk-regulator-coupler.c:
* Copyright (C) 2022 Collabora, Ltd.
* Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/suspend.h>
#define to_rockchip_coupler(x) container_of(x, struct rockchip_regulator_coupler, coupler)
struct rockchip_regulator_coupler {
struct regulator_coupler coupler;
struct regulator_dev *vsram_rdev;
};
/*
* We currently support only couples of not more than two vregs and
* modify the vsram voltage only when changing voltage of vgpu.
*
* This function is limited to the GPU<->SRAM voltages relationships.
*/
static int rockchip_regulator_balance_voltage(struct regulator_coupler *coupler,
struct regulator_dev *rdev,
suspend_state_t state)
{
struct rockchip_regulator_coupler *mrc = to_rockchip_coupler(coupler);
int max_spread = rdev->constraints->max_spread[0];
int vsram_min_uV = mrc->vsram_rdev->constraints->min_uV;
int vsram_max_uV = mrc->vsram_rdev->constraints->max_uV;
int vsram_target_min_uV, vsram_target_max_uV;
int min_uV = 0;
int max_uV = INT_MAX;
int ret;
/*
* If the target device is on, setting the SRAM voltage directly
* is not supported as it scales through its coupled supply voltage.
*
* An exception is made in case the use_count is zero: this means
* that this is the first time we power up the SRAM regulator, which
* implies that the target device has yet to perform initialization
* and setting a voltage at that time is harmless.
*/
if (rdev == mrc->vsram_rdev) {
if (rdev->use_count == 0)
return regulator_do_balance_voltage(rdev, state, true);
return -EPERM;
}
ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
if (ret < 0)
return ret;
if (min_uV == 0) {
ret = regulator_get_voltage_rdev(rdev);
if (ret < 0)
return ret;
min_uV = ret;
}
ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
if (ret < 0)
return ret;
/*
* If we're asked to set a voltage less than VSRAM min_uV, set
* the minimum allowed voltage on VSRAM, as in this case it is
* safe to ignore the max_spread parameter.
*/
vsram_target_min_uV = max(vsram_min_uV, min_uV + max_spread);
vsram_target_max_uV = min(vsram_max_uV, vsram_target_min_uV + max_spread);
/* Make sure we're not out of range */
vsram_target_min_uV = min(vsram_target_min_uV, vsram_max_uV);
pr_debug("Setting voltage %d-%duV on %s (minuV %d)\n",
vsram_target_min_uV, vsram_target_max_uV,
rdev_get_name(mrc->vsram_rdev), min_uV);
ret = regulator_set_voltage_rdev(mrc->vsram_rdev, vsram_target_min_uV,
vsram_target_max_uV, state);
if (ret)
return ret;
/* The sram voltage is now balanced: update the target vreg voltage */
return regulator_do_balance_voltage(rdev, state, true);
}
static int rockchip_regulator_attach(struct regulator_coupler *coupler,
struct regulator_dev *rdev)
{
struct rockchip_regulator_coupler *mrc = to_rockchip_coupler(coupler);
const char *rdev_name = rdev_get_name(rdev);
/*
* If we're getting a coupling of more than two regulators here and
* this means that this is surely not a GPU<->SRAM couple: in that
* case, we may want to use another coupler implementation, if any,
* or the generic one: the regulator core will keep walking through
* the list of couplers when any .attach_regulator() cb returns 1.
*/
if (rdev->coupling_desc.n_coupled > 2)
return 1;
if (strstr(rdev_name, "gpu_mem")) {
if (mrc->vsram_rdev)
return -EINVAL;
mrc->vsram_rdev = rdev;
} else if (!strstr(rdev_name, "gpu")) {
return 1;
}
return 0;
}
static int rockchip_regulator_detach(struct regulator_coupler *coupler,
struct regulator_dev *rdev)
{
struct rockchip_regulator_coupler *mrc = to_rockchip_coupler(coupler);
if (rdev == mrc->vsram_rdev)
mrc->vsram_rdev = NULL;
return 0;
}
static struct rockchip_regulator_coupler rockchip_coupler = {
.coupler = {
.attach_regulator = rockchip_regulator_attach,
.detach_regulator = rockchip_regulator_detach,
.balance_voltage = rockchip_regulator_balance_voltage,
},
};
static int rockchip_regulator_coupler_init(void)
{
if (!of_machine_is_compatible("rockchip,rk3588"))
return 0;
return regulator_coupler_register(&rockchip_coupler.coupler);
}
arch_initcall(rockchip_regulator_coupler_init);
MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
MODULE_DESCRIPTION("Rockchip Regulator Coupler driver");
MODULE_LICENSE("GPL");
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment