blob: 36184797d829b8b3eb7375752155e6afa4ce2dd7 [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
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -070033static void sde_power_event_trigger_locked(struct sde_power_handle *phandle,
34 u32 event_type)
35{
36 struct sde_power_event *event;
37
38 list_for_each_entry(event, &phandle->event_list, list) {
39 if (event->event_type & event_type)
40 event->cb_fnc(event_type, event->usr);
41 }
42}
43
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -070044static int sde_power_rsc_update(struct sde_power_handle *phandle, bool enable)
45{
46 u32 rsc_state;
Veera Sundaram Sankaran479defc2017-04-28 15:33:54 -070047 int ret = 0;
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -070048
49 /* creates the rsc client on the first enable */
50 if (!phandle->rsc_client_init) {
51 phandle->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX,
52 "sde_power_handle", false);
53 if (IS_ERR_OR_NULL(phandle->rsc_client)) {
54 pr_debug("sde rsc client create failed :%ld\n",
55 PTR_ERR(phandle->rsc_client));
56 phandle->rsc_client = NULL;
57 }
58 phandle->rsc_client_init = true;
59 }
60
61 rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
62
Veera Sundaram Sankaran479defc2017-04-28 15:33:54 -070063 if (phandle->rsc_client)
64 ret = sde_rsc_client_state_update(phandle->rsc_client,
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -070065 rsc_state, NULL, -1);
Veera Sundaram Sankaran479defc2017-04-28 15:33:54 -070066
67 return ret;
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -070068}
69
Dhaval Patel480dc522016-07-27 18:36:59 -070070struct sde_power_client *sde_power_client_create(
71 struct sde_power_handle *phandle, char *client_name)
72{
73 struct sde_power_client *client;
74 static u32 id;
75
76 if (!client_name || !phandle) {
77 pr_err("client name is null or invalid power data\n");
78 return ERR_PTR(-EINVAL);
79 }
80
81 client = kzalloc(sizeof(struct sde_power_client), GFP_KERNEL);
82 if (!client)
83 return ERR_PTR(-ENOMEM);
84
85 mutex_lock(&phandle->phandle_lock);
86 strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN);
87 client->usecase_ndx = VOTE_INDEX_DISABLE;
88 client->id = id;
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -070089 client->active = true;
Dhaval Patel480dc522016-07-27 18:36:59 -070090 pr_debug("client %s created:%pK id :%d\n", client_name,
91 client, id);
92 id++;
93 list_add(&client->list, &phandle->power_client_clist);
94 mutex_unlock(&phandle->phandle_lock);
95
96 return client;
97}
98
99void sde_power_client_destroy(struct sde_power_handle *phandle,
100 struct sde_power_client *client)
101{
102 if (!client || !phandle) {
103 pr_err("reg bus vote: invalid client handle\n");
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700104 } else if (!client->active) {
105 pr_err("sde power deinit already done\n");
106 kfree(client);
Dhaval Patel480dc522016-07-27 18:36:59 -0700107 } else {
108 pr_debug("bus vote client %s destroyed:%pK id:%u\n",
109 client->name, client, client->id);
110 mutex_lock(&phandle->phandle_lock);
111 list_del_init(&client->list);
112 mutex_unlock(&phandle->phandle_lock);
113 kfree(client);
114 }
115}
116
117static int sde_power_parse_dt_supply(struct platform_device *pdev,
118 struct dss_module_power *mp)
119{
120 int i = 0, rc = 0;
121 u32 tmp = 0;
122 struct device_node *of_node = NULL, *supply_root_node = NULL;
123 struct device_node *supply_node = NULL;
124
125 if (!pdev || !mp) {
126 pr_err("invalid input param pdev:%pK mp:%pK\n", pdev, mp);
127 return -EINVAL;
128 }
129
130 of_node = pdev->dev.of_node;
131
132 mp->num_vreg = 0;
133 supply_root_node = of_get_child_by_name(of_node,
134 "qcom,platform-supply-entries");
135 if (!supply_root_node) {
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700136 pr_debug("no supply entry present\n");
Dhaval Patel480dc522016-07-27 18:36:59 -0700137 return rc;
138 }
139
140 for_each_child_of_node(supply_root_node, supply_node)
141 mp->num_vreg++;
142
143 if (mp->num_vreg == 0) {
144 pr_debug("no vreg\n");
145 return rc;
146 }
147
148 pr_debug("vreg found. count=%d\n", mp->num_vreg);
149 mp->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct dss_vreg) *
150 mp->num_vreg, GFP_KERNEL);
151 if (!mp->vreg_config) {
152 rc = -ENOMEM;
153 return rc;
154 }
155
156 for_each_child_of_node(supply_root_node, supply_node) {
157
158 const char *st = NULL;
159
160 rc = of_property_read_string(supply_node,
161 "qcom,supply-name", &st);
162 if (rc) {
163 pr_err("error reading name. rc=%d\n", rc);
164 goto error;
165 }
166
167 strlcpy(mp->vreg_config[i].vreg_name, st,
168 sizeof(mp->vreg_config[i].vreg_name));
169
170 rc = of_property_read_u32(supply_node,
171 "qcom,supply-min-voltage", &tmp);
172 if (rc) {
173 pr_err("error reading min volt. rc=%d\n", rc);
174 goto error;
175 }
176 mp->vreg_config[i].min_voltage = tmp;
177
178 rc = of_property_read_u32(supply_node,
179 "qcom,supply-max-voltage", &tmp);
180 if (rc) {
181 pr_err("error reading max volt. rc=%d\n", rc);
182 goto error;
183 }
184 mp->vreg_config[i].max_voltage = tmp;
185
186 rc = of_property_read_u32(supply_node,
187 "qcom,supply-enable-load", &tmp);
188 if (rc) {
189 pr_err("error reading enable load. rc=%d\n", rc);
190 goto error;
191 }
192 mp->vreg_config[i].enable_load = tmp;
193
194 rc = of_property_read_u32(supply_node,
195 "qcom,supply-disable-load", &tmp);
196 if (rc) {
197 pr_err("error reading disable load. rc=%d\n", rc);
198 goto error;
199 }
200 mp->vreg_config[i].disable_load = tmp;
201
202 rc = of_property_read_u32(supply_node,
203 "qcom,supply-pre-on-sleep", &tmp);
204 if (rc)
205 pr_debug("error reading supply pre sleep value. rc=%d\n",
206 rc);
207
208 mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
209
210 rc = of_property_read_u32(supply_node,
211 "qcom,supply-pre-off-sleep", &tmp);
212 if (rc)
213 pr_debug("error reading supply pre sleep value. rc=%d\n",
214 rc);
215
216 mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
217
218 rc = of_property_read_u32(supply_node,
219 "qcom,supply-post-on-sleep", &tmp);
220 if (rc)
221 pr_debug("error reading supply post sleep value. rc=%d\n",
222 rc);
223
224 mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
225
226 rc = of_property_read_u32(supply_node,
227 "qcom,supply-post-off-sleep", &tmp);
228 if (rc)
229 pr_debug("error reading supply post sleep value. rc=%d\n",
230 rc);
231
232 mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
233
234 pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
235 mp->vreg_config[i].vreg_name,
236 mp->vreg_config[i].min_voltage,
237 mp->vreg_config[i].max_voltage,
238 mp->vreg_config[i].enable_load,
239 mp->vreg_config[i].disable_load,
240 mp->vreg_config[i].pre_on_sleep,
241 mp->vreg_config[i].post_on_sleep,
242 mp->vreg_config[i].pre_off_sleep,
243 mp->vreg_config[i].post_off_sleep);
244 ++i;
245
246 rc = 0;
247 }
248
249 return rc;
250
251error:
252 if (mp->vreg_config) {
253 devm_kfree(&pdev->dev, mp->vreg_config);
254 mp->vreg_config = NULL;
255 mp->num_vreg = 0;
256 }
257
258 return rc;
259}
260
261static int sde_power_parse_dt_clock(struct platform_device *pdev,
262 struct dss_module_power *mp)
263{
264 u32 i = 0, rc = 0;
265 const char *clock_name;
Kalyan Thota8f727922016-10-28 19:09:03 +0530266 u32 clock_rate = 0;
267 u32 clock_max_rate = 0;
268 int num_clk = 0;
Dhaval Patel480dc522016-07-27 18:36:59 -0700269
270 if (!pdev || !mp) {
271 pr_err("invalid input param pdev:%pK mp:%pK\n", pdev, mp);
272 return -EINVAL;
273 }
274
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700275 mp->num_clk = 0;
276 num_clk = of_property_count_strings(pdev->dev.of_node,
Dhaval Patel480dc522016-07-27 18:36:59 -0700277 "clock-names");
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700278 if (num_clk <= 0) {
279 pr_debug("clocks are not defined\n");
Dhaval Patel480dc522016-07-27 18:36:59 -0700280 goto clk_err;
281 }
282
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700283 mp->num_clk = num_clk;
Dhaval Patel480dc522016-07-27 18:36:59 -0700284 mp->clk_config = devm_kzalloc(&pdev->dev,
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700285 sizeof(struct dss_clk) * num_clk, GFP_KERNEL);
Dhaval Patel480dc522016-07-27 18:36:59 -0700286 if (!mp->clk_config) {
287 rc = -ENOMEM;
288 mp->num_clk = 0;
289 goto clk_err;
290 }
291
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700292 for (i = 0; i < num_clk; i++) {
Dhaval Patel480dc522016-07-27 18:36:59 -0700293 of_property_read_string_index(pdev->dev.of_node, "clock-names",
294 i, &clock_name);
295 strlcpy(mp->clk_config[i].clk_name, clock_name,
296 sizeof(mp->clk_config[i].clk_name));
297
298 of_property_read_u32_index(pdev->dev.of_node, "clock-rate",
299 i, &clock_rate);
300 mp->clk_config[i].rate = clock_rate;
301
302 if (!clock_rate)
303 mp->clk_config[i].type = DSS_CLK_AHB;
304 else
305 mp->clk_config[i].type = DSS_CLK_PCLK;
Alan Kwong83b6cbe2016-09-17 20:08:37 -0400306
307 clock_max_rate = 0;
308 of_property_read_u32_index(pdev->dev.of_node, "clock-max-rate",
309 i, &clock_max_rate);
310 mp->clk_config[i].max_rate = clock_max_rate;
Dhaval Patel480dc522016-07-27 18:36:59 -0700311 }
312
313clk_err:
314 return rc;
315}
316
317#ifdef CONFIG_QCOM_BUS_SCALING
Alan Kwong67a3f792016-11-01 23:16:53 -0400318
319#define MAX_AXI_PORT_COUNT 3
320
321static int _sde_power_data_bus_set_quota(
322 struct sde_power_data_bus_handle *pdbus,
323 u64 ab_quota_rt, u64 ab_quota_nrt,
324 u64 ib_quota_rt, u64 ib_quota_nrt)
325{
326 int new_uc_idx;
327 u64 ab_quota[MAX_AXI_PORT_COUNT] = {0, 0};
328 u64 ib_quota[MAX_AXI_PORT_COUNT] = {0, 0};
329 int rc;
330
331 if (pdbus->data_bus_hdl < 1) {
332 pr_err("invalid bus handle %d\n", pdbus->data_bus_hdl);
333 return -EINVAL;
334 }
335
336 if (!ab_quota_rt && !ab_quota_nrt && !ib_quota_rt && !ib_quota_nrt) {
337 new_uc_idx = 0;
338 } else {
339 int i;
340 struct msm_bus_vectors *vect = NULL;
341 struct msm_bus_scale_pdata *bw_table =
342 pdbus->data_bus_scale_table;
343 u32 nrt_axi_port_cnt = pdbus->nrt_axi_port_cnt;
344 u32 total_axi_port_cnt = pdbus->axi_port_cnt;
345 u32 rt_axi_port_cnt = total_axi_port_cnt - nrt_axi_port_cnt;
346 int match_cnt = 0;
347
348 if (!bw_table || !total_axi_port_cnt ||
349 total_axi_port_cnt > MAX_AXI_PORT_COUNT) {
350 pr_err("invalid input\n");
351 return -EINVAL;
352 }
353
354 if (pdbus->bus_channels) {
355 ib_quota_rt = div_u64(ib_quota_rt,
356 pdbus->bus_channels);
357 ib_quota_nrt = div_u64(ib_quota_nrt,
358 pdbus->bus_channels);
359 }
360
361 if (nrt_axi_port_cnt) {
362
363 ab_quota_rt = div_u64(ab_quota_rt, rt_axi_port_cnt);
364 ab_quota_nrt = div_u64(ab_quota_nrt, nrt_axi_port_cnt);
365
366 for (i = 0; i < total_axi_port_cnt; i++) {
367 if (i < rt_axi_port_cnt) {
368 ab_quota[i] = ab_quota_rt;
369 ib_quota[i] = ib_quota_rt;
370 } else {
371 ab_quota[i] = ab_quota_nrt;
372 ib_quota[i] = ib_quota_nrt;
373 }
374 }
375 } else {
376 ab_quota[0] = div_u64(ab_quota_rt + ab_quota_nrt,
377 total_axi_port_cnt);
378 ib_quota[0] = ib_quota_rt + ib_quota_nrt;
379
380 for (i = 1; i < total_axi_port_cnt; i++) {
381 ab_quota[i] = ab_quota[0];
382 ib_quota[i] = ib_quota[0];
383 }
384 }
385
386 for (i = 0; i < total_axi_port_cnt; i++) {
387 vect = &bw_table->usecase
388 [pdbus->curr_bw_uc_idx].vectors[i];
389 /* avoid performing updates for small changes */
390 if ((ab_quota[i] == vect->ab) &&
391 (ib_quota[i] == vect->ib))
392 match_cnt++;
393 }
394
395 if (match_cnt == total_axi_port_cnt) {
396 pr_debug("skip BW vote\n");
397 return 0;
398 }
399
400 new_uc_idx = (pdbus->curr_bw_uc_idx %
401 (bw_table->num_usecases - 1)) + 1;
402
403 for (i = 0; i < total_axi_port_cnt; i++) {
404 vect = &bw_table->usecase[new_uc_idx].vectors[i];
405 vect->ab = ab_quota[i];
406 vect->ib = ib_quota[i];
407
408 pr_debug("uc_idx=%d %s path idx=%d ab=%llu ib=%llu\n",
409 new_uc_idx, (i < rt_axi_port_cnt) ? "rt" : "nrt"
410 , i, vect->ab, vect->ib);
411 }
412 }
413 pdbus->curr_bw_uc_idx = new_uc_idx;
414 pdbus->ao_bw_uc_idx = new_uc_idx;
415
Dhaval Patel3fe015e2017-02-18 10:11:27 -0800416 SDE_ATRACE_BEGIN("msm_bus_scale_req");
417 rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl,
Alan Kwong67a3f792016-11-01 23:16:53 -0400418 new_uc_idx);
Dhaval Patel3fe015e2017-02-18 10:11:27 -0800419 SDE_ATRACE_END("msm_bus_scale_req");
420
Alan Kwong67a3f792016-11-01 23:16:53 -0400421 return rc;
422}
423
424int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,
425 struct sde_power_client *pclient,
426 int bus_client, u64 ab_quota, u64 ib_quota)
427{
428 int rc = 0;
429 int i;
430 u64 total_ab_rt = 0, total_ib_rt = 0;
431 u64 total_ab_nrt = 0, total_ib_nrt = 0;
432 struct sde_power_client *client;
433
434 if (!phandle || !pclient ||
435 bus_client >= SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX) {
436 pr_err("invalid parameters\n");
437 return -EINVAL;
438 }
439
440 mutex_lock(&phandle->phandle_lock);
441
442 pclient->ab[bus_client] = ab_quota;
443 pclient->ib[bus_client] = ib_quota;
444 trace_sde_perf_update_bus(bus_client, ab_quota, ib_quota);
445
446 list_for_each_entry(client, &phandle->power_client_clist, list) {
447 for (i = 0; i < SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX; i++) {
448 if (i == SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT) {
449 total_ab_nrt += client->ab[i];
450 total_ib_nrt += client->ib[i];
451 } else {
452 total_ab_rt += client->ab[i];
453 total_ib_rt = max(total_ib_rt, client->ib[i]);
454 }
455 }
456 }
457
458 rc = _sde_power_data_bus_set_quota(&phandle->data_bus_handle,
459 total_ab_rt, total_ab_nrt,
460 total_ib_rt, total_ib_nrt);
461
462 mutex_unlock(&phandle->phandle_lock);
463
464 return rc;
465}
466
467static void sde_power_data_bus_unregister(
468 struct sde_power_data_bus_handle *pdbus)
469{
470 if (pdbus->data_bus_hdl) {
471 msm_bus_scale_unregister_client(pdbus->data_bus_hdl);
472 pdbus->data_bus_hdl = 0;
473 }
474}
475
476static int sde_power_data_bus_parse(struct platform_device *pdev,
477 struct sde_power_data_bus_handle *pdbus)
478{
479 struct device_node *node;
480 int rc = 0;
481 int paths;
482
483 pdbus->bus_channels = 1;
484 rc = of_property_read_u32(pdev->dev.of_node,
485 "qcom,sde-dram-channels", &pdbus->bus_channels);
Alan Kwong1bd11be2017-01-10 10:31:39 -0500486 if (rc) {
Alan Kwong67a3f792016-11-01 23:16:53 -0400487 pr_debug("number of channels property not specified\n");
Alan Kwong1bd11be2017-01-10 10:31:39 -0500488 rc = 0;
489 }
Alan Kwong67a3f792016-11-01 23:16:53 -0400490
491 pdbus->nrt_axi_port_cnt = 0;
492 rc = of_property_read_u32(pdev->dev.of_node,
493 "qcom,sde-num-nrt-paths",
494 &pdbus->nrt_axi_port_cnt);
Alan Kwong1bd11be2017-01-10 10:31:39 -0500495 if (rc) {
496 pr_debug("number of axi port property not specified\n");
497 rc = 0;
498 }
Alan Kwong67a3f792016-11-01 23:16:53 -0400499
500 node = of_get_child_by_name(pdev->dev.of_node, "qcom,sde-data-bus");
501 if (node) {
502 rc = of_property_read_u32(node,
503 "qcom,msm-bus,num-paths", &paths);
504 if (rc) {
505 pr_err("Error. qcom,msm-bus,num-paths not found\n");
506 return rc;
507 }
508 pdbus->axi_port_cnt = paths;
509
510 pdbus->data_bus_scale_table =
511 msm_bus_pdata_from_node(pdev, node);
512 if (IS_ERR_OR_NULL(pdbus->data_bus_scale_table)) {
513 pr_err("reg bus handle parsing failed\n");
514 rc = PTR_ERR(pdbus->data_bus_scale_table);
Dhaval Patel5398f602017-03-25 18:25:18 -0700515 if (!pdbus->data_bus_scale_table)
516 rc = -EINVAL;
Alan Kwong67a3f792016-11-01 23:16:53 -0400517 goto end;
518 }
519 pdbus->data_bus_hdl = msm_bus_scale_register_client(
520 pdbus->data_bus_scale_table);
521 if (!pdbus->data_bus_hdl) {
522 pr_err("data_bus_client register failed\n");
523 rc = -EINVAL;
524 goto end;
525 }
526 pr_debug("register data_bus_hdl=%x\n", pdbus->data_bus_hdl);
Alan Kwong67a3f792016-11-01 23:16:53 -0400527 }
528
529end:
530 return rc;
531}
532
Dhaval Patel480dc522016-07-27 18:36:59 -0700533static int sde_power_reg_bus_parse(struct platform_device *pdev,
534 struct sde_power_handle *phandle)
535{
536 struct device_node *node;
537 struct msm_bus_scale_pdata *bus_scale_table;
538 int rc = 0;
539
540 node = of_get_child_by_name(pdev->dev.of_node, "qcom,sde-reg-bus");
541 if (node) {
542 bus_scale_table = msm_bus_pdata_from_node(pdev, node);
543 if (IS_ERR_OR_NULL(bus_scale_table)) {
544 pr_err("reg bus handle parsing failed\n");
545 rc = PTR_ERR(bus_scale_table);
Dhaval Patel5398f602017-03-25 18:25:18 -0700546 if (!bus_scale_table)
547 rc = -EINVAL;
Dhaval Patel480dc522016-07-27 18:36:59 -0700548 goto end;
549 }
550 phandle->reg_bus_hdl = msm_bus_scale_register_client(
551 bus_scale_table);
552 if (!phandle->reg_bus_hdl) {
553 pr_err("reg_bus_client register failed\n");
554 rc = -EINVAL;
555 goto end;
556 }
557 pr_debug("register reg_bus_hdl=%x\n", phandle->reg_bus_hdl);
558 }
559
560end:
561 return rc;
562}
563
564static void sde_power_reg_bus_unregister(u32 reg_bus_hdl)
565{
566 if (reg_bus_hdl)
567 msm_bus_scale_unregister_client(reg_bus_hdl);
568}
569
Dhaval Patel60c25062017-02-21 17:44:05 -0800570static int sde_power_data_bus_update(struct sde_power_data_bus_handle *pdbus,
571 bool enable)
572{
573 int rc = 0;
574 u64 ab_quota_rt, ab_quota_nrt;
575 u64 ib_quota_rt, ib_quota_nrt;
576
577 ab_quota_rt = ab_quota_nrt = enable ?
578 SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA :
579 SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA;
580 ib_quota_rt = ib_quota_nrt = enable ?
581 SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA :
582 SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA;
583
584 if (pdbus->data_bus_hdl)
585 rc = _sde_power_data_bus_set_quota(pdbus, ab_quota_rt,
586 ab_quota_nrt, ib_quota_rt, ib_quota_nrt);
587
588 if (rc)
589 pr_err("failed to set data bus vote rc=%d enable:%d\n",
590 rc, enable);
591
592 return rc;
593}
594
Dhaval Patel480dc522016-07-27 18:36:59 -0700595static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx)
596{
597 int rc = 0;
598
599 if (reg_bus_hdl)
600 rc = msm_bus_scale_client_update_request(reg_bus_hdl,
601 usecase_ndx);
602 if (rc)
603 pr_err("failed to set reg bus vote rc=%d\n", rc);
604
605 return rc;
606}
607#else
Alan Kwong67a3f792016-11-01 23:16:53 -0400608static int sde_power_data_bus_parse(struct platform_device *pdev,
609 struct sde_power_data_bus_handle *pdbus)
610{
611 return 0;
612}
613
614static void sde_power_data_bus_unregister(
615 struct sde_power_data_bus_handle *pdbus)
616{
617}
618
619int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,
620 struct sde_power_client *pclient,
621 int bus_client, u64 ab_quota, u64 ib_quota)
622{
623 return 0;
624}
625
Dhaval Patel480dc522016-07-27 18:36:59 -0700626static int sde_power_reg_bus_parse(struct platform_device *pdev,
627 struct sde_power_handle *phandle)
628{
629 return 0;
630}
631
632static void sde_power_reg_bus_unregister(u32 reg_bus_hdl)
633{
634}
635
636static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx)
637{
638 return 0;
639}
Dhaval Patel60c25062017-02-21 17:44:05 -0800640
641static int sde_power_data_bus_update(struct sde_power_data_bus_handle *pdbus,
642 bool enable)
643{
644 return 0;
645}
Dhaval Patel480dc522016-07-27 18:36:59 -0700646#endif
647
648int sde_power_resource_init(struct platform_device *pdev,
649 struct sde_power_handle *phandle)
650{
651 int rc = 0;
652 struct dss_module_power *mp;
653
654 if (!phandle || !pdev) {
655 pr_err("invalid input param\n");
656 rc = -EINVAL;
657 goto end;
658 }
659 mp = &phandle->mp;
Alan Kwong67a3f792016-11-01 23:16:53 -0400660 phandle->dev = &pdev->dev;
Dhaval Patel480dc522016-07-27 18:36:59 -0700661
662 rc = sde_power_parse_dt_clock(pdev, mp);
663 if (rc) {
664 pr_err("device clock parsing failed\n");
665 goto end;
666 }
667
668 rc = sde_power_parse_dt_supply(pdev, mp);
669 if (rc) {
670 pr_err("device vreg supply parsing failed\n");
671 goto parse_vreg_err;
672 }
673
674 rc = msm_dss_config_vreg(&pdev->dev,
675 mp->vreg_config, mp->num_vreg, 1);
676 if (rc) {
677 pr_err("vreg config failed rc=%d\n", rc);
678 goto vreg_err;
679 }
680
681 rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, mp->num_clk);
682 if (rc) {
683 pr_err("clock get failed rc=%d\n", rc);
684 goto clk_err;
685 }
686
687 rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
688 if (rc) {
689 pr_err("clock set rate failed rc=%d\n", rc);
690 goto bus_err;
691 }
692
693 rc = sde_power_reg_bus_parse(pdev, phandle);
694 if (rc) {
695 pr_err("register bus parse failed rc=%d\n", rc);
696 goto bus_err;
697 }
698
Alan Kwong67a3f792016-11-01 23:16:53 -0400699 rc = sde_power_data_bus_parse(pdev, &phandle->data_bus_handle);
700 if (rc) {
701 pr_err("register data bus parse failed rc=%d\n", rc);
702 goto data_bus_err;
703 }
704
Dhaval Patel480dc522016-07-27 18:36:59 -0700705 INIT_LIST_HEAD(&phandle->power_client_clist);
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700706 INIT_LIST_HEAD(&phandle->event_list);
707
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700708 phandle->rsc_client = NULL;
709 phandle->rsc_client_init = false;
710
Dhaval Patel480dc522016-07-27 18:36:59 -0700711 mutex_init(&phandle->phandle_lock);
712
713 return rc;
714
Alan Kwong67a3f792016-11-01 23:16:53 -0400715data_bus_err:
716 sde_power_reg_bus_unregister(phandle->reg_bus_hdl);
Dhaval Patel480dc522016-07-27 18:36:59 -0700717bus_err:
718 msm_dss_put_clk(mp->clk_config, mp->num_clk);
719clk_err:
720 msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
721vreg_err:
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700722 if (mp->vreg_config)
723 devm_kfree(&pdev->dev, mp->vreg_config);
Dhaval Patel480dc522016-07-27 18:36:59 -0700724 mp->num_vreg = 0;
725parse_vreg_err:
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700726 if (mp->clk_config)
727 devm_kfree(&pdev->dev, mp->clk_config);
Dhaval Patel480dc522016-07-27 18:36:59 -0700728 mp->num_clk = 0;
729end:
730 return rc;
731}
732
733void sde_power_resource_deinit(struct platform_device *pdev,
734 struct sde_power_handle *phandle)
735{
736 struct dss_module_power *mp;
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700737 struct sde_power_client *curr_client, *next_client;
738 struct sde_power_event *curr_event, *next_event;
Dhaval Patel480dc522016-07-27 18:36:59 -0700739
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700740 if (!phandle || !pdev) {
Dhaval Patel480dc522016-07-27 18:36:59 -0700741 pr_err("invalid input param\n");
742 return;
743 }
744 mp = &phandle->mp;
745
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700746 mutex_lock(&phandle->phandle_lock);
747 list_for_each_entry_safe(curr_client, next_client,
748 &phandle->power_client_clist, list) {
749 pr_err("cliend:%s-%d still registered with refcount:%d\n",
750 curr_client->name, curr_client->id,
751 curr_client->refcount);
752 curr_client->active = false;
753 list_del(&curr_client->list);
754 }
755
756 list_for_each_entry_safe(curr_event, next_event,
757 &phandle->event_list, list) {
758 pr_err("event:%d, client:%s still registered\n",
759 curr_event->event_type,
760 curr_event->client_name);
761 curr_event->active = false;
762 list_del(&curr_event->list);
763 }
764 mutex_unlock(&phandle->phandle_lock);
765
Alan Kwong67a3f792016-11-01 23:16:53 -0400766 sde_power_data_bus_unregister(&phandle->data_bus_handle);
767
Dhaval Patel480dc522016-07-27 18:36:59 -0700768 sde_power_reg_bus_unregister(phandle->reg_bus_hdl);
769
770 msm_dss_put_clk(mp->clk_config, mp->num_clk);
771
772 msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
773
Dhaval Patelcd78b8a2016-10-11 10:26:07 -0700774 if (mp->clk_config)
775 devm_kfree(&pdev->dev, mp->clk_config);
776
777 if (mp->vreg_config)
778 devm_kfree(&pdev->dev, mp->vreg_config);
779
Dhaval Patel480dc522016-07-27 18:36:59 -0700780 mp->num_vreg = 0;
781 mp->num_clk = 0;
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700782
783 if (phandle->rsc_client)
784 sde_rsc_client_destroy(phandle->rsc_client);
Dhaval Patel480dc522016-07-27 18:36:59 -0700785}
786
787int sde_power_resource_enable(struct sde_power_handle *phandle,
788 struct sde_power_client *pclient, bool enable)
789{
790 int rc = 0;
791 bool changed = false;
792 u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx;
793 struct sde_power_client *client;
794 struct dss_module_power *mp;
795
796 if (!phandle || !pclient) {
797 pr_err("invalid input argument\n");
798 return -EINVAL;
799 }
800
801 mp = &phandle->mp;
802
803 mutex_lock(&phandle->phandle_lock);
804 if (enable)
805 pclient->refcount++;
806 else if (pclient->refcount)
807 pclient->refcount--;
808
809 if (pclient->refcount)
810 pclient->usecase_ndx = VOTE_INDEX_LOW;
811 else
812 pclient->usecase_ndx = VOTE_INDEX_DISABLE;
813
814 list_for_each_entry(client, &phandle->power_client_clist, list) {
815 if (client->usecase_ndx < VOTE_INDEX_MAX &&
816 client->usecase_ndx > max_usecase_ndx)
817 max_usecase_ndx = client->usecase_ndx;
818 }
819
820 if (phandle->current_usecase_ndx != max_usecase_ndx) {
821 changed = true;
822 prev_usecase_ndx = phandle->current_usecase_ndx;
823 phandle->current_usecase_ndx = max_usecase_ndx;
824 }
825
826 pr_debug("%pS: changed=%d current idx=%d request client %s id:%u enable:%d refcount:%d\n",
827 __builtin_return_address(0), changed, max_usecase_ndx,
828 pclient->name, pclient->id, enable, pclient->refcount);
829
830 if (!changed)
831 goto end;
832
833 if (enable) {
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700834 sde_power_event_trigger_locked(phandle,
835 SDE_POWER_EVENT_PRE_ENABLE);
836
Dhaval Patel60c25062017-02-21 17:44:05 -0800837 rc = sde_power_data_bus_update(&phandle->data_bus_handle,
838 enable);
839 if (rc) {
840 pr_err("failed to set data bus vote rc=%d\n", rc);
841 goto data_bus_hdl_err;
842 }
843
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700844 if (!phandle->rsc_client_init) {
845 rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
846 enable);
847 if (rc) {
848 pr_err("failed to enable vregs rc=%d\n", rc);
849 goto vreg_err;
850 }
Dhaval Patel480dc522016-07-27 18:36:59 -0700851 }
852
853 rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
854 max_usecase_ndx);
855 if (rc) {
856 pr_err("failed to set reg bus vote rc=%d\n", rc);
857 goto reg_bus_hdl_err;
858 }
859
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700860 rc = sde_power_rsc_update(phandle, true);
861 if (rc) {
862 pr_err("failed to update rsc\n");
863 goto rsc_err;
864 }
865
Dhaval Patel480dc522016-07-27 18:36:59 -0700866 rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
867 if (rc) {
868 pr_err("clock enable failed rc:%d\n", rc);
869 goto clk_err;
870 }
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700871
872 sde_power_event_trigger_locked(phandle,
873 SDE_POWER_EVENT_POST_ENABLE);
874
Dhaval Patel480dc522016-07-27 18:36:59 -0700875 } else {
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700876 sde_power_event_trigger_locked(phandle,
877 SDE_POWER_EVENT_PRE_DISABLE);
878
Dhaval Patel480dc522016-07-27 18:36:59 -0700879 msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
880
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700881 sde_power_rsc_update(phandle, false);
882
Dhaval Patel480dc522016-07-27 18:36:59 -0700883 sde_power_reg_bus_update(phandle->reg_bus_hdl,
884 max_usecase_ndx);
885
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700886 if (!phandle->rsc_client_init)
887 msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
888 enable);
Dhaval Patel60c25062017-02-21 17:44:05 -0800889 sde_power_data_bus_update(&phandle->data_bus_handle, enable);
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -0700890
891 sde_power_event_trigger_locked(phandle,
892 SDE_POWER_EVENT_POST_DISABLE);
Dhaval Patel480dc522016-07-27 18:36:59 -0700893 }
894
895end:
896 mutex_unlock(&phandle->phandle_lock);
897 return rc;
898
899clk_err:
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700900 sde_power_rsc_update(phandle, false);
901rsc_err:
Dhaval Patel480dc522016-07-27 18:36:59 -0700902 sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx);
903reg_bus_hdl_err:
Veera Sundaram Sankaran38318f12017-03-24 15:54:21 -0700904 if (!phandle->rsc_client_init)
905 msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
Dhaval Patel480dc522016-07-27 18:36:59 -0700906vreg_err:
Dhaval Patel60c25062017-02-21 17:44:05 -0800907 sde_power_data_bus_update(&phandle->data_bus_handle, 0);
908data_bus_hdl_err:
Dhaval Patel480dc522016-07-27 18:36:59 -0700909 phandle->current_usecase_ndx = prev_usecase_ndx;
910 mutex_unlock(&phandle->phandle_lock);
911 return rc;
912}
913
914int sde_power_clk_set_rate(struct sde_power_handle *phandle, char *clock_name,
915 u64 rate)
916{
917 int i, rc = -EINVAL;
918 struct dss_module_power *mp;
919
920 if (!phandle) {
921 pr_err("invalid input power handle\n");
922 return -EINVAL;
923 }
924 mp = &phandle->mp;
925
926 for (i = 0; i < mp->num_clk; i++) {
927 if (!strcmp(mp->clk_config[i].clk_name, clock_name)) {
Alan Kwong83b6cbe2016-09-17 20:08:37 -0400928 if (mp->clk_config[i].max_rate &&
929 (rate > mp->clk_config[i].max_rate))
930 rate = mp->clk_config[i].max_rate;
931
Dhaval Patel480dc522016-07-27 18:36:59 -0700932 mp->clk_config[i].rate = rate;
933 rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
934 break;
935 }
936 }
937
938 return rc;
939}
940
941u64 sde_power_clk_get_rate(struct sde_power_handle *phandle, char *clock_name)
942{
943 int i;
944 struct dss_module_power *mp;
945 u64 rate = -EINVAL;
946
947 if (!phandle) {
948 pr_err("invalid input power handle\n");
949 return -EINVAL;
950 }
951 mp = &phandle->mp;
952
953 for (i = 0; i < mp->num_clk; i++) {
954 if (!strcmp(mp->clk_config[i].clk_name, clock_name)) {
955 rate = clk_get_rate(mp->clk_config[i].clk);
956 break;
957 }
958 }
959
960 return rate;
961}
Alan Kwong67a3f792016-11-01 23:16:53 -0400962
963u64 sde_power_clk_get_max_rate(struct sde_power_handle *phandle,
964 char *clock_name)
965{
966 int i;
967 struct dss_module_power *mp;
968 u64 rate = 0;
969
970 if (!phandle) {
971 pr_err("invalid input power handle\n");
972 return 0;
973 }
974 mp = &phandle->mp;
975
976 for (i = 0; i < mp->num_clk; i++) {
977 if (!strcmp(mp->clk_config[i].clk_name, clock_name)) {
978 rate = mp->clk_config[i].max_rate;
979 break;
980 }
981 }
982
983 return rate;
984}
985
986struct clk *sde_power_clk_get_clk(struct sde_power_handle *phandle,
987 char *clock_name)
988{
989 int i;
990 struct dss_module_power *mp;
991 struct clk *clk = NULL;
992
993 if (!phandle) {
994 pr_err("invalid input power handle\n");
995 return 0;
996 }
997 mp = &phandle->mp;
998
999 for (i = 0; i < mp->num_clk; i++) {
1000 if (!strcmp(mp->clk_config[i].clk_name, clock_name)) {
1001 clk = mp->clk_config[i].clk;
1002 break;
1003 }
1004 }
1005
1006 return clk;
1007}
Veera Sundaram Sankaran410d1562017-03-24 14:48:13 -07001008
1009struct sde_power_event *sde_power_handle_register_event(
1010 struct sde_power_handle *phandle,
1011 u32 event_type, void (*cb_fnc)(u32 event_type, void *usr),
1012 void *usr, char *client_name)
1013{
1014 struct sde_power_event *event;
1015
1016 if (!phandle) {
1017 pr_err("invalid power handle\n");
1018 return ERR_PTR(-EINVAL);
1019 } else if (!cb_fnc || !event_type) {
1020 pr_err("no callback fnc or event type\n");
1021 return ERR_PTR(-EINVAL);
1022 }
1023
1024 event = kzalloc(sizeof(struct sde_power_event), GFP_KERNEL);
1025 if (!event)
1026 return ERR_PTR(-ENOMEM);
1027
1028 event->event_type = event_type;
1029 event->cb_fnc = cb_fnc;
1030 event->usr = usr;
1031 strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN);
1032 event->active = true;
1033
1034 mutex_lock(&phandle->phandle_lock);
1035 list_add(&event->list, &phandle->event_list);
1036 mutex_unlock(&phandle->phandle_lock);
1037
1038 return event;
1039}
1040
1041void sde_power_handle_unregister_event(
1042 struct sde_power_handle *phandle,
1043 struct sde_power_event *event)
1044{
1045 if (!phandle || !event) {
1046 pr_err("invalid phandle or event\n");
1047 } else if (!event->active) {
1048 pr_err("power handle deinit already done\n");
1049 kfree(event);
1050 } else {
1051 mutex_lock(&phandle->phandle_lock);
1052 list_del_init(&event->list);
1053 mutex_unlock(&phandle->phandle_lock);
1054 kfree(event);
1055 }
1056}