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 device *dev;
 18	struct drm_device *drm_dev;
 19	struct clk *link_clk_src;
 20	struct clk *pixel_provider;
 21	struct clk *link_provider;
 22
 23	struct dp_power dp_power;
 24};
 25
 26static int dp_power_clk_init(struct dp_power_private *power)
 27{
 28	int rc = 0;
 29	struct dss_module_power *core, *ctrl, *stream;
 30	struct device *dev = power->dev;
 31
 32	core = &power->parser->mp[DP_CORE_PM];
 33	ctrl = &power->parser->mp[DP_CTRL_PM];
 34	stream = &power->parser->mp[DP_STREAM_PM];
 35
 36	rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
 37	if (rc)
 38		return rc;
 39
 40	rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
 41	if (rc)
 42		return -ENODEV;
 43
 44	rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks);
 45	if (rc)
 46		return -ENODEV;
 47
 48	return 0;
 49}
 50
 51int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
 52{
 53	struct dp_power_private *power;
 54
 55	power = container_of(dp_power, struct dp_power_private, dp_power);
 56
 57	drm_dbg_dp(power->drm_dev,
 58		"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
 59		dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on);
 60
 61	if (pm_type == DP_CORE_PM)
 62		return dp_power->core_clks_on;
 63
 64	if (pm_type == DP_CTRL_PM)
 65		return dp_power->link_clks_on;
 66
 67	if (pm_type == DP_STREAM_PM)
 68		return dp_power->stream_clks_on;
 69
 70	return 0;
 71}
 72
 73int dp_power_clk_enable(struct dp_power *dp_power,
 74		enum dp_pm_type pm_type, bool enable)
 75{
 76	int rc = 0;
 77	struct dp_power_private *power;
 78	struct dss_module_power *mp;
 79
 80	power = container_of(dp_power, struct dp_power_private, dp_power);
 81
 82	if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
 83			pm_type != DP_STREAM_PM) {
 84		DRM_ERROR("unsupported power module: %s\n",
 85				dp_parser_pm_name(pm_type));
 86		return -EINVAL;
 87	}
 88
 89	if (enable) {
 90		if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
 91			drm_dbg_dp(power->drm_dev,
 92					"core clks already enabled\n");
 93			return 0;
 94		}
 95
 96		if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
 97			drm_dbg_dp(power->drm_dev,
 98					"links clks already enabled\n");
 99			return 0;
100		}
101
102		if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
103			drm_dbg_dp(power->drm_dev,
104					"pixel clks already enabled\n");
105			return 0;
106		}
107
108		if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
109			drm_dbg_dp(power->drm_dev,
110					"Enable core clks before link clks\n");
111			mp = &power->parser->mp[DP_CORE_PM];
112
113			rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
114			if (rc)
115				return rc;
116
117			dp_power->core_clks_on = true;
118		}
119	}
120
121	mp = &power->parser->mp[pm_type];
122	if (enable) {
123		rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
124		if (rc)
125			return rc;
126	} else {
127		clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
128	}
129
130	if (pm_type == DP_CORE_PM)
131		dp_power->core_clks_on = enable;
132	else if (pm_type == DP_STREAM_PM)
133		dp_power->stream_clks_on = enable;
134	else
135		dp_power->link_clks_on = enable;
136
137	drm_dbg_dp(power->drm_dev, "%s clocks for %s\n",
138			enable ? "enable" : "disable",
139			dp_parser_pm_name(pm_type));
140	drm_dbg_dp(power->drm_dev,
141		"strem_clks:%s link_clks:%s core_clks:%s\n",
142		dp_power->stream_clks_on ? "on" : "off",
143		dp_power->link_clks_on ? "on" : "off",
144		dp_power->core_clks_on ? "on" : "off");
145
146	return 0;
147}
148
149int dp_power_client_init(struct dp_power *dp_power)
150{
151	struct dp_power_private *power;
152
153	power = container_of(dp_power, struct dp_power_private, dp_power);
154
155	return dp_power_clk_init(power);
156}
157
158int dp_power_init(struct dp_power *dp_power)
159{
160	return dp_power_clk_enable(dp_power, DP_CORE_PM, true);
161}
162
163int dp_power_deinit(struct dp_power *dp_power)
164{
165	return dp_power_clk_enable(dp_power, DP_CORE_PM, false);
166}
167
168struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
169{
170	struct dp_power_private *power;
171	struct dp_power *dp_power;
172
173	power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
174	if (!power)
175		return ERR_PTR(-ENOMEM);
176
177	power->parser = parser;
178	power->dev = dev;
179
180	dp_power = &power->dp_power;
181
182	return dp_power;
183}