blob: 7f7da9bf92af7e60bdc116d857d96bc6979a0e44 [file] [log] [blame]
Sachin Bhayarecf8460a2018-01-03 18:34:30 +05301/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/err.h>
18#include <linux/string.h>
19#include <linux/clk/msm-clock-generic.h>
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053020#include <linux/vmalloc.h>
21#include <linux/memblock.h>
22
23#include "mdss-pll.h"
24
25int mdss_pll_util_resource_init(struct platform_device *pdev,
26 struct mdss_pll_resources *pll_res)
27{
28 int rc = 0;
Sachin Bhayare5076e252018-01-18 14:56:45 +053029 struct mdss_module_power *mp = &pll_res->mp;
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053030
Sachin Bhayare5076e252018-01-18 14:56:45 +053031 rc = msm_mdss_config_vreg(&pdev->dev,
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053032 mp->vreg_config, mp->num_vreg, 1);
33 if (rc) {
34 pr_err("Vreg config failed rc=%d\n", rc);
35 goto vreg_err;
36 }
37
Sachin Bhayare5076e252018-01-18 14:56:45 +053038 rc = msm_mdss_get_clk(&pdev->dev, mp->clk_config, mp->num_clk);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053039 if (rc) {
40 pr_err("Clock get failed rc=%d\n", rc);
41 goto clk_err;
42 }
43
44 return rc;
45
46clk_err:
Sachin Bhayare5076e252018-01-18 14:56:45 +053047 msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053048vreg_err:
49 return rc;
50}
51
52/**
53 * mdss_pll_get_mp_by_reg_name() -- Find power module by regulator name
54 *@pll_res: Pointer to the PLL resource
55 *@name: Regulator name as specified in the pll dtsi
56 *
57 * This is a helper function to retrieve the regulator information
58 * for each pll resource.
59 */
Sachin Bhayare5076e252018-01-18 14:56:45 +053060struct mdss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053061 , char *name)
62{
63
Sachin Bhayare5076e252018-01-18 14:56:45 +053064 struct mdss_vreg *regulator = NULL;
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053065 int i;
66
67 if ((pll_res == NULL) || (pll_res->mp.vreg_config == NULL)) {
68 pr_err("%s Invalid PLL resource\n", __func__);
69 goto error;
70 }
71
72 regulator = pll_res->mp.vreg_config;
73
74 for (i = 0; i < pll_res->mp.num_vreg; i++) {
75 if (!strcmp(name, regulator->vreg_name)) {
76 pr_debug("Found regulator match for %s\n", name);
77 break;
78 }
79 regulator++;
80 }
81
82error:
83 return regulator;
84}
85
86void mdss_pll_util_resource_deinit(struct platform_device *pdev,
87 struct mdss_pll_resources *pll_res)
88{
Sachin Bhayare5076e252018-01-18 14:56:45 +053089 struct mdss_module_power *mp = &pll_res->mp;
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053090
Sachin Bhayare5076e252018-01-18 14:56:45 +053091 msm_mdss_put_clk(mp->clk_config, mp->num_clk);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053092
Sachin Bhayare5076e252018-01-18 14:56:45 +053093 msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +053094}
95
96void mdss_pll_util_resource_release(struct platform_device *pdev,
97 struct mdss_pll_resources *pll_res)
98{
Sachin Bhayare5076e252018-01-18 14:56:45 +053099 struct mdss_module_power *mp = &pll_res->mp;
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530100
101 devm_kfree(&pdev->dev, mp->clk_config);
102 devm_kfree(&pdev->dev, mp->vreg_config);
103 mp->num_vreg = 0;
104 mp->num_clk = 0;
105}
106
107int mdss_pll_util_resource_enable(struct mdss_pll_resources *pll_res,
108 bool enable)
109{
110 int rc = 0;
Sachin Bhayare5076e252018-01-18 14:56:45 +0530111 struct mdss_module_power *mp = &pll_res->mp;
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530112
113 if (enable) {
Sachin Bhayare5076e252018-01-18 14:56:45 +0530114 rc = msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg,
115 enable);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530116 if (rc) {
117 pr_err("Failed to enable vregs rc=%d\n", rc);
118 goto vreg_err;
119 }
120
Sachin Bhayare5076e252018-01-18 14:56:45 +0530121 rc = msm_mdss_clk_set_rate(mp->clk_config, mp->num_clk);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530122 if (rc) {
123 pr_err("Failed to set clock rate rc=%d\n", rc);
124 goto clk_err;
125 }
126
Sachin Bhayare5076e252018-01-18 14:56:45 +0530127 rc = msm_mdss_enable_clk(mp->clk_config, mp->num_clk, enable);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530128 if (rc) {
129 pr_err("clock enable failed rc:%d\n", rc);
130 goto clk_err;
131 }
132 } else {
Sachin Bhayare5076e252018-01-18 14:56:45 +0530133 msm_mdss_enable_clk(mp->clk_config, mp->num_clk, enable);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530134
Sachin Bhayare5076e252018-01-18 14:56:45 +0530135 msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530136 }
137
138 return rc;
139
140clk_err:
Sachin Bhayare5076e252018-01-18 14:56:45 +0530141 msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530142vreg_err:
143 return rc;
144}
145
146static int mdss_pll_util_parse_dt_supply(struct platform_device *pdev,
147 struct mdss_pll_resources *pll_res)
148{
149 int i = 0, rc = 0;
150 u32 tmp = 0;
151 struct device_node *of_node = NULL, *supply_root_node = NULL;
152 struct device_node *supply_node = NULL;
Sachin Bhayare5076e252018-01-18 14:56:45 +0530153 struct mdss_module_power *mp = &pll_res->mp;
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530154
155 of_node = pdev->dev.of_node;
156
157 mp->num_vreg = 0;
158 supply_root_node = of_get_child_by_name(of_node,
159 "qcom,platform-supply-entries");
160 if (!supply_root_node) {
161 pr_err("no supply entry present\n");
162 return rc;
163 }
164
165 for_each_child_of_node(supply_root_node, supply_node) {
166 mp->num_vreg++;
167 }
168
169 if (mp->num_vreg == 0) {
170 pr_debug("no vreg\n");
171 return rc;
172 }
173 pr_debug("vreg found. count=%d\n", mp->num_vreg);
174
Sachin Bhayare5076e252018-01-18 14:56:45 +0530175 mp->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct mdss_vreg) *
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530176 mp->num_vreg, GFP_KERNEL);
177 if (!mp->vreg_config) {
178 rc = -ENOMEM;
179 return rc;
180 }
181
182 for_each_child_of_node(supply_root_node, supply_node) {
183
184 const char *st = NULL;
185
186 rc = of_property_read_string(supply_node,
187 "qcom,supply-name", &st);
188 if (rc) {
189 pr_err(":error reading name. rc=%d\n", rc);
190 goto error;
191 }
192
193 strlcpy(mp->vreg_config[i].vreg_name, st,
194 sizeof(mp->vreg_config[i].vreg_name));
195
196 rc = of_property_read_u32(supply_node,
197 "qcom,supply-min-voltage", &tmp);
198 if (rc) {
199 pr_err(": error reading min volt. rc=%d\n", rc);
200 goto error;
201 }
202 mp->vreg_config[i].min_voltage = tmp;
203
204 rc = of_property_read_u32(supply_node,
205 "qcom,supply-max-voltage", &tmp);
206 if (rc) {
207 pr_err(": error reading max volt. rc=%d\n", rc);
208 goto error;
209 }
210 mp->vreg_config[i].max_voltage = tmp;
211
212 rc = of_property_read_u32(supply_node,
213 "qcom,supply-enable-load", &tmp);
214 if (rc) {
215 pr_err(": error reading enable load. rc=%d\n", rc);
216 goto error;
217 }
218 mp->vreg_config[i].load[DSS_REG_MODE_ENABLE] = tmp;
219
220 rc = of_property_read_u32(supply_node,
221 "qcom,supply-disable-load", &tmp);
222 if (rc) {
223 pr_err(": error reading disable load. rc=%d\n", rc);
224 goto error;
225 }
226 mp->vreg_config[i].load[DSS_REG_MODE_DISABLE] = tmp;
227
228 rc = of_property_read_u32(supply_node,
229 "qcom,supply-ulp-load", &tmp);
230 if (rc)
231 pr_warn(": error reading ulp load. rc=%d\n", rc);
232
233 mp->vreg_config[i].load[DSS_REG_MODE_ULP] = (!rc ? tmp :
234 mp->vreg_config[i].load[DSS_REG_MODE_ENABLE]);
235
236 rc = of_property_read_u32(supply_node,
237 "qcom,supply-pre-on-sleep", &tmp);
238 if (rc)
239 pr_debug("error reading supply pre sleep value. rc=%d\n",
240 rc);
241
242 mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
243
244 rc = of_property_read_u32(supply_node,
245 "qcom,supply-pre-off-sleep", &tmp);
246 if (rc)
247 pr_debug("error reading supply pre sleep value. rc=%d\n",
248 rc);
249
250 mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
251
252 rc = of_property_read_u32(supply_node,
253 "qcom,supply-post-on-sleep", &tmp);
254 if (rc)
255 pr_debug("error reading supply post sleep value. rc=%d\n",
256 rc);
257
258 mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
259
260 rc = of_property_read_u32(supply_node,
261 "qcom,supply-post-off-sleep", &tmp);
262 if (rc)
263 pr_debug("error reading supply post sleep value. rc=%d\n",
264 rc);
265
266 mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
267
268 pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, ulp=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
269 mp->vreg_config[i].vreg_name,
270 mp->vreg_config[i].min_voltage,
271 mp->vreg_config[i].max_voltage,
272 mp->vreg_config[i].load[DSS_REG_MODE_ENABLE],
273 mp->vreg_config[i].load[DSS_REG_MODE_DISABLE],
274 mp->vreg_config[i].load[DSS_REG_MODE_ULP],
275 mp->vreg_config[i].pre_on_sleep,
276 mp->vreg_config[i].post_on_sleep,
277 mp->vreg_config[i].pre_off_sleep,
278 mp->vreg_config[i].post_off_sleep);
279 ++i;
280
281 rc = 0;
282 }
283
284 return rc;
285
286error:
287 if (mp->vreg_config) {
288 devm_kfree(&pdev->dev, mp->vreg_config);
289 mp->vreg_config = NULL;
290 mp->num_vreg = 0;
291 }
292
293 return rc;
294}
295
296static int mdss_pll_util_parse_dt_clock(struct platform_device *pdev,
297 struct mdss_pll_resources *pll_res)
298{
299 u32 i = 0, rc = 0;
Sachin Bhayare5076e252018-01-18 14:56:45 +0530300 struct mdss_module_power *mp = &pll_res->mp;
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530301 const char *clock_name;
302 u32 clock_rate;
303
304 mp->num_clk = of_property_count_strings(pdev->dev.of_node,
305 "clock-names");
306 if (mp->num_clk <= 0) {
307 pr_err("clocks are not defined\n");
308 goto clk_err;
309 }
310
311 mp->clk_config = devm_kzalloc(&pdev->dev,
Sachin Bhayare5076e252018-01-18 14:56:45 +0530312 sizeof(struct mdss_clk) * mp->num_clk, GFP_KERNEL);
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530313 if (!mp->clk_config) {
314 rc = -ENOMEM;
315 mp->num_clk = 0;
316 goto clk_err;
317 }
318
319 for (i = 0; i < mp->num_clk; i++) {
320 of_property_read_string_index(pdev->dev.of_node, "clock-names",
321 i, &clock_name);
322 strlcpy(mp->clk_config[i].clk_name, clock_name,
323 sizeof(mp->clk_config[i].clk_name));
324
325 of_property_read_u32_index(pdev->dev.of_node, "clock-rate",
326 i, &clock_rate);
327 mp->clk_config[i].rate = clock_rate;
328
329 if (!clock_rate)
330 mp->clk_config[i].type = DSS_CLK_AHB;
331 else
332 mp->clk_config[i].type = DSS_CLK_PCLK;
333 }
334
335clk_err:
336 return rc;
337}
338
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530339int mdss_pll_util_resource_parse(struct platform_device *pdev,
340 struct mdss_pll_resources *pll_res)
341{
342 int rc = 0;
Sachin Bhayare5076e252018-01-18 14:56:45 +0530343 struct mdss_module_power *mp = &pll_res->mp;
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530344
345 rc = mdss_pll_util_parse_dt_supply(pdev, pll_res);
346 if (rc) {
347 pr_err("vreg parsing failed rc=%d\n", rc);
348 goto end;
349 }
350
351 rc = mdss_pll_util_parse_dt_clock(pdev, pll_res);
352 if (rc) {
353 pr_err("clock name parsing failed rc=%d", rc);
354 goto clk_err;
355 }
356
Sachin Bhayarecf8460a2018-01-03 18:34:30 +0530357 return rc;
358
359clk_err:
360 devm_kfree(&pdev->dev, mp->vreg_config);
361 mp->num_vreg = 0;
362end:
363 return rc;
364}