212 lines
4.8 KiB
C
Raw Normal View History

2026-01-21 18:59:54 +08:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/regulator/consumer.h>
2026-01-29 22:25:33 +08:00
#include <linux/pm_opp.h>
2026-01-21 18:59:54 +08:00
#include "dp_power.h"
#include "msm_drv.h"
struct dp_power_private {
struct dp_parser *parser;
2026-01-29 22:25:33 +08:00
struct device *dev;
struct drm_device *drm_dev;
2026-01-21 18:59:54 +08:00
struct clk *link_clk_src;
struct clk *pixel_provider;
struct clk *link_provider;
struct dp_power dp_power;
};
static int dp_power_clk_init(struct dp_power_private *power)
{
int rc = 0;
struct dss_module_power *core, *ctrl, *stream;
2026-01-29 22:25:33 +08:00
struct device *dev = power->dev;
2026-01-21 18:59:54 +08:00
core = &power->parser->mp[DP_CORE_PM];
ctrl = &power->parser->mp[DP_CTRL_PM];
stream = &power->parser->mp[DP_STREAM_PM];
2026-01-29 22:25:33 +08:00
rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
if (rc)
2026-01-21 18:59:54 +08:00
return rc;
2026-01-29 22:25:33 +08:00
rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
if (rc)
2026-01-21 18:59:54 +08:00
return -ENODEV;
2026-01-29 22:25:33 +08:00
rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks);
if (rc)
2026-01-21 18:59:54 +08:00
return -ENODEV;
return 0;
}
2026-01-29 22:25:33 +08:00
int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
2026-01-21 18:59:54 +08:00
{
2026-01-29 22:25:33 +08:00
struct dp_power_private *power;
2026-01-21 18:59:54 +08:00
2026-01-29 22:25:33 +08:00
power = container_of(dp_power, struct dp_power_private, dp_power);
2026-01-21 18:59:54 +08:00
2026-01-29 22:25:33 +08:00
drm_dbg_dp(power->drm_dev,
"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on);
2026-01-21 18:59:54 +08:00
if (pm_type == DP_CORE_PM)
return dp_power->core_clks_on;
if (pm_type == DP_CTRL_PM)
return dp_power->link_clks_on;
if (pm_type == DP_STREAM_PM)
return dp_power->stream_clks_on;
return 0;
}
int dp_power_clk_enable(struct dp_power *dp_power,
enum dp_pm_type pm_type, bool enable)
{
int rc = 0;
struct dp_power_private *power;
2026-01-29 22:25:33 +08:00
struct dss_module_power *mp;
2026-01-21 18:59:54 +08:00
power = container_of(dp_power, struct dp_power_private, dp_power);
if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
pm_type != DP_STREAM_PM) {
DRM_ERROR("unsupported power module: %s\n",
dp_parser_pm_name(pm_type));
return -EINVAL;
}
if (enable) {
if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
2026-01-29 22:25:33 +08:00
drm_dbg_dp(power->drm_dev,
"core clks already enabled\n");
2026-01-21 18:59:54 +08:00
return 0;
}
if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
2026-01-29 22:25:33 +08:00
drm_dbg_dp(power->drm_dev,
"links clks already enabled\n");
2026-01-21 18:59:54 +08:00
return 0;
}
if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
2026-01-29 22:25:33 +08:00
drm_dbg_dp(power->drm_dev,
"pixel clks already enabled\n");
2026-01-21 18:59:54 +08:00
return 0;
}
if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
2026-01-29 22:25:33 +08:00
drm_dbg_dp(power->drm_dev,
"Enable core clks before link clks\n");
mp = &power->parser->mp[DP_CORE_PM];
2026-01-21 18:59:54 +08:00
2026-01-29 22:25:33 +08:00
rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
if (rc)
2026-01-21 18:59:54 +08:00
return rc;
2026-01-29 22:25:33 +08:00
2026-01-21 18:59:54 +08:00
dp_power->core_clks_on = true;
}
}
2026-01-29 22:25:33 +08:00
mp = &power->parser->mp[pm_type];
if (enable) {
rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
if (rc)
2026-01-21 18:59:54 +08:00
return rc;
2026-01-29 22:25:33 +08:00
} else {
clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
2026-01-21 18:59:54 +08:00
}
if (pm_type == DP_CORE_PM)
dp_power->core_clks_on = enable;
else if (pm_type == DP_STREAM_PM)
dp_power->stream_clks_on = enable;
else
dp_power->link_clks_on = enable;
2026-01-29 22:25:33 +08:00
drm_dbg_dp(power->drm_dev, "%s clocks for %s\n",
2026-01-21 18:59:54 +08:00
enable ? "enable" : "disable",
dp_parser_pm_name(pm_type));
2026-01-29 22:25:33 +08:00
drm_dbg_dp(power->drm_dev,
"strem_clks:%s link_clks:%s core_clks:%s\n",
2026-01-21 18:59:54 +08:00
dp_power->stream_clks_on ? "on" : "off",
dp_power->link_clks_on ? "on" : "off",
dp_power->core_clks_on ? "on" : "off");
return 0;
}
int dp_power_client_init(struct dp_power *dp_power)
{
struct dp_power_private *power;
power = container_of(dp_power, struct dp_power_private, dp_power);
2026-01-29 22:25:33 +08:00
pm_runtime_enable(power->dev);
2026-01-21 18:59:54 +08:00
2026-01-29 22:25:33 +08:00
return dp_power_clk_init(power);
2026-01-21 18:59:54 +08:00
}
void dp_power_client_deinit(struct dp_power *dp_power)
{
struct dp_power_private *power;
power = container_of(dp_power, struct dp_power_private, dp_power);
2026-01-29 22:25:33 +08:00
pm_runtime_disable(power->dev);
2026-01-21 18:59:54 +08:00
}
2026-01-29 22:25:33 +08:00
int dp_power_init(struct dp_power *dp_power)
2026-01-21 18:59:54 +08:00
{
int rc = 0;
struct dp_power_private *power = NULL;
power = container_of(dp_power, struct dp_power_private, dp_power);
2026-01-29 22:25:33 +08:00
pm_runtime_get_sync(power->dev);
2026-01-21 18:59:54 +08:00
rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
2026-01-29 22:25:33 +08:00
if (rc)
pm_runtime_put_sync(power->dev);
2026-01-21 18:59:54 +08:00
return rc;
}
int dp_power_deinit(struct dp_power *dp_power)
{
struct dp_power_private *power;
power = container_of(dp_power, struct dp_power_private, dp_power);
dp_power_clk_enable(dp_power, DP_CORE_PM, false);
2026-01-29 22:25:33 +08:00
pm_runtime_put_sync(power->dev);
2026-01-21 18:59:54 +08:00
return 0;
}
2026-01-29 22:25:33 +08:00
struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
2026-01-21 18:59:54 +08:00
{
struct dp_power_private *power;
struct dp_power *dp_power;
2026-01-29 22:25:33 +08:00
power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
2026-01-21 18:59:54 +08:00
if (!power)
return ERR_PTR(-ENOMEM);
power->parser = parser;
2026-01-29 22:25:33 +08:00
power->dev = dev;
2026-01-21 18:59:54 +08:00
dp_power = &power->dp_power;
return dp_power;
}