xref: /openbmc/linux/drivers/gpu/drm/msm/dp/dp_power.c (revision 8ab59da2)
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 
15 struct 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 
27 static 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 
61 int 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 
83 int 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 
163 int 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 
184 void 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 
198 int 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 
220 exit:
221 	pm_runtime_put_sync(&power->pdev->dev);
222 	return rc;
223 }
224 
225 int 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 
236 struct 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 }
258