blob: 34a826d997f106d383525a63c963b9567fa49db2 [file] [log] [blame]
Alan Kwong83b6cbe2016-09-17 20:08:37 -04001/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
Dhaval Patel480dc522016-07-27 18:36:59 -07002 *
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) "[drm:%s:%d]: " fmt, __func__, __LINE__
15
16#include <linux/clk.h>
17#include <linux/kernel.h>
18#include <linux/of.h>
19#include <linux/string.h>
20#include <linux/of_address.h>
Dhaval Patel480dc522016-07-27 18:36:59 -070021#include <linux/slab.h>
22#include <linux/mutex.h>
23#include <linux/of_platform.h>
24
25#include <linux/msm-bus.h>
26#include <linux/msm-bus-board.h>
Dhaval Patel1ac91032016-09-26 19:25:39 -070027#include <linux/sde_io_util.h>
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -070028#include <linux/sde_rsc.h>
Dhaval Patel480dc522016-07-27 18:36:59 -070029
30#include "sde_power_handle.h"
Alan Kwong67a3f792016-11-01 23:16:53 -040031#include "sde_trace.h"
Dhaval Patel480dc522016-07-27 18:36:59 -070032
Alan Kwong0230a102017-05-16 11:36:44 -070033static const char *data_bus_name[SDE_POWER_HANDLE_DBUS_ID_MAX] = {
34 [SDE_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,sde-data-bus",
35 [SDE_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,sde-llcc-bus",
36 [SDE_POWER_HANDLE_DBUS_ID_EBI] = "qcom,sde-ebi-bus",
37};
38
39const char *sde_power_handle_get_dbus_name(u32 bus_id)
40{
41 if (bus_id < SDE_POWER_HANDLE_DBUS_ID_MAX)
42 return data_bus_name[bus_id];
43
44 return NULL;
45}
46
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -070047static void sde_power_event_trigger_locked(struct sde_power_handle *phandle,
48 u32 event_type)
49{
50 struct sde_power_event *event;
51
52 list_for_each_entry(event, &phandle->event_list, list) {
53 if (event->event_type & event_type)
54 event->cb_fnc(event_type, event->usr);
55 }
56}
57
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -070058static int sde_power_rsc_update(struct sde_power_handle *phandle, bool enable)
59{
60 u32 rsc_state;
Veera Sundaram Sankaran479defc2017-04-28 15:33:54 -070061 int ret = 0;
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -070062
63 /* creates the rsc client on the first enable */
64 if (!phandle->rsc_client_init) {
65 phandle->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX,
66 "sde_power_handle", false);
67 if (IS_ERR_OR_NULL(phandle->rsc_client)) {
68 pr_debug("sde rsc client create failed :%ld\n",
69 PTR_ERR(phandle->rsc_client));
70 phandle->rsc_client = NULL;
71 }
72 phandle->rsc_client_init = true;
73 }
74
75 rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
76
Veera Sundaram Sankaran479defc2017-04-28 15:33:54 -070077 if (phandle->rsc_client)
78 ret = sde_rsc_client_state_update(phandle->rsc_client,
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -040079 rsc_state, NULL, SDE_RSC_INVALID_CRTC_ID, NULL);
Veera Sundaram Sankaran479defc2017-04-28 15:33:54 -070080
81 return ret;
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -070082}
83
Dhaval Patel480dc522016-07-27 18:36:59 -070084struct sde_power_client *sde_power_client_create(
85 struct sde_power_handle *phandle, char *client_name)
86{
87 struct sde_power_client *client;
88 static u32 id;
89
90 if (!client_name || !phandle) {
91 pr_err("client name is null or invalid power data\n");
92 return ERR_PTR(-EINVAL);
93 }
94
95 client = kzalloc(sizeof(struct sde_power_client), GFP_KERNEL);
96 if (!client)
97 return ERR_PTR(-ENOMEM);
98
99 mutex_lock(&phandle->phandle_lock);
100 strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN);
101 client->usecase_ndx = VOTE_INDEX_DISABLE;
102 client->id = id;
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700103 client->active = true;
Dhaval Patel480dc522016-07-27 18:36:59 -0700104 pr_debug("client %s created:%pK id :%d\n", client_name,
105 client, id);
106 id++;
107 list_add(&client->list, &phandle->power_client_clist);
108 mutex_unlock(&phandle->phandle_lock);
109
110 return client;
111}
112
113void sde_power_client_destroy(struct sde_power_handle *phandle,
114 struct sde_power_client *client)
115{
116 if (!client || !phandle) {
117 pr_err("reg bus vote: invalid client handle\n");
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700118 } else if (!client->active) {
119 pr_err("sde power deinit already done\n");
120 kfree(client);
Dhaval Patel480dc522016-07-27 18:36:59 -0700121 } else {
122 pr_debug("bus vote client %s destroyed:%pK id:%u\n",
123 client->name, client, client->id);
124 mutex_lock(&phandle->phandle_lock);
125 list_del_init(&client->list);
126 mutex_unlock(&phandle->phandle_lock);
127 kfree(client);
128 }
129}
130
131static int sde_power_parse_dt_supply(struct platform_device *pdev,
132 struct dss_module_power *mp)
133{
134 int i = 0, rc = 0;
135 u32 tmp = 0;
136 struct device_node *of_node = NULL, *supply_root_node = NULL;
137 struct device_node *supply_node = NULL;
138
139 if (!pdev || !mp) {
140 pr_err("invalid input param pdev:%pK mp:%pK\n", pdev, mp);
141 return -EINVAL;
142 }
143
144 of_node = pdev->dev.of_node;
145
146 mp->num_vreg = 0;
147 supply_root_node = of_get_child_by_name(of_node,
148 "qcom,platform-supply-entries");
149 if (!supply_root_node) {
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700150 pr_debug("no supply entry present\n");
Dhaval Patel480dc522016-07-27 18:36:59 -0700151 return rc;
152 }
153
154 for_each_child_of_node(supply_root_node, supply_node)
155 mp->num_vreg++;
156
157 if (mp->num_vreg == 0) {
158 pr_debug("no vreg\n");
159 return rc;
160 }
161
162 pr_debug("vreg found. count=%d\n", mp->num_vreg);
163 mp->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct dss_vreg) *
164 mp->num_vreg, GFP_KERNEL);
165 if (!mp->vreg_config) {
166 rc = -ENOMEM;
167 return rc;
168 }
169
170 for_each_child_of_node(supply_root_node, supply_node) {
171
172 const char *st = NULL;
173
174 rc = of_property_read_string(supply_node,
175 "qcom,supply-name", &st);
176 if (rc) {
177 pr_err("error reading name. rc=%d\n", rc);
178 goto error;
179 }
180
181 strlcpy(mp->vreg_config[i].vreg_name, st,
182 sizeof(mp->vreg_config[i].vreg_name));
183
184 rc = of_property_read_u32(supply_node,
185 "qcom,supply-min-voltage", &tmp);
186 if (rc) {
187 pr_err("error reading min volt. rc=%d\n", rc);
188 goto error;
189 }
190 mp->vreg_config[i].min_voltage = tmp;
191
192 rc = of_property_read_u32(supply_node,
193 "qcom,supply-max-voltage", &tmp);
194 if (rc) {
195 pr_err("error reading max volt. rc=%d\n", rc);
196 goto error;
197 }
198 mp->vreg_config[i].max_voltage = tmp;
199
200 rc = of_property_read_u32(supply_node,
201 "qcom,supply-enable-load", &tmp);
202 if (rc) {
203 pr_err("error reading enable load. rc=%d\n", rc);
204 goto error;
205 }
206 mp->vreg_config[i].enable_load = tmp;
207
208 rc = of_property_read_u32(supply_node,
209 "qcom,supply-disable-load", &tmp);
210 if (rc) {
211 pr_err("error reading disable load. rc=%d\n", rc);
212 goto error;
213 }
214 mp->vreg_config[i].disable_load = tmp;
215
216 rc = of_property_read_u32(supply_node,
217 "qcom,supply-pre-on-sleep", &tmp);
218 if (rc)
219 pr_debug("error reading supply pre sleep value. rc=%d\n",
220 rc);
221
222 mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
223
224 rc = of_property_read_u32(supply_node,
225 "qcom,supply-pre-off-sleep", &tmp);
226 if (rc)
227 pr_debug("error reading supply pre sleep value. rc=%d\n",
228 rc);
229
230 mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
231
232 rc = of_property_read_u32(supply_node,
233 "qcom,supply-post-on-sleep", &tmp);
234 if (rc)
235 pr_debug("error reading supply post sleep value. rc=%d\n",
236 rc);
237
238 mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
239
240 rc = of_property_read_u32(supply_node,
241 "qcom,supply-post-off-sleep", &tmp);
242 if (rc)
243 pr_debug("error reading supply post sleep value. rc=%d\n",
244 rc);
245
246 mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
247
248 pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
249 mp->vreg_config[i].vreg_name,
250 mp->vreg_config[i].min_voltage,
251 mp->vreg_config[i].max_voltage,
252 mp->vreg_config[i].enable_load,
253 mp->vreg_config[i].disable_load,
254 mp->vreg_config[i].pre_on_sleep,
255 mp->vreg_config[i].post_on_sleep,
256 mp->vreg_config[i].pre_off_sleep,
257 mp->vreg_config[i].post_off_sleep);
258 ++i;
259
260 rc = 0;
261 }
262
263 return rc;
264
265error:
266 if (mp->vreg_config) {
267 devm_kfree(&pdev->dev, mp->vreg_config);
268 mp->vreg_config = NULL;
269 mp->num_vreg = 0;
270 }
271
272 return rc;
273}
274
275static int sde_power_parse_dt_clock(struct platform_device *pdev,
276 struct dss_module_power *mp)
277{
278 u32 i = 0, rc = 0;
279 const char *clock_name;
Kalyan Thota8f727922016-10-28 19:09:03 +0530280 u32 clock_rate = 0;
281 u32 clock_max_rate = 0;
282 int num_clk = 0;
Dhaval Patel480dc522016-07-27 18:36:59 -0700283
284 if (!pdev || !mp) {
285 pr_err("invalid input param pdev:%pK mp:%pK\n", pdev, mp);
286 return -EINVAL;
287 }
288
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700289 mp->num_clk = 0;
290 num_clk = of_property_count_strings(pdev->dev.of_node,
Dhaval Patel480dc522016-07-27 18:36:59 -0700291 "clock-names");
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700292 if (num_clk <= 0) {
293 pr_debug("clocks are not defined\n");
Dhaval Patel480dc522016-07-27 18:36:59 -0700294 goto clk_err;
295 }
296
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700297 mp->num_clk = num_clk;
Dhaval Patel480dc522016-07-27 18:36:59 -0700298 mp->clk_config = devm_kzalloc(&pdev->dev,
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700299 sizeof(struct dss_clk) * num_clk, GFP_KERNEL);
Dhaval Patel480dc522016-07-27 18:36:59 -0700300 if (!mp->clk_config) {
301 rc = -ENOMEM;
302 mp->num_clk = 0;
303 goto clk_err;
304 }
305
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700306 for (i = 0; i < num_clk; i++) {
Dhaval Patel480dc522016-07-27 18:36:59 -0700307 of_property_read_string_index(pdev->dev.of_node, "clock-names",
308 i, &clock_name);
309 strlcpy(mp->clk_config[i].clk_name, clock_name,
310 sizeof(mp->clk_config[i].clk_name));
311
312 of_property_read_u32_index(pdev->dev.of_node, "clock-rate",
313 i, &clock_rate);
314 mp->clk_config[i].rate = clock_rate;
315
316 if (!clock_rate)
317 mp->clk_config[i].type = DSS_CLK_AHB;
318 else
319 mp->clk_config[i].type = DSS_CLK_PCLK;
Alan Kwong83b6cbe2016-09-17 20:08:37 -0400320
321 clock_max_rate = 0;
322 of_property_read_u32_index(pdev->dev.of_node, "clock-max-rate",
323 i, &clock_max_rate);
324 mp->clk_config[i].max_rate = clock_max_rate;
Dhaval Patel480dc522016-07-27 18:36:59 -0700325 }
326
327clk_err:
328 return rc;
329}
330
331#ifdef CONFIG_QCOM_BUS_SCALING
Alan Kwong67a3f792016-11-01 23:16:53 -0400332
333#define MAX_AXI_PORT_COUNT 3
334
335static int _sde_power_data_bus_set_quota(
336 struct sde_power_data_bus_handle *pdbus,
337 u64 ab_quota_rt, u64 ab_quota_nrt,
338 u64 ib_quota_rt, u64 ib_quota_nrt)
339{
340 int new_uc_idx;
341 u64 ab_quota[MAX_AXI_PORT_COUNT] = {0, 0};
342 u64 ib_quota[MAX_AXI_PORT_COUNT] = {0, 0};
343 int rc;
344
345 if (pdbus->data_bus_hdl < 1) {
346 pr_err("invalid bus handle %d\n", pdbus->data_bus_hdl);
347 return -EINVAL;
348 }
349
Alan Kwongff30f4a2017-05-23 12:02:00 -0700350 pdbus->ab_rt = ab_quota_rt;
351 pdbus->ib_rt = ib_quota_rt;
352 pdbus->ab_nrt = ab_quota_nrt;
353 pdbus->ib_nrt = ib_quota_nrt;
354
355 if (pdbus->enable) {
356 ab_quota_rt = max_t(u64, ab_quota_rt,
357 SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA);
358 ib_quota_rt = max_t(u64, ib_quota_rt,
359 SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA);
360 ab_quota_nrt = max_t(u64, ab_quota_nrt,
361 SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA);
362 ib_quota_nrt = max_t(u64, ib_quota_nrt,
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700363 SDE_POWER_HANDLE_ENABLE_NRT_BUS_IB_QUOTA);
Alan Kwongff30f4a2017-05-23 12:02:00 -0700364 } else {
Dhaval Patelc4f1c7c2017-08-16 12:02:21 -0700365 ab_quota_rt = min_t(u64, ab_quota_rt,
Alan Kwongff30f4a2017-05-23 12:02:00 -0700366 SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA);
Dhaval Patelc4f1c7c2017-08-16 12:02:21 -0700367 ib_quota_rt = min_t(u64, ib_quota_rt,
Alan Kwongff30f4a2017-05-23 12:02:00 -0700368 SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA);
Dhaval Patelc4f1c7c2017-08-16 12:02:21 -0700369 ab_quota_nrt = min_t(u64, ab_quota_nrt,
Alan Kwongff30f4a2017-05-23 12:02:00 -0700370 SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA);
Dhaval Patelc4f1c7c2017-08-16 12:02:21 -0700371 ib_quota_nrt = min_t(u64, ib_quota_nrt,
Alan Kwongff30f4a2017-05-23 12:02:00 -0700372 SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA);
373 }
374
Alan Kwong67a3f792016-11-01 23:16:53 -0400375 if (!ab_quota_rt && !ab_quota_nrt && !ib_quota_rt && !ib_quota_nrt) {
376 new_uc_idx = 0;
377 } else {
378 int i;
379 struct msm_bus_vectors *vect = NULL;
380 struct msm_bus_scale_pdata *bw_table =
381 pdbus->data_bus_scale_table;
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700382 u32 nrt_data_paths_cnt = pdbus->nrt_data_paths_cnt;
383 u32 total_data_paths_cnt = pdbus->data_paths_cnt;
384 u32 rt_data_paths_cnt = total_data_paths_cnt -
385 nrt_data_paths_cnt;
Alan Kwong67a3f792016-11-01 23:16:53 -0400386
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700387 if (!bw_table || !total_data_paths_cnt ||
388 total_data_paths_cnt > MAX_AXI_PORT_COUNT) {
Alan Kwong67a3f792016-11-01 23:16:53 -0400389 pr_err("invalid input\n");
390 return -EINVAL;
391 }
392
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700393 if (nrt_data_paths_cnt) {
394
395 ab_quota_rt = div_u64(ab_quota_rt, rt_data_paths_cnt);
396 ab_quota_nrt = div_u64(ab_quota_nrt,
397 nrt_data_paths_cnt);
398
Alan Kwong67a3f792016-11-01 23:16:53 -0400399 ib_quota_rt = div_u64(ib_quota_rt,
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700400 rt_data_paths_cnt);
Alan Kwong67a3f792016-11-01 23:16:53 -0400401 ib_quota_nrt = div_u64(ib_quota_nrt,
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700402 nrt_data_paths_cnt);
Alan Kwong67a3f792016-11-01 23:16:53 -0400403
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700404 for (i = 0; i < total_data_paths_cnt; i++) {
405 if (i < rt_data_paths_cnt) {
Alan Kwong67a3f792016-11-01 23:16:53 -0400406 ab_quota[i] = ab_quota_rt;
407 ib_quota[i] = ib_quota_rt;
408 } else {
409 ab_quota[i] = ab_quota_nrt;
410 ib_quota[i] = ib_quota_nrt;
411 }
412 }
413 } else {
414 ab_quota[0] = div_u64(ab_quota_rt + ab_quota_nrt,
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700415 total_data_paths_cnt);
416 ib_quota[0] = div_u64(ib_quota_rt + ib_quota_nrt,
417 total_data_paths_cnt);
Alan Kwong67a3f792016-11-01 23:16:53 -0400418
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700419 for (i = 1; i < total_data_paths_cnt; i++) {
Alan Kwong67a3f792016-11-01 23:16:53 -0400420 ab_quota[i] = ab_quota[0];
421 ib_quota[i] = ib_quota[0];
422 }
423 }
424
Alan Kwong67a3f792016-11-01 23:16:53 -0400425 new_uc_idx = (pdbus->curr_bw_uc_idx %
426 (bw_table->num_usecases - 1)) + 1;
427
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700428 for (i = 0; i < total_data_paths_cnt; i++) {
Alan Kwong67a3f792016-11-01 23:16:53 -0400429 vect = &bw_table->usecase[new_uc_idx].vectors[i];
430 vect->ab = ab_quota[i];
431 vect->ib = ib_quota[i];
432
Alan Kwong0230a102017-05-16 11:36:44 -0700433 pr_debug(
434 "%s uc_idx=%d %s path idx=%d ab=%llu ib=%llu\n",
435 bw_table->name,
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700436 new_uc_idx, (i < rt_data_paths_cnt) ?
437 "rt" : "nrt", i, vect->ab, vect->ib);
Alan Kwong67a3f792016-11-01 23:16:53 -0400438 }
439 }
440 pdbus->curr_bw_uc_idx = new_uc_idx;
441 pdbus->ao_bw_uc_idx = new_uc_idx;
442
Dhaval Patel3fe015e2017-02-18 10:11:27 -0800443 SDE_ATRACE_BEGIN("msm_bus_scale_req");
444 rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl,
Alan Kwong67a3f792016-11-01 23:16:53 -0400445 new_uc_idx);
Dhaval Patel3fe015e2017-02-18 10:11:27 -0800446 SDE_ATRACE_END("msm_bus_scale_req");
447
Alan Kwong67a3f792016-11-01 23:16:53 -0400448 return rc;
449}
450
451int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,
452 struct sde_power_client *pclient,
Alan Kwong0230a102017-05-16 11:36:44 -0700453 int bus_client, u32 bus_id,
454 u64 ab_quota, u64 ib_quota)
Alan Kwong67a3f792016-11-01 23:16:53 -0400455{
456 int rc = 0;
457 int i;
458 u64 total_ab_rt = 0, total_ib_rt = 0;
459 u64 total_ab_nrt = 0, total_ib_nrt = 0;
460 struct sde_power_client *client;
461
462 if (!phandle || !pclient ||
Alan Kwong0230a102017-05-16 11:36:44 -0700463 bus_client >= SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX ||
464 bus_id >= SDE_POWER_HANDLE_DBUS_ID_MAX) {
Alan Kwong67a3f792016-11-01 23:16:53 -0400465 pr_err("invalid parameters\n");
466 return -EINVAL;
467 }
468
469 mutex_lock(&phandle->phandle_lock);
470
471 pclient->ab[bus_client] = ab_quota;
472 pclient->ib[bus_client] = ib_quota;
473 trace_sde_perf_update_bus(bus_client, ab_quota, ib_quota);
474
475 list_for_each_entry(client, &phandle->power_client_clist, list) {
476 for (i = 0; i < SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX; i++) {
477 if (i == SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT) {
478 total_ab_nrt += client->ab[i];
479 total_ib_nrt += client->ib[i];
480 } else {
481 total_ab_rt += client->ab[i];
482 total_ib_rt = max(total_ib_rt, client->ib[i]);
483 }
484 }
485 }
486
Alan Kwong0230a102017-05-16 11:36:44 -0700487 if (phandle->data_bus_handle[bus_id].data_bus_hdl)
488 rc = _sde_power_data_bus_set_quota(
489 &phandle->data_bus_handle[bus_id],
Alan Kwong67a3f792016-11-01 23:16:53 -0400490 total_ab_rt, total_ab_nrt,
491 total_ib_rt, total_ib_nrt);
492
493 mutex_unlock(&phandle->phandle_lock);
494
495 return rc;
496}
497
498static void sde_power_data_bus_unregister(
499 struct sde_power_data_bus_handle *pdbus)
500{
501 if (pdbus->data_bus_hdl) {
502 msm_bus_scale_unregister_client(pdbus->data_bus_hdl);
503 pdbus->data_bus_hdl = 0;
504 }
505}
506
507static int sde_power_data_bus_parse(struct platform_device *pdev,
Alan Kwong0230a102017-05-16 11:36:44 -0700508 struct sde_power_data_bus_handle *pdbus, const char *name)
Alan Kwong67a3f792016-11-01 23:16:53 -0400509{
510 struct device_node *node;
511 int rc = 0;
512 int paths;
513
514 pdbus->bus_channels = 1;
515 rc = of_property_read_u32(pdev->dev.of_node,
516 "qcom,sde-dram-channels", &pdbus->bus_channels);
Alan Kwong1bd11be2017-01-10 10:31:39 -0500517 if (rc) {
Alan Kwong67a3f792016-11-01 23:16:53 -0400518 pr_debug("number of channels property not specified\n");
Alan Kwong1bd11be2017-01-10 10:31:39 -0500519 rc = 0;
520 }
Alan Kwong67a3f792016-11-01 23:16:53 -0400521
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700522 pdbus->nrt_data_paths_cnt = 0;
Alan Kwong67a3f792016-11-01 23:16:53 -0400523 rc = of_property_read_u32(pdev->dev.of_node,
524 "qcom,sde-num-nrt-paths",
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700525 &pdbus->nrt_data_paths_cnt);
Alan Kwong1bd11be2017-01-10 10:31:39 -0500526 if (rc) {
527 pr_debug("number of axi port property not specified\n");
528 rc = 0;
529 }
Alan Kwong67a3f792016-11-01 23:16:53 -0400530
Alan Kwong0230a102017-05-16 11:36:44 -0700531 node = of_get_child_by_name(pdev->dev.of_node, name);
Alan Kwong67a3f792016-11-01 23:16:53 -0400532 if (node) {
533 rc = of_property_read_u32(node,
534 "qcom,msm-bus,num-paths", &paths);
535 if (rc) {
536 pr_err("Error. qcom,msm-bus,num-paths not found\n");
537 return rc;
538 }
Ingrid Gallardo72cca3002017-10-26 18:25:47 -0700539 pdbus->data_paths_cnt = paths;
Alan Kwong67a3f792016-11-01 23:16:53 -0400540
541 pdbus->data_bus_scale_table =
542 msm_bus_pdata_from_node(pdev, node);
543 if (IS_ERR_OR_NULL(pdbus->data_bus_scale_table)) {
544 pr_err("reg bus handle parsing failed\n");
545 rc = PTR_ERR(pdbus->data_bus_scale_table);
Dhaval Patel5398f602017-03-25 18:25:18 -0700546 if (!pdbus->data_bus_scale_table)
547 rc = -EINVAL;
Alan Kwong67a3f792016-11-01 23:16:53 -0400548 goto end;
549 }
550 pdbus->data_bus_hdl = msm_bus_scale_register_client(
551 pdbus->data_bus_scale_table);
552 if (!pdbus->data_bus_hdl) {
553 pr_err("data_bus_client register failed\n");
554 rc = -EINVAL;
555 goto end;
556 }
Alan Kwong0230a102017-05-16 11:36:44 -0700557 pr_debug("register %s data_bus_hdl=%x\n", name,
558 pdbus->data_bus_hdl);
Alan Kwong67a3f792016-11-01 23:16:53 -0400559 }
560
561end:
562 return rc;
563}
564
Dhaval Patel480dc522016-07-27 18:36:59 -0700565static int sde_power_reg_bus_parse(struct platform_device *pdev,
566 struct sde_power_handle *phandle)
567{
568 struct device_node *node;
569 struct msm_bus_scale_pdata *bus_scale_table;
570 int rc = 0;
571
572 node = of_get_child_by_name(pdev->dev.of_node, "qcom,sde-reg-bus");
573 if (node) {
574 bus_scale_table = msm_bus_pdata_from_node(pdev, node);
575 if (IS_ERR_OR_NULL(bus_scale_table)) {
576 pr_err("reg bus handle parsing failed\n");
577 rc = PTR_ERR(bus_scale_table);
Dhaval Patel5398f602017-03-25 18:25:18 -0700578 if (!bus_scale_table)
579 rc = -EINVAL;
Dhaval Patel480dc522016-07-27 18:36:59 -0700580 goto end;
581 }
582 phandle->reg_bus_hdl = msm_bus_scale_register_client(
583 bus_scale_table);
584 if (!phandle->reg_bus_hdl) {
585 pr_err("reg_bus_client register failed\n");
586 rc = -EINVAL;
587 goto end;
588 }
589 pr_debug("register reg_bus_hdl=%x\n", phandle->reg_bus_hdl);
590 }
591
592end:
593 return rc;
594}
595
596static void sde_power_reg_bus_unregister(u32 reg_bus_hdl)
597{
598 if (reg_bus_hdl)
599 msm_bus_scale_unregister_client(reg_bus_hdl);
600}
601
Dhaval Patelc4f1c7c2017-08-16 12:02:21 -0700602int sde_power_data_bus_state_update(struct sde_power_handle *phandle,
603 bool enable)
604{
605 int i;
606
607 if (!phandle) {
608 pr_err("invalid param\n");
609 return -EINVAL;
610 }
611
612 for (i = SDE_POWER_HANDLE_DBUS_ID_MNOC;
613 i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
614 phandle->data_bus_handle[i].enable = enable;
615
616 return 0;
617}
618
Dhaval Patel60c25062017-02-21 17:44:05 -0800619static int sde_power_data_bus_update(struct sde_power_data_bus_handle *pdbus,
620 bool enable)
621{
622 int rc = 0;
Dhaval Patel60c25062017-02-21 17:44:05 -0800623
Alan Kwongff30f4a2017-05-23 12:02:00 -0700624 pdbus->enable = enable;
Dhaval Patel60c25062017-02-21 17:44:05 -0800625
626 if (pdbus->data_bus_hdl)
Alan Kwongff30f4a2017-05-23 12:02:00 -0700627 rc = _sde_power_data_bus_set_quota(pdbus, pdbus->ab_rt,
628 pdbus->ab_nrt, pdbus->ib_rt, pdbus->ib_nrt);
Dhaval Patel60c25062017-02-21 17:44:05 -0800629
630 if (rc)
631 pr_err("failed to set data bus vote rc=%d enable:%d\n",
632 rc, enable);
633
634 return rc;
635}
636
Dhaval Patel480dc522016-07-27 18:36:59 -0700637static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx)
638{
639 int rc = 0;
640
641 if (reg_bus_hdl)
642 rc = msm_bus_scale_client_update_request(reg_bus_hdl,
643 usecase_ndx);
644 if (rc)
645 pr_err("failed to set reg bus vote rc=%d\n", rc);
646
647 return rc;
648}
649#else
Alan Kwong67a3f792016-11-01 23:16:53 -0400650static int sde_power_data_bus_parse(struct platform_device *pdev,
Lingutla Chandrasekhar6044b962017-07-10 13:07:50 +0530651 struct sde_power_data_bus_handle *pdbus, const char *name)
Alan Kwong67a3f792016-11-01 23:16:53 -0400652{
653 return 0;
654}
655
656static void sde_power_data_bus_unregister(
657 struct sde_power_data_bus_handle *pdbus)
658{
659}
660
661int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,
662 struct sde_power_client *pclient,
Alan Kwong0230a102017-05-16 11:36:44 -0700663 int bus_client, u32 bus_id,
664 u64 ab_quota, u64 ib_quota)
Alan Kwong67a3f792016-11-01 23:16:53 -0400665{
666 return 0;
667}
668
Dhaval Patel480dc522016-07-27 18:36:59 -0700669static int sde_power_reg_bus_parse(struct platform_device *pdev,
670 struct sde_power_handle *phandle)
671{
672 return 0;
673}
674
675static void sde_power_reg_bus_unregister(u32 reg_bus_hdl)
676{
677}
678
679static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx)
680{
681 return 0;
682}
Dhaval Patel60c25062017-02-21 17:44:05 -0800683
684static int sde_power_data_bus_update(struct sde_power_data_bus_handle *pdbus,
685 bool enable)
686{
687 return 0;
688}
Dhaval Patelc4f1c7c2017-08-16 12:02:21 -0700689
690int sde_power_data_bus_state_update(struct sde_power_handle *phandle,
691 bool enable)
692{
693 return 0;
694}
Dhaval Patel480dc522016-07-27 18:36:59 -0700695#endif
696
697int sde_power_resource_init(struct platform_device *pdev,
698 struct sde_power_handle *phandle)
699{
Alan Kwong0230a102017-05-16 11:36:44 -0700700 int rc = 0, i;
Dhaval Patel480dc522016-07-27 18:36:59 -0700701 struct dss_module_power *mp;
702
703 if (!phandle || !pdev) {
704 pr_err("invalid input param\n");
705 rc = -EINVAL;
706 goto end;
707 }
708 mp = &phandle->mp;
Alan Kwong67a3f792016-11-01 23:16:53 -0400709 phandle->dev = &pdev->dev;
Dhaval Patel480dc522016-07-27 18:36:59 -0700710
711 rc = sde_power_parse_dt_clock(pdev, mp);
712 if (rc) {
713 pr_err("device clock parsing failed\n");
714 goto end;
715 }
716
717 rc = sde_power_parse_dt_supply(pdev, mp);
718 if (rc) {
719 pr_err("device vreg supply parsing failed\n");
720 goto parse_vreg_err;
721 }
722
723 rc = msm_dss_config_vreg(&pdev->dev,
724 mp->vreg_config, mp->num_vreg, 1);
725 if (rc) {
726 pr_err("vreg config failed rc=%d\n", rc);
727 goto vreg_err;
728 }
729
730 rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, mp->num_clk);
731 if (rc) {
732 pr_err("clock get failed rc=%d\n", rc);
733 goto clk_err;
734 }
735
736 rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
737 if (rc) {
738 pr_err("clock set rate failed rc=%d\n", rc);
739 goto bus_err;
740 }
741
742 rc = sde_power_reg_bus_parse(pdev, phandle);
743 if (rc) {
744 pr_err("register bus parse failed rc=%d\n", rc);
745 goto bus_err;
746 }
747
Alan Kwong0230a102017-05-16 11:36:44 -0700748 for (i = SDE_POWER_HANDLE_DBUS_ID_MNOC;
749 i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
750 rc = sde_power_data_bus_parse(pdev,
751 &phandle->data_bus_handle[i],
752 data_bus_name[i]);
753 if (rc) {
754 pr_err("register data bus parse failed id=%d rc=%d\n",
755 i, rc);
756 goto data_bus_err;
757 }
Alan Kwong67a3f792016-11-01 23:16:53 -0400758 }
759
Dhaval Patel480dc522016-07-27 18:36:59 -0700760 INIT_LIST_HEAD(&phandle->power_client_clist);
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700761 INIT_LIST_HEAD(&phandle->event_list);
762
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700763 phandle->rsc_client = NULL;
764 phandle->rsc_client_init = false;
765
Dhaval Patel480dc522016-07-27 18:36:59 -0700766 mutex_init(&phandle->phandle_lock);
767
768 return rc;
769
Alan Kwong67a3f792016-11-01 23:16:53 -0400770data_bus_err:
Alan Kwong0230a102017-05-16 11:36:44 -0700771 for (i--; i >= 0; i--)
772 sde_power_data_bus_unregister(&phandle->data_bus_handle[i]);
Alan Kwong67a3f792016-11-01 23:16:53 -0400773 sde_power_reg_bus_unregister(phandle->reg_bus_hdl);
Dhaval Patel480dc522016-07-27 18:36:59 -0700774bus_err:
775 msm_dss_put_clk(mp->clk_config, mp->num_clk);
776clk_err:
777 msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
778vreg_err:
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700779 if (mp->vreg_config)
780 devm_kfree(&pdev->dev, mp->vreg_config);
Dhaval Patel480dc522016-07-27 18:36:59 -0700781 mp->num_vreg = 0;
782parse_vreg_err:
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700783 if (mp->clk_config)
784 devm_kfree(&pdev->dev, mp->clk_config);
Dhaval Patel480dc522016-07-27 18:36:59 -0700785 mp->num_clk = 0;
786end:
787 return rc;
788}
789
790void sde_power_resource_deinit(struct platform_device *pdev,
791 struct sde_power_handle *phandle)
792{
793 struct dss_module_power *mp;
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700794 struct sde_power_client *curr_client, *next_client;
795 struct sde_power_event *curr_event, *next_event;
Alan Kwong0230a102017-05-16 11:36:44 -0700796 int i;
Dhaval Patel480dc522016-07-27 18:36:59 -0700797
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700798 if (!phandle || !pdev) {
Dhaval Patel480dc522016-07-27 18:36:59 -0700799 pr_err("invalid input param\n");
800 return;
801 }
802 mp = &phandle->mp;
803
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700804 mutex_lock(&phandle->phandle_lock);
805 list_for_each_entry_safe(curr_client, next_client,
806 &phandle->power_client_clist, list) {
807 pr_err("cliend:%s-%d still registered with refcount:%d\n",
808 curr_client->name, curr_client->id,
809 curr_client->refcount);
810 curr_client->active = false;
811 list_del(&curr_client->list);
812 }
813
814 list_for_each_entry_safe(curr_event, next_event,
815 &phandle->event_list, list) {
816 pr_err("event:%d, client:%s still registered\n",
817 curr_event->event_type,
818 curr_event->client_name);
819 curr_event->active = false;
820 list_del(&curr_event->list);
821 }
822 mutex_unlock(&phandle->phandle_lock);
823
Alan Kwong0230a102017-05-16 11:36:44 -0700824 for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
825 sde_power_data_bus_unregister(&phandle->data_bus_handle[i]);
Alan Kwong67a3f792016-11-01 23:16:53 -0400826
Dhaval Patel480dc522016-07-27 18:36:59 -0700827 sde_power_reg_bus_unregister(phandle->reg_bus_hdl);
828
829 msm_dss_put_clk(mp->clk_config, mp->num_clk);
830
831 msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
832
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700833 if (mp->clk_config)
834 devm_kfree(&pdev->dev, mp->clk_config);
835
836 if (mp->vreg_config)
837 devm_kfree(&pdev->dev, mp->vreg_config);
838
Dhaval Patel480dc522016-07-27 18:36:59 -0700839 mp->num_vreg = 0;
840 mp->num_clk = 0;
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700841
842 if (phandle->rsc_client)
843 sde_rsc_client_destroy(phandle->rsc_client);
Dhaval Patel480dc522016-07-27 18:36:59 -0700844}
845
846int sde_power_resource_enable(struct sde_power_handle *phandle,
847 struct sde_power_client *pclient, bool enable)
848{
Alan Kwong0230a102017-05-16 11:36:44 -0700849 int rc = 0, i;
Dhaval Patel480dc522016-07-27 18:36:59 -0700850 bool changed = false;
851 u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx;
852 struct sde_power_client *client;
853 struct dss_module_power *mp;
854
855 if (!phandle || !pclient) {
856 pr_err("invalid input argument\n");
857 return -EINVAL;
858 }
859
860 mp = &phandle->mp;
861
862 mutex_lock(&phandle->phandle_lock);
863 if (enable)
864 pclient->refcount++;
865 else if (pclient->refcount)
866 pclient->refcount--;
867
868 if (pclient->refcount)
869 pclient->usecase_ndx = VOTE_INDEX_LOW;
870 else
871 pclient->usecase_ndx = VOTE_INDEX_DISABLE;
872
873 list_for_each_entry(client, &phandle->power_client_clist, list) {
874 if (client->usecase_ndx < VOTE_INDEX_MAX &&
875 client->usecase_ndx > max_usecase_ndx)
876 max_usecase_ndx = client->usecase_ndx;
877 }
878
879 if (phandle->current_usecase_ndx != max_usecase_ndx) {
880 changed = true;
881 prev_usecase_ndx = phandle->current_usecase_ndx;
882 phandle->current_usecase_ndx = max_usecase_ndx;
883 }
884
885 pr_debug("%pS: changed=%d current idx=%d request client %s id:%u enable:%d refcount:%d\n",
886 __builtin_return_address(0), changed, max_usecase_ndx,
887 pclient->name, pclient->id, enable, pclient->refcount);
888
889 if (!changed)
890 goto end;
891
892 if (enable) {
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700893 sde_power_event_trigger_locked(phandle,
894 SDE_POWER_EVENT_PRE_ENABLE);
895
Alan Kwong0230a102017-05-16 11:36:44 -0700896 for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
897 rc = sde_power_data_bus_update(
898 &phandle->data_bus_handle[i], enable);
899 if (rc) {
900 pr_err("failed to set data bus vote id=%d rc=%d\n",
901 i, rc);
902 goto data_bus_hdl_err;
903 }
Dhaval Patel60c25062017-02-21 17:44:05 -0800904 }
Veera Sundaram Sankaran9aa24e92017-05-01 17:04:10 -0700905 /*
906 * - When the target is RSCC enabled, regulator should
907 * be enabled by the s/w only for the first time during
908 * bootup. After that, RSCC hardware takes care of enabling/
909 * disabling it.
910 * - When the target is not RSCC enabled, regulator should
911 * be totally handled by the software.
912 */
913 if (!phandle->rsc_client) {
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700914 rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
915 enable);
916 if (rc) {
917 pr_err("failed to enable vregs rc=%d\n", rc);
918 goto vreg_err;
919 }
Dhaval Patel480dc522016-07-27 18:36:59 -0700920 }
921
922 rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
923 max_usecase_ndx);
924 if (rc) {
925 pr_err("failed to set reg bus vote rc=%d\n", rc);
926 goto reg_bus_hdl_err;
927 }
928
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700929 rc = sde_power_rsc_update(phandle, true);
930 if (rc) {
931 pr_err("failed to update rsc\n");
932 goto rsc_err;
933 }
934
Dhaval Patel480dc522016-07-27 18:36:59 -0700935 rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
936 if (rc) {
937 pr_err("clock enable failed rc:%d\n", rc);
938 goto clk_err;
939 }
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700940
941 sde_power_event_trigger_locked(phandle,
942 SDE_POWER_EVENT_POST_ENABLE);
943
Dhaval Patel480dc522016-07-27 18:36:59 -0700944 } else {
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700945 sde_power_event_trigger_locked(phandle,
946 SDE_POWER_EVENT_PRE_DISABLE);
947
Dhaval Patel480dc522016-07-27 18:36:59 -0700948 msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
949
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700950 sde_power_rsc_update(phandle, false);
951
Dhaval Patel480dc522016-07-27 18:36:59 -0700952 sde_power_reg_bus_update(phandle->reg_bus_hdl,
953 max_usecase_ndx);
954
Veera Sundaram Sankaran9aa24e92017-05-01 17:04:10 -0700955 if (!phandle->rsc_client)
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700956 msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
957 enable);
Alan Kwong0230a102017-05-16 11:36:44 -0700958 for (i = 0 ; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
959 sde_power_data_bus_update(&phandle->data_bus_handle[i],
960 enable);
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700961
962 sde_power_event_trigger_locked(phandle,
963 SDE_POWER_EVENT_POST_DISABLE);
Dhaval Patel480dc522016-07-27 18:36:59 -0700964 }
965
966end:
967 mutex_unlock(&phandle->phandle_lock);
968 return rc;
969
970clk_err:
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700971 sde_power_rsc_update(phandle, false);
972rsc_err:
Dhaval Patel480dc522016-07-27 18:36:59 -0700973 sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx);
974reg_bus_hdl_err:
Veera Sundaram Sankaran9aa24e92017-05-01 17:04:10 -0700975 if (!phandle->rsc_client)
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700976 msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
Dhaval Patel480dc522016-07-27 18:36:59 -0700977vreg_err:
Alan Kwong0230a102017-05-16 11:36:44 -0700978 for (i = 0 ; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
979 sde_power_data_bus_update(&phandle->data_bus_handle[i], 0);
Dhaval Patel60c25062017-02-21 17:44:05 -0800980data_bus_hdl_err:
Dhaval Patel480dc522016-07-27 18:36:59 -0700981 phandle->current_usecase_ndx = prev_usecase_ndx;
982 mutex_unlock(&phandle->phandle_lock);
983 return rc;
984}
985
Alan Kwong1124f1f2017-11-10 18:14:39 -0500986int sde_power_resource_is_enabled(struct sde_power_handle *phandle)
987{
988 if (!phandle) {
989 pr_err("invalid input argument\n");
990 return false;
991 }
992
993 return phandle->current_usecase_ndx != VOTE_INDEX_DISABLE;
994}
995
Dhaval Patel480dc522016-07-27 18:36:59 -0700996int sde_power_clk_set_rate(struct sde_power_handle *phandle, char *clock_name,
997 u64 rate)
998{
999 int i, rc = -EINVAL;
1000 struct dss_module_power *mp;
1001
1002 if (!phandle) {
1003 pr_err("invalid input power handle\n");
1004 return -EINVAL;
1005 }
1006 mp = &phandle->mp;
1007
1008 for (i = 0; i < mp->num_clk; i++) {
1009 if (!strcmp(mp->clk_config[i].clk_name, clock_name)) {
Alan Kwong83b6cbe2016-09-17 20:08:37 -04001010 if (mp->clk_config[i].max_rate &&
1011 (rate > mp->clk_config[i].max_rate))
1012 rate = mp->clk_config[i].max_rate;
1013
Dhaval Patel480dc522016-07-27 18:36:59 -07001014 mp->clk_config[i].rate = rate;
1015 rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
1016 break;
1017 }
1018 }
1019
1020 return rc;
1021}
1022
1023u64 sde_power_clk_get_rate(struct sde_power_handle *phandle, char *clock_name)
1024{
1025 int i;
1026 struct dss_module_power *mp;
1027 u64 rate = -EINVAL;
1028
1029 if (!phandle) {
1030 pr_err("invalid input power handle\n");
1031 return -EINVAL;
1032 }
1033 mp = &phandle->mp;
1034
1035 for (i = 0; i < mp->num_clk; i++) {
1036 if (!strcmp(mp->clk_config[i].clk_name, clock_name)) {
1037 rate = clk_get_rate(mp->clk_config[i].clk);
1038 break;
1039 }
1040 }
1041
1042 return rate;
1043}
Alan Kwong67a3f792016-11-01 23:16:53 -04001044
1045u64 sde_power_clk_get_max_rate(struct sde_power_handle *phandle,
1046 char *clock_name)
1047{
1048 int i;
1049 struct dss_module_power *mp;
1050 u64 rate = 0;
1051
1052 if (!phandle) {
1053 pr_err("invalid input power handle\n");
1054 return 0;
1055 }
1056 mp = &phandle->mp;
1057
1058 for (i = 0; i < mp->num_clk; i++) {
1059 if (!strcmp(mp->clk_config[i].clk_name, clock_name)) {
1060 rate = mp->clk_config[i].max_rate;
1061 break;
1062 }
1063 }
1064
1065 return rate;
1066}
1067
1068struct clk *sde_power_clk_get_clk(struct sde_power_handle *phandle,
1069 char *clock_name)
1070{
1071 int i;
1072 struct dss_module_power *mp;
1073 struct clk *clk = NULL;
1074
1075 if (!phandle) {
1076 pr_err("invalid input power handle\n");
1077 return 0;
1078 }
1079 mp = &phandle->mp;
1080
1081 for (i = 0; i < mp->num_clk; i++) {
1082 if (!strcmp(mp->clk_config[i].clk_name, clock_name)) {
1083 clk = mp->clk_config[i].clk;
1084 break;
1085 }
1086 }
1087
1088 return clk;
1089}
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -07001090
1091struct sde_power_event *sde_power_handle_register_event(
1092 struct sde_power_handle *phandle,
1093 u32 event_type, void (*cb_fnc)(u32 event_type, void *usr),
1094 void *usr, char *client_name)
1095{
1096 struct sde_power_event *event;
1097
1098 if (!phandle) {
1099 pr_err("invalid power handle\n");
1100 return ERR_PTR(-EINVAL);
1101 } else if (!cb_fnc || !event_type) {
1102 pr_err("no callback fnc or event type\n");
1103 return ERR_PTR(-EINVAL);
1104 }
1105
1106 event = kzalloc(sizeof(struct sde_power_event), GFP_KERNEL);
1107 if (!event)
1108 return ERR_PTR(-ENOMEM);
1109
1110 event->event_type = event_type;
1111 event->cb_fnc = cb_fnc;
1112 event->usr = usr;
1113 strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN);
1114 event->active = true;
1115
1116 mutex_lock(&phandle->phandle_lock);
1117 list_add(&event->list, &phandle->event_list);
1118 mutex_unlock(&phandle->phandle_lock);
1119
1120 return event;
1121}
1122
1123void sde_power_handle_unregister_event(
1124 struct sde_power_handle *phandle,
1125 struct sde_power_event *event)
1126{
1127 if (!phandle || !event) {
1128 pr_err("invalid phandle or event\n");
1129 } else if (!event->active) {
1130 pr_err("power handle deinit already done\n");
1131 kfree(event);
1132 } else {
1133 mutex_lock(&phandle->phandle_lock);
1134 list_del_init(&event->list);
1135 mutex_unlock(&phandle->phandle_lock);
1136 kfree(event);
1137 }
1138}