xref: /openbmc/linux/drivers/gpu/drm/msm/dp/dp_power.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1c943b494SChandan Uddaraju // SPDX-License-Identifier: GPL-2.0-only
2c943b494SChandan Uddaraju /*
3c943b494SChandan Uddaraju  * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
4c943b494SChandan Uddaraju  */
5c943b494SChandan Uddaraju 
6c943b494SChandan Uddaraju #define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
7c943b494SChandan Uddaraju 
8c943b494SChandan Uddaraju #include <linux/clk.h>
9c943b494SChandan Uddaraju #include <linux/clk-provider.h>
10c943b494SChandan Uddaraju #include <linux/regulator/consumer.h>
11ab387647SKuogee Hsieh #include <linux/pm_opp.h>
12c943b494SChandan Uddaraju #include "dp_power.h"
13937f941cSStephen Boyd #include "msm_drv.h"
14c943b494SChandan Uddaraju 
15c943b494SChandan Uddaraju struct dp_power_private {
16c943b494SChandan Uddaraju 	struct dp_parser *parser;
17ab387647SKuogee Hsieh 	struct device *dev;
18202aceacSKuogee Hsieh 	struct drm_device *drm_dev;
19c943b494SChandan Uddaraju 	struct clk *link_clk_src;
20c943b494SChandan Uddaraju 	struct clk *pixel_provider;
21c943b494SChandan Uddaraju 	struct clk *link_provider;
22c943b494SChandan Uddaraju 
23c943b494SChandan Uddaraju 	struct dp_power dp_power;
24c943b494SChandan Uddaraju };
25c943b494SChandan Uddaraju 
dp_power_clk_init(struct dp_power_private * power)26c943b494SChandan Uddaraju static int dp_power_clk_init(struct dp_power_private *power)
27c943b494SChandan Uddaraju {
28c943b494SChandan Uddaraju 	int rc = 0;
298ede2eccSKuogee Hsieh 	struct dss_module_power *core, *ctrl, *stream;
30*9edac2eeSBjorn Andersson 	struct device *dev = power->dev;
31c943b494SChandan Uddaraju 
32c943b494SChandan Uddaraju 	core = &power->parser->mp[DP_CORE_PM];
33c943b494SChandan Uddaraju 	ctrl = &power->parser->mp[DP_CTRL_PM];
348ede2eccSKuogee Hsieh 	stream = &power->parser->mp[DP_STREAM_PM];
35c943b494SChandan Uddaraju 
3650b1131eSDmitry Baryshkov 	rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
379f932585SBjorn Andersson 	if (rc)
38c943b494SChandan Uddaraju 		return rc;
39c943b494SChandan Uddaraju 
4050b1131eSDmitry Baryshkov 	rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
419f932585SBjorn Andersson 	if (rc)
42c943b494SChandan Uddaraju 		return -ENODEV;
43c943b494SChandan Uddaraju 
4450b1131eSDmitry Baryshkov 	rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks);
459f932585SBjorn Andersson 	if (rc)
468ede2eccSKuogee Hsieh 		return -ENODEV;
478ede2eccSKuogee Hsieh 
48c943b494SChandan Uddaraju 	return 0;
49c943b494SChandan Uddaraju }
50c943b494SChandan Uddaraju 
dp_power_clk_status(struct dp_power * dp_power,enum dp_pm_type pm_type)518ede2eccSKuogee Hsieh int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
528ede2eccSKuogee Hsieh {
53202aceacSKuogee Hsieh 	struct dp_power_private *power;
54202aceacSKuogee Hsieh 
55202aceacSKuogee Hsieh 	power = container_of(dp_power, struct dp_power_private, dp_power);
56202aceacSKuogee Hsieh 
57202aceacSKuogee Hsieh 	drm_dbg_dp(power->drm_dev,
58202aceacSKuogee Hsieh 		"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
59601f0479SMaitreyee Rao 		dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on);
60601f0479SMaitreyee Rao 
618ede2eccSKuogee Hsieh 	if (pm_type == DP_CORE_PM)
628ede2eccSKuogee Hsieh 		return dp_power->core_clks_on;
638ede2eccSKuogee Hsieh 
648ede2eccSKuogee Hsieh 	if (pm_type == DP_CTRL_PM)
658ede2eccSKuogee Hsieh 		return dp_power->link_clks_on;
668ede2eccSKuogee Hsieh 
678ede2eccSKuogee Hsieh 	if (pm_type == DP_STREAM_PM)
688ede2eccSKuogee Hsieh 		return dp_power->stream_clks_on;
698ede2eccSKuogee Hsieh 
708ede2eccSKuogee Hsieh 	return 0;
718ede2eccSKuogee Hsieh }
728ede2eccSKuogee Hsieh 
dp_power_clk_enable(struct dp_power * dp_power,enum dp_pm_type pm_type,bool enable)73c943b494SChandan Uddaraju int dp_power_clk_enable(struct dp_power *dp_power,
74c943b494SChandan Uddaraju 		enum dp_pm_type pm_type, bool enable)
75c943b494SChandan Uddaraju {
76c943b494SChandan Uddaraju 	int rc = 0;
77c943b494SChandan Uddaraju 	struct dp_power_private *power;
78fc18ea98SDmitry Baryshkov 	struct dss_module_power *mp;
79c943b494SChandan Uddaraju 
80c943b494SChandan Uddaraju 	power = container_of(dp_power, struct dp_power_private, dp_power);
81c943b494SChandan Uddaraju 
828ede2eccSKuogee Hsieh 	if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
838ede2eccSKuogee Hsieh 			pm_type != DP_STREAM_PM) {
84c943b494SChandan Uddaraju 		DRM_ERROR("unsupported power module: %s\n",
85c943b494SChandan Uddaraju 				dp_parser_pm_name(pm_type));
86c943b494SChandan Uddaraju 		return -EINVAL;
87c943b494SChandan Uddaraju 	}
88c943b494SChandan Uddaraju 
89c943b494SChandan Uddaraju 	if (enable) {
90c943b494SChandan Uddaraju 		if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
91202aceacSKuogee Hsieh 			drm_dbg_dp(power->drm_dev,
92202aceacSKuogee Hsieh 					"core clks already enabled\n");
93c943b494SChandan Uddaraju 			return 0;
94c943b494SChandan Uddaraju 		}
95c943b494SChandan Uddaraju 
96c943b494SChandan Uddaraju 		if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
97202aceacSKuogee Hsieh 			drm_dbg_dp(power->drm_dev,
98202aceacSKuogee Hsieh 					"links clks already enabled\n");
99c943b494SChandan Uddaraju 			return 0;
100c943b494SChandan Uddaraju 		}
101c943b494SChandan Uddaraju 
1028ede2eccSKuogee Hsieh 		if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
103202aceacSKuogee Hsieh 			drm_dbg_dp(power->drm_dev,
104202aceacSKuogee Hsieh 					"pixel clks already enabled\n");
1058ede2eccSKuogee Hsieh 			return 0;
1068ede2eccSKuogee Hsieh 		}
1078ede2eccSKuogee Hsieh 
108c943b494SChandan Uddaraju 		if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
109202aceacSKuogee Hsieh 			drm_dbg_dp(power->drm_dev,
110202aceacSKuogee Hsieh 					"Enable core clks before link clks\n");
111fc18ea98SDmitry Baryshkov 			mp = &power->parser->mp[DP_CORE_PM];
112c943b494SChandan Uddaraju 
11350b1131eSDmitry Baryshkov 			rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
1149f932585SBjorn Andersson 			if (rc)
115c943b494SChandan Uddaraju 				return rc;
1169f932585SBjorn Andersson 
117c943b494SChandan Uddaraju 			dp_power->core_clks_on = true;
118c943b494SChandan Uddaraju 		}
119c943b494SChandan Uddaraju 	}
120c943b494SChandan Uddaraju 
121fc18ea98SDmitry Baryshkov 	mp = &power->parser->mp[pm_type];
12250b1131eSDmitry Baryshkov 	if (enable) {
12350b1131eSDmitry Baryshkov 		rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
1249f932585SBjorn Andersson 		if (rc)
125c943b494SChandan Uddaraju 			return rc;
12650b1131eSDmitry Baryshkov 	} else {
12750b1131eSDmitry Baryshkov 		clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
12850b1131eSDmitry Baryshkov 	}
129c943b494SChandan Uddaraju 
130c943b494SChandan Uddaraju 	if (pm_type == DP_CORE_PM)
131c943b494SChandan Uddaraju 		dp_power->core_clks_on = enable;
1328ede2eccSKuogee Hsieh 	else if (pm_type == DP_STREAM_PM)
1338ede2eccSKuogee Hsieh 		dp_power->stream_clks_on = enable;
134c943b494SChandan Uddaraju 	else
135c943b494SChandan Uddaraju 		dp_power->link_clks_on = enable;
136c943b494SChandan Uddaraju 
137202aceacSKuogee Hsieh 	drm_dbg_dp(power->drm_dev, "%s clocks for %s\n",
138c943b494SChandan Uddaraju 			enable ? "enable" : "disable",
139c943b494SChandan Uddaraju 			dp_parser_pm_name(pm_type));
140202aceacSKuogee Hsieh 	drm_dbg_dp(power->drm_dev,
141202aceacSKuogee Hsieh 		"strem_clks:%s link_clks:%s core_clks:%s\n",
1428ede2eccSKuogee Hsieh 		dp_power->stream_clks_on ? "on" : "off",
143c943b494SChandan Uddaraju 		dp_power->link_clks_on ? "on" : "off",
144c943b494SChandan Uddaraju 		dp_power->core_clks_on ? "on" : "off");
145c943b494SChandan Uddaraju 
146c943b494SChandan Uddaraju 	return 0;
147c943b494SChandan Uddaraju }
148c943b494SChandan Uddaraju 
dp_power_client_init(struct dp_power * dp_power)149c943b494SChandan Uddaraju int dp_power_client_init(struct dp_power *dp_power)
150c943b494SChandan Uddaraju {
151c943b494SChandan Uddaraju 	struct dp_power_private *power;
152c943b494SChandan Uddaraju 
153c943b494SChandan Uddaraju 	power = container_of(dp_power, struct dp_power_private, dp_power);
154c943b494SChandan Uddaraju 
155*9edac2eeSBjorn Andersson 	pm_runtime_enable(power->dev);
156c943b494SChandan Uddaraju 
1579f932585SBjorn Andersson 	return dp_power_clk_init(power);
158c943b494SChandan Uddaraju }
159c943b494SChandan Uddaraju 
dp_power_client_deinit(struct dp_power * dp_power)160c943b494SChandan Uddaraju void dp_power_client_deinit(struct dp_power *dp_power)
161c943b494SChandan Uddaraju {
162c943b494SChandan Uddaraju 	struct dp_power_private *power;
163c943b494SChandan Uddaraju 
164c943b494SChandan Uddaraju 	power = container_of(dp_power, struct dp_power_private, dp_power);
165c943b494SChandan Uddaraju 
166*9edac2eeSBjorn Andersson 	pm_runtime_disable(power->dev);
167c943b494SChandan Uddaraju }
168c943b494SChandan Uddaraju 
dp_power_init(struct dp_power * dp_power)1691c5f6051SDmitry Baryshkov int dp_power_init(struct dp_power *dp_power)
170c943b494SChandan Uddaraju {
171c943b494SChandan Uddaraju 	int rc = 0;
172c943b494SChandan Uddaraju 	struct dp_power_private *power = NULL;
173c943b494SChandan Uddaraju 
174c943b494SChandan Uddaraju 	power = container_of(dp_power, struct dp_power_private, dp_power);
175c943b494SChandan Uddaraju 
176*9edac2eeSBjorn Andersson 	pm_runtime_get_sync(power->dev);
177c943b494SChandan Uddaraju 
178c943b494SChandan Uddaraju 	rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
1799f932585SBjorn Andersson 	if (rc)
180*9edac2eeSBjorn Andersson 		pm_runtime_put_sync(power->dev);
1819f932585SBjorn Andersson 
182c943b494SChandan Uddaraju 	return rc;
183c943b494SChandan Uddaraju }
184c943b494SChandan Uddaraju 
dp_power_deinit(struct dp_power * dp_power)185c943b494SChandan Uddaraju int dp_power_deinit(struct dp_power *dp_power)
186c943b494SChandan Uddaraju {
187c943b494SChandan Uddaraju 	struct dp_power_private *power;
188c943b494SChandan Uddaraju 
189c943b494SChandan Uddaraju 	power = container_of(dp_power, struct dp_power_private, dp_power);
190c943b494SChandan Uddaraju 
191c943b494SChandan Uddaraju 	dp_power_clk_enable(dp_power, DP_CORE_PM, false);
192*9edac2eeSBjorn Andersson 	pm_runtime_put_sync(power->dev);
193c943b494SChandan Uddaraju 	return 0;
194c943b494SChandan Uddaraju }
195c943b494SChandan Uddaraju 
dp_power_get(struct device * dev,struct dp_parser * parser)196ab387647SKuogee Hsieh struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
197c943b494SChandan Uddaraju {
198c943b494SChandan Uddaraju 	struct dp_power_private *power;
199c943b494SChandan Uddaraju 	struct dp_power *dp_power;
200c943b494SChandan Uddaraju 
201*9edac2eeSBjorn Andersson 	power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
202c943b494SChandan Uddaraju 	if (!power)
203c943b494SChandan Uddaraju 		return ERR_PTR(-ENOMEM);
204c943b494SChandan Uddaraju 
205c943b494SChandan Uddaraju 	power->parser = parser;
206ab387647SKuogee Hsieh 	power->dev = dev;
207c943b494SChandan Uddaraju 
208c943b494SChandan Uddaraju 	dp_power = &power->dp_power;
209c943b494SChandan Uddaraju 
210c943b494SChandan Uddaraju 	return dp_power;
211c943b494SChandan Uddaraju }
212