Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
  4 */
  5
  6#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
  7
  8#include <linux/clk.h>
  9#include <linux/clk-provider.h>
 10#include <linux/regulator/consumer.h>
 11#include <linux/pm_opp.h>
 12#include "dp_power.h"
 13#include "msm_drv.h"
 14
 15struct dp_power_private {
 16	struct dp_parser *parser;
 17	struct platform_device *pdev;
 18	struct device *dev;
 19	struct drm_device *drm_dev;
 20	struct clk *link_clk_src;
 21	struct clk *pixel_provider;
 22	struct clk *link_provider;
 23
 24	struct dp_power dp_power;
 25};
 26
 27static int dp_power_clk_init(struct dp_power_private *power)
 28{
 29	int rc = 0;
 30	struct dss_module_power *core, *ctrl, *stream;
 31	struct device *dev = &power->pdev->dev;
 32
 33	core = &power->parser->mp[DP_CORE_PM];
 34	ctrl = &power->parser->mp[DP_CTRL_PM];
 35	stream = &power->parser->mp[DP_STREAM_PM];
 36
 37	rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
 38	if (rc) {
 39		DRM_ERROR("failed to get %s clk. err=%d\n",
 40			dp_parser_pm_name(DP_CORE_PM), rc);
 41		return rc;
 42	}
 43
 44	rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
 45	if (rc) {
 46		DRM_ERROR("failed to get %s clk. err=%d\n",
 47			dp_parser_pm_name(DP_CTRL_PM), rc);
 48		return -ENODEV;
 49	}
 50
 51	rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks);
 52	if (rc) {
 53		DRM_ERROR("failed to get %s clk. err=%d\n",
 54			dp_parser_pm_name(DP_CTRL_PM), rc);
 55		return -ENODEV;
 56	}
 57
 58	return 0;
 59}
 60
 61int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
 62{
 63	struct dp_power_private *power;
 64
 65	power = container_of(dp_power, struct dp_power_private, dp_power);
 66
 67	drm_dbg_dp(power->drm_dev,
 68		"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
 69		dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on);
 70
 71	if (pm_type == DP_CORE_PM)
 72		return dp_power->core_clks_on;
 73
 74	if (pm_type == DP_CTRL_PM)
 75		return dp_power->link_clks_on;
 76
 77	if (pm_type == DP_STREAM_PM)
 78		return dp_power->stream_clks_on;
 79
 80	return 0;
 81}
 82
 83int dp_power_clk_enable(struct dp_power *dp_power,
 84		enum dp_pm_type pm_type, bool enable)
 85{
 86	int rc = 0;
 87	struct dp_power_private *power;
 88	struct dss_module_power *mp;
 89
 90	power = container_of(dp_power, struct dp_power_private, dp_power);
 91
 92	if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
 93			pm_type != DP_STREAM_PM) {
 94		DRM_ERROR("unsupported power module: %s\n",
 95				dp_parser_pm_name(pm_type));
 96		return -EINVAL;
 97	}
 98
 99	if (enable) {
100		if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
101			drm_dbg_dp(power->drm_dev,
102					"core clks already enabled\n");
103			return 0;
104		}
105
106		if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
107			drm_dbg_dp(power->drm_dev,
108					"links clks already enabled\n");
109			return 0;
110		}
111
112		if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
113			drm_dbg_dp(power->drm_dev,
114					"pixel clks already enabled\n");
115			return 0;
116		}
117
118		if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
119			drm_dbg_dp(power->drm_dev,
120					"Enable core clks before link clks\n");
121			mp = &power->parser->mp[DP_CORE_PM];
122
123			rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
124			if (rc) {
125				DRM_ERROR("fail to enable clks: %s. err=%d\n",
126					dp_parser_pm_name(DP_CORE_PM), rc);
127				return rc;
128			}
129			dp_power->core_clks_on = true;
130		}
131	}
132
133	mp = &power->parser->mp[pm_type];
134	if (enable) {
135		rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
136		if (rc) {
137			DRM_ERROR("failed to enable clks, err: %d\n", rc);
138			return rc;
139		}
140	} else {
141		clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
142	}
143
144	if (pm_type == DP_CORE_PM)
145		dp_power->core_clks_on = enable;
146	else if (pm_type == DP_STREAM_PM)
147		dp_power->stream_clks_on = enable;
148	else
149		dp_power->link_clks_on = enable;
150
151	drm_dbg_dp(power->drm_dev, "%s clocks for %s\n",
152			enable ? "enable" : "disable",
153			dp_parser_pm_name(pm_type));
154	drm_dbg_dp(power->drm_dev,
155		"strem_clks:%s link_clks:%s core_clks:%s\n",
156		dp_power->stream_clks_on ? "on" : "off",
157		dp_power->link_clks_on ? "on" : "off",
158		dp_power->core_clks_on ? "on" : "off");
159
160	return 0;
161}
162
163int dp_power_client_init(struct dp_power *dp_power)
164{
165	int rc = 0;
166	struct dp_power_private *power;
167
168	if (!dp_power) {
169		DRM_ERROR("invalid power data\n");
170		return -EINVAL;
171	}
172
173	power = container_of(dp_power, struct dp_power_private, dp_power);
174
175	pm_runtime_enable(&power->pdev->dev);
176
177	rc = dp_power_clk_init(power);
178	if (rc)
179		DRM_ERROR("failed to init clocks %d\n", rc);
180
181	return rc;
182}
183
184void dp_power_client_deinit(struct dp_power *dp_power)
185{
186	struct dp_power_private *power;
187
188	if (!dp_power) {
189		DRM_ERROR("invalid power data\n");
190		return;
191	}
192
193	power = container_of(dp_power, struct dp_power_private, dp_power);
194
195	pm_runtime_disable(&power->pdev->dev);
196}
197
198int dp_power_init(struct dp_power *dp_power, bool flip)
199{
200	int rc = 0;
201	struct dp_power_private *power = NULL;
202
203	if (!dp_power) {
204		DRM_ERROR("invalid power data\n");
205		return -EINVAL;
206	}
207
208	power = container_of(dp_power, struct dp_power_private, dp_power);
209
210	pm_runtime_get_sync(&power->pdev->dev);
211
212	rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
213	if (rc) {
214		DRM_ERROR("failed to enable DP core clocks, %d\n", rc);
215		goto exit;
216	}
217
218	return 0;
219
220exit:
221	pm_runtime_put_sync(&power->pdev->dev);
222	return rc;
223}
224
225int dp_power_deinit(struct dp_power *dp_power)
226{
227	struct dp_power_private *power;
228
229	power = container_of(dp_power, struct dp_power_private, dp_power);
230
231	dp_power_clk_enable(dp_power, DP_CORE_PM, false);
232	pm_runtime_put_sync(&power->pdev->dev);
233	return 0;
234}
235
236struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
237{
238	struct dp_power_private *power;
239	struct dp_power *dp_power;
240
241	if (!parser) {
242		DRM_ERROR("invalid input\n");
243		return ERR_PTR(-EINVAL);
244	}
245
246	power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL);
247	if (!power)
248		return ERR_PTR(-ENOMEM);
249
250	power->parser = parser;
251	power->pdev = parser->pdev;
252	power->dev = dev;
253
254	dp_power = &power->dp_power;
255
256	return dp_power;
257}