blob: 50710cd5c30c08bd9e287a38cf1c650659b2e20a [file] [log] [blame]
Dhaval Patel020f7e122016-11-15 14:39:18 -08001/* Copyright (c) 2016-2017, 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) "[sde_rsc:%s:%d]: " fmt, __func__, __LINE__
15
16#include <linux/kernel.h>
17#include <linux/debugfs.h>
18#include <linux/of.h>
19#include <linux/string.h>
20#include <linux/of_address.h>
21#include <linux/component.h>
22#include <linux/slab.h>
23#include <linux/mutex.h>
24#include <linux/of_platform.h>
25#include <linux/module.h>
26
27#include <soc/qcom/rpmh.h>
28#include <drm/drmP.h>
29#include <drm/drm_irq.h>
Dhaval Patel49ef6d72017-03-26 09:35:53 -070030#include "sde_rsc_priv.h"
Dhaval Patel824e9682017-05-01 23:31:22 -070031#include "sde_dbg.h"
Dhaval Patel020f7e122016-11-15 14:39:18 -080032
Dhaval Patel824e9682017-05-01 23:31:22 -070033/* worst case time to execute the one tcs vote(sleep/wake) - ~1ms */
34#define TCS_CASE_EXECUTION_TIME 1064000
Dhaval Patel020f7e122016-11-15 14:39:18 -080035
Dhaval Patel824e9682017-05-01 23:31:22 -070036/* this time is ~1ms - only wake tcs in any mode */
37#define RSC_BACKOFF_TIME_NS (TCS_CASE_EXECUTION_TIME + 100)
Dhaval Patel020f7e122016-11-15 14:39:18 -080038
Dhaval Patel824e9682017-05-01 23:31:22 -070039/* this time is ~1ms - only wake TCS in mode-0 */
40#define RSC_MODE_THRESHOLD_TIME_IN_NS ((TCS_CASE_EXECUTION_TIME >> 1) + 100)
41
42/* this time is ~2ms - sleep+ wake TCS in mode-1 */
43#define RSC_TIME_SLOT_0_NS ((TCS_CASE_EXECUTION_TIME * 2) + 100)
Dhaval Patel020f7e122016-11-15 14:39:18 -080044
45#define DEFAULT_PANEL_FPS 60
46#define DEFAULT_PANEL_JITTER 5
47#define DEFAULT_PANEL_PREFILL_LINES 16
48#define DEFAULT_PANEL_VTOTAL (480 + DEFAULT_PANEL_PREFILL_LINES)
49#define TICKS_IN_NANO_SECOND 1000000000
50
51#define MAX_BUFFER_SIZE 256
52
53#define TRY_CMD_MODE_SWITCH 0xFFFF
Dhaval Patela65b0f12017-03-16 00:36:55 -070054#define TRY_CLK_MODE_SWITCH 0xFFFE
55#define STATE_UPDATE_NOT_ALLOWED 0xFFFD
Dhaval Patel020f7e122016-11-15 14:39:18 -080056
57static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT];
58
59/**
60 * sde_rsc_client_create() - create the client for sde rsc.
61 * Different displays like DSI, HDMI, DP, WB, etc should call this
62 * api to register their vote for rpmh. They still need to vote for
63 * power handle to get the clocks.
64
65 * @rsc_index: A client will be created on this RSC. As of now only
66 * SDE_RSC_INDEX is valid rsc index.
67 * @name: Caller needs to provide some valid string to identify
68 * the client. "primary", "dp", "hdmi" are suggested name.
69 * @is_primary: Caller needs to provide information if client is primary
70 * or not. Primary client votes will be redirected to
71 * display rsc.
72 *
73 * Return: client node pointer.
74 */
75struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *client_name,
76 bool is_primary_client)
77{
78 struct sde_rsc_client *client;
79 struct sde_rsc_priv *rsc;
Dhaval Patel824e9682017-05-01 23:31:22 -070080 static int id;
Dhaval Patel020f7e122016-11-15 14:39:18 -080081
82 if (!client_name) {
83 pr_err("client name is null- not supported\n");
84 return ERR_PTR(-EINVAL);
85 } else if (rsc_index >= MAX_RSC_COUNT) {
86 pr_err("invalid rsc index\n");
87 return ERR_PTR(-EINVAL);
88 } else if (!rsc_prv_list[rsc_index]) {
89 pr_err("rsc not probed yet or not available\n");
Dhaval Patel824e9682017-05-01 23:31:22 -070090 return NULL;
Dhaval Patel020f7e122016-11-15 14:39:18 -080091 }
92
93 rsc = rsc_prv_list[rsc_index];
94 client = kzalloc(sizeof(struct sde_rsc_client), GFP_KERNEL);
95 if (!client)
96 return ERR_PTR(-ENOMEM);
97
98 mutex_lock(&rsc->client_lock);
99 strlcpy(client->name, client_name, MAX_RSC_CLIENT_NAME_LEN);
100 client->current_state = SDE_RSC_IDLE_STATE;
101 client->rsc_index = rsc_index;
Dhaval Patel824e9682017-05-01 23:31:22 -0700102 client->id = id;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800103 if (is_primary_client)
104 rsc->primary_client = client;
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800105 pr_debug("client %s rsc index:%d primary:%d\n", client_name,
106 rsc_index, is_primary_client);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800107
108 list_add(&client->list, &rsc->client_list);
Dhaval Patel824e9682017-05-01 23:31:22 -0700109 id++;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800110 mutex_unlock(&rsc->client_lock);
111
112 return client;
113}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700114EXPORT_SYMBOL(sde_rsc_client_create);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800115
116/**
117 * sde_rsc_client_destroy() - Destroy the sde rsc client.
118 *
119 * @client: Client pointer provided by sde_rsc_client_create().
120 *
121 * Return: none
122 */
123void sde_rsc_client_destroy(struct sde_rsc_client *client)
124{
125 struct sde_rsc_priv *rsc;
126
127 if (!client) {
128 pr_debug("invalid client\n");
129 goto end;
130 } else if (client->rsc_index >= MAX_RSC_COUNT) {
131 pr_err("invalid rsc index\n");
132 goto end;
133 }
134
135 pr_debug("client %s destroyed\n", client->name);
136 rsc = rsc_prv_list[client->rsc_index];
137 if (!rsc)
138 goto end;
139
140 mutex_lock(&rsc->client_lock);
141 if (client->current_state != SDE_RSC_IDLE_STATE)
142 sde_rsc_client_state_update(client, SDE_RSC_IDLE_STATE,
143 NULL, -1);
144 list_del_init(&client->list);
145 mutex_unlock(&rsc->client_lock);
146
147 kfree(client);
148end:
149 return;
150}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700151EXPORT_SYMBOL(sde_rsc_client_destroy);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800152
Dhaval Patel031b4152017-03-16 13:03:18 -0700153struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
154 void (*cb_func)(uint32_t event_type, void *usr), void *usr)
155{
156 struct sde_rsc_event *evt;
157 struct sde_rsc_priv *rsc;
158
159 if (rsc_index >= MAX_RSC_COUNT) {
160 pr_err("invalid rsc index:%d\n", rsc_index);
161 return ERR_PTR(-EINVAL);
162 } else if (!rsc_prv_list[rsc_index]) {
163 pr_err("rsc idx:%d not probed yet or not available\n",
164 rsc_index);
165 return ERR_PTR(-EINVAL);
166 } else if (!cb_func || !event_type) {
167 pr_err("no event or cb func\n");
168 return ERR_PTR(-EINVAL);
169 }
170
171 rsc = rsc_prv_list[rsc_index];
172 evt = kzalloc(sizeof(struct sde_rsc_event), GFP_KERNEL);
173 if (!evt)
174 return ERR_PTR(-ENOMEM);
175
176 evt->event_type = event_type;
177 evt->rsc_index = rsc_index;
178 evt->usr = usr;
179 evt->cb_func = cb_func;
180 pr_debug("event register type:%d rsc index:%d\n",
181 event_type, rsc_index);
182
183 mutex_lock(&rsc->client_lock);
184 list_add(&evt->list, &rsc->event_list);
185 mutex_unlock(&rsc->client_lock);
186
187 return evt;
188}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700189EXPORT_SYMBOL(sde_rsc_register_event);
Dhaval Patel031b4152017-03-16 13:03:18 -0700190
191void sde_rsc_unregister_event(struct sde_rsc_event *event)
192{
193 struct sde_rsc_priv *rsc;
194
195 if (!event) {
196 pr_debug("invalid event client\n");
197 goto end;
198 } else if (event->rsc_index >= MAX_RSC_COUNT) {
199 pr_err("invalid rsc index\n");
200 goto end;
201 }
202
203 pr_debug("event client destroyed\n");
204 rsc = rsc_prv_list[event->rsc_index];
205 if (!rsc)
206 goto end;
207
208 mutex_lock(&rsc->client_lock);
209 list_del_init(&event->list);
210 mutex_unlock(&rsc->client_lock);
211
212 kfree(event);
213end:
214 return;
215}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700216EXPORT_SYMBOL(sde_rsc_unregister_event);
Dhaval Patel031b4152017-03-16 13:03:18 -0700217
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700218static int sde_rsc_clk_enable(struct sde_power_handle *phandle,
219 struct sde_power_client *pclient, bool enable)
220{
221 int rc = 0;
222 struct dss_module_power *mp;
223
224 if (!phandle || !pclient) {
225 pr_err("invalid input argument\n");
226 return -EINVAL;
227 }
228
229 mp = &phandle->mp;
230
231 if (enable)
232 pclient->refcount++;
233 else if (pclient->refcount)
234 pclient->refcount--;
235
236 if (pclient->refcount)
237 pclient->usecase_ndx = VOTE_INDEX_LOW;
238 else
239 pclient->usecase_ndx = VOTE_INDEX_DISABLE;
240
241 if (phandle->current_usecase_ndx == pclient->usecase_ndx)
242 goto end;
243
244 if (enable) {
245 rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
246 if (rc) {
247 pr_err("clock enable failed rc:%d\n", rc);
248 goto end;
249 }
250 } else {
251 msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
252 }
253
254 phandle->current_usecase_ndx = pclient->usecase_ndx;
255
256end:
257 return rc;
258}
259
Dhaval Patel020f7e122016-11-15 14:39:18 -0800260static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800261 struct sde_rsc_cmd_config *cmd_config)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800262{
263 const u32 cxo_period_ns = 52;
264 u64 rsc_backoff_time_ns = RSC_BACKOFF_TIME_NS;
265 u64 rsc_mode_threshold_time_ns = RSC_MODE_THRESHOLD_TIME_IN_NS;
266 u64 rsc_time_slot_0_ns = RSC_TIME_SLOT_0_NS;
267 u64 rsc_time_slot_1_ns;
268 const u64 pdc_jitter = 20; /* 20% more */
269
270 u64 frame_time_ns, frame_jitter;
271 u64 line_time_ns, prefill_time_ns;
272 u64 pdc_backoff_time_ns;
273 s64 total;
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800274 int ret = 0;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800275
276 if (cmd_config)
277 memcpy(&rsc->cmd_config, cmd_config, sizeof(*cmd_config));
278
279 /* calculate for 640x480 60 fps resolution by default */
280 if (!rsc->cmd_config.fps)
281 rsc->cmd_config.fps = DEFAULT_PANEL_FPS;
282 if (!rsc->cmd_config.jitter)
283 rsc->cmd_config.jitter = DEFAULT_PANEL_JITTER;
284 if (!rsc->cmd_config.vtotal)
285 rsc->cmd_config.vtotal = DEFAULT_PANEL_VTOTAL;
286 if (!rsc->cmd_config.prefill_lines)
287 rsc->cmd_config.prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
288 pr_debug("frame fps:%d jitter:%d vtotal:%d prefill lines:%d\n",
289 rsc->cmd_config.fps, rsc->cmd_config.jitter,
290 rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines);
291
292 /* 1 nano second */
293 frame_time_ns = TICKS_IN_NANO_SECOND;
294 frame_time_ns = div_u64(frame_time_ns, rsc->cmd_config.fps);
295
296 frame_jitter = frame_time_ns * rsc->cmd_config.jitter;
297 /* convert it to percentage */
298 frame_jitter = div_u64(frame_jitter, 100);
299
300 line_time_ns = frame_time_ns;
301 line_time_ns = div_u64(line_time_ns, rsc->cmd_config.vtotal);
302 prefill_time_ns = line_time_ns * rsc->cmd_config.prefill_lines;
303
304 total = frame_time_ns - frame_jitter - prefill_time_ns;
305 if (total < 0) {
306 pr_err("invalid total time period time:%llu jiter_time:%llu blanking time:%llu\n",
307 frame_time_ns, frame_jitter, prefill_time_ns);
308 total = 0;
309 }
310
311 total = div_u64(total, cxo_period_ns);
312 rsc->timer_config.static_wakeup_time_ns = total;
313
314 pr_debug("frame time:%llu frame jiter_time:%llu\n",
315 frame_time_ns, frame_jitter);
316 pr_debug("line time:%llu prefill time ps:%llu\n",
317 line_time_ns, prefill_time_ns);
318 pr_debug("static wakeup time:%lld cxo:%u\n", total, cxo_period_ns);
319
320 pdc_backoff_time_ns = rsc_backoff_time_ns;
321 rsc_backoff_time_ns = div_u64(rsc_backoff_time_ns, cxo_period_ns);
322 rsc->timer_config.rsc_backoff_time_ns = (u32) rsc_backoff_time_ns;
323
324 pdc_backoff_time_ns *= pdc_jitter;
325 pdc_backoff_time_ns = div_u64(pdc_backoff_time_ns, 100);
326 rsc->timer_config.pdc_backoff_time_ns = (u32) pdc_backoff_time_ns;
327
328 rsc_mode_threshold_time_ns =
329 div_u64(rsc_mode_threshold_time_ns, cxo_period_ns);
330 rsc->timer_config.rsc_mode_threshold_time_ns
331 = (u32) rsc_mode_threshold_time_ns;
332
333 /* time_slot_0 for mode0 latency */
334 rsc_time_slot_0_ns = div_u64(rsc_time_slot_0_ns, cxo_period_ns);
335 rsc->timer_config.rsc_time_slot_0_ns = (u32) rsc_time_slot_0_ns;
336
337 /* time_slot_1 for mode1 latency */
338 rsc_time_slot_1_ns = frame_time_ns;
339 rsc_time_slot_1_ns = div_u64(rsc_time_slot_1_ns, cxo_period_ns);
340 rsc->timer_config.rsc_time_slot_1_ns = (u32) rsc_time_slot_1_ns;
341
342 /* mode 2 is infinite */
343 rsc->timer_config.rsc_time_slot_2_ns = 0xFFFFFFFF;
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800344
345 if (rsc->hw_ops.init) {
346 ret = rsc->hw_ops.init(rsc);
347 if (ret)
348 pr_err("sde rsc: hw init failed ret:%d\n", ret);
349 }
350
351 return ret;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800352}
353
354static int sde_rsc_switch_to_idle(struct sde_rsc_priv *rsc)
355{
356 struct sde_rsc_client *client;
Dhaval Patela65b0f12017-03-16 00:36:55 -0700357 int rc = STATE_UPDATE_NOT_ALLOWED;
358 bool idle_switch = true;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800359
360 list_for_each_entry(client, &rsc->client_list, list)
Dhaval Patela65b0f12017-03-16 00:36:55 -0700361 if (client->current_state != SDE_RSC_IDLE_STATE) {
362 idle_switch = false;
363 break;
364 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800365
Dhaval Patela65b0f12017-03-16 00:36:55 -0700366 if (!idle_switch) {
367 /**
368 * following code needs to run the loop through each
369 * client because they might be in different order
370 * sorting is not possible; only preference is available
371 */
372
373 /* first check if any vid client active */
374 list_for_each_entry(client, &rsc->client_list, list)
375 if (client->current_state == SDE_RSC_VID_STATE)
376 return rc;
377
378 /* now try cmd state switch */
379 list_for_each_entry(client, &rsc->client_list, list)
380 if (client->current_state == SDE_RSC_CMD_STATE)
381 return TRY_CMD_MODE_SWITCH;
382
383 /* now try clk state switch */
384 list_for_each_entry(client, &rsc->client_list, list)
385 if (client->current_state == SDE_RSC_CLK_STATE)
386 return TRY_CLK_MODE_SWITCH;
387
388 } else if (rsc->hw_ops.state_update) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800389 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_IDLE_STATE);
Dhaval Patel52ec1192017-05-02 23:13:24 -0700390 if (!rc)
391 rpmh_mode_solver_set(rsc->disp_rsc, false);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700392 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800393
394 return rc;
395}
396
Dhaval Patela65b0f12017-03-16 00:36:55 -0700397static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800398 struct sde_rsc_cmd_config *config,
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700399 struct sde_rsc_client *caller_client)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800400{
401 struct sde_rsc_client *client;
Dhaval Patela65b0f12017-03-16 00:36:55 -0700402 int rc = STATE_UPDATE_NOT_ALLOWED;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800403
404 if (!rsc->primary_client) {
405 pr_err("primary client not available for cmd state switch\n");
406 rc = -EINVAL;
407 goto end;
408 } else if (caller_client != rsc->primary_client) {
409 pr_err("primary client state:%d not cmd state request\n",
410 rsc->primary_client->current_state);
411 rc = -EINVAL;
412 goto end;
413 }
414
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800415 /* update timers - might not be available at next switch */
416 if (config)
417 sde_rsc_timer_calculate(rsc, config);
418
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700419 if (rsc->current_state == SDE_RSC_CMD_STATE) {
420 rc = 0;
421 goto vsync_wait;
422 }
423
Dhaval Patel020f7e122016-11-15 14:39:18 -0800424 /* any one client in video state blocks the cmd state switch */
425 list_for_each_entry(client, &rsc->client_list, list)
426 if (client->current_state == SDE_RSC_VID_STATE)
427 goto end;
428
Dhaval Patel52ec1192017-05-02 23:13:24 -0700429 if (rsc->hw_ops.state_update) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800430 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CMD_STATE);
Dhaval Patel52ec1192017-05-02 23:13:24 -0700431 if (!rc)
432 rpmh_mode_solver_set(rsc->disp_rsc, true);
433 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800434
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700435vsync_wait:
436 /* wait for vsync for vid to cmd state switch and config update */
437 if (!rc && (rsc->current_state == SDE_RSC_VID_STATE ||
438 rsc->current_state == SDE_RSC_CMD_STATE))
Dhaval Patel020f7e122016-11-15 14:39:18 -0800439 drm_wait_one_vblank(rsc->master_drm,
440 rsc->primary_client->crtc_id);
441end:
442 return rc;
443}
444
Dhaval Patela65b0f12017-03-16 00:36:55 -0700445static bool sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc)
446{
447 struct sde_rsc_client *client;
448 int rc = STATE_UPDATE_NOT_ALLOWED;
449
450 list_for_each_entry(client, &rsc->client_list, list)
451 if ((client->current_state == SDE_RSC_VID_STATE) ||
452 (client->current_state == SDE_RSC_CMD_STATE))
453 goto end;
454
Dhaval Patel52ec1192017-05-02 23:13:24 -0700455 if (rsc->hw_ops.state_update) {
Dhaval Patelfbb11f02017-04-06 13:43:28 -0700456 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CLK_STATE);
Dhaval Patel52ec1192017-05-02 23:13:24 -0700457 if (!rc)
458 rpmh_mode_solver_set(rsc->disp_rsc, false);
459 }
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700460
461 /* wait for vsync for cmd to clk state switch */
462 if (!rc && rsc->primary_client &&
463 (rsc->current_state == SDE_RSC_CMD_STATE))
464 drm_wait_one_vblank(rsc->master_drm,
465 rsc->primary_client->crtc_id);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700466end:
467 return rc;
468}
469
Dhaval Patel020f7e122016-11-15 14:39:18 -0800470static bool sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800471 struct sde_rsc_cmd_config *config,
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700472 struct sde_rsc_client *caller_client)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800473{
474 int rc = 0;
475
476 /* update timers - might not be available at next switch */
477 if (config && (caller_client == rsc->primary_client))
478 sde_rsc_timer_calculate(rsc, config);
479
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700480 /* early exit without vsync wait for vid state */
481 if (rsc->current_state == SDE_RSC_VID_STATE)
482 goto end;
483
Dhaval Patel020f7e122016-11-15 14:39:18 -0800484 /* video state switch should be done immediately */
Dhaval Patel52ec1192017-05-02 23:13:24 -0700485 if (rsc->hw_ops.state_update) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800486 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE);
Dhaval Patel52ec1192017-05-02 23:13:24 -0700487 if (!rc)
488 rpmh_mode_solver_set(rsc->disp_rsc, false);
489 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800490
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700491 /* wait for vsync for cmd to vid state switch */
492 if (!rc && rsc->primary_client &&
493 (rsc->current_state == SDE_RSC_CMD_STATE))
Dhaval Patel020f7e122016-11-15 14:39:18 -0800494 drm_wait_one_vblank(rsc->master_drm,
495 rsc->primary_client->crtc_id);
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700496
497end:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800498 return rc;
499}
500
501/**
502 * sde_rsc_client_state_update() - rsc client state update
Dhaval Patela65b0f12017-03-16 00:36:55 -0700503 * Video mode, cmd mode and clk state are suppoed as modes. A client need to
Dhaval Patel020f7e122016-11-15 14:39:18 -0800504 * set this property during panel config time. A switching client can set the
505 * property to change the state
506 *
507 * @client: Client pointer provided by sde_rsc_client_create().
508 * @state: Client state - video/cmd
509 * @config: fps, vtotal, porches, etc configuration for command mode
510 * panel
511 * @crtc_id: current client's crtc id
512 *
513 * Return: error code.
514 */
515int sde_rsc_client_state_update(struct sde_rsc_client *caller_client,
516 enum sde_rsc_state state,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800517 struct sde_rsc_cmd_config *config, int crtc_id)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800518{
519 int rc = 0;
520 struct sde_rsc_priv *rsc;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800521
522 if (!caller_client) {
523 pr_err("invalid client for rsc state update\n");
524 return -EINVAL;
525 } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
526 pr_err("invalid rsc index\n");
527 return -EINVAL;
528 }
529
530 rsc = rsc_prv_list[caller_client->rsc_index];
531 if (!rsc)
532 return -EINVAL;
533
534 mutex_lock(&rsc->client_lock);
Dhaval Patel824e9682017-05-01 23:31:22 -0700535 SDE_EVT32(caller_client->id, caller_client->current_state,
536 state, rsc->current_state, SDE_EVTLOG_FUNC_ENTRY);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800537 caller_client->crtc_id = crtc_id;
538 caller_client->current_state = state;
539
540 if (rsc->master_drm == NULL) {
541 pr_err("invalid master component binding\n");
542 rc = -EINVAL;
543 goto end;
Dhaval Patela65b0f12017-03-16 00:36:55 -0700544 } else if ((rsc->current_state == state) && !config) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800545 pr_debug("no state change: %d\n", state);
546 goto end;
547 }
548
549 pr_debug("%pS: rsc state:%d request client:%s state:%d\n",
550 __builtin_return_address(0), rsc->current_state,
551 caller_client->name, state);
552
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700553 if (rsc->current_state == SDE_RSC_IDLE_STATE)
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700554 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800555
556 switch (state) {
557 case SDE_RSC_IDLE_STATE:
558 rc = sde_rsc_switch_to_idle(rsc);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700559
Dhaval Patel020f7e122016-11-15 14:39:18 -0800560 /* video state client might be exiting; try cmd state switch */
Dhaval Patela65b0f12017-03-16 00:36:55 -0700561 if (rc == TRY_CMD_MODE_SWITCH) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800562 rc = sde_rsc_switch_to_cmd(rsc, NULL,
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700563 rsc->primary_client);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700564 if (!rc)
565 state = SDE_RSC_CMD_STATE;
566
567 /* cmd state client might be exiting; try clk state switch */
568 } else if (rc == TRY_CLK_MODE_SWITCH) {
569 rc = sde_rsc_switch_to_clk(rsc);
570 if (!rc)
571 state = SDE_RSC_CLK_STATE;
572 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800573 break;
574
575 case SDE_RSC_CMD_STATE:
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700576 rc = sde_rsc_switch_to_cmd(rsc, config, caller_client);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800577 break;
578
579 case SDE_RSC_VID_STATE:
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700580 rc = sde_rsc_switch_to_vid(rsc, config, caller_client);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800581 break;
582
Dhaval Patela65b0f12017-03-16 00:36:55 -0700583 case SDE_RSC_CLK_STATE:
584 rc = sde_rsc_switch_to_clk(rsc);
585 break;
586
Dhaval Patel020f7e122016-11-15 14:39:18 -0800587 default:
588 pr_err("invalid state handling %d\n", state);
589 break;
590 }
591
Dhaval Patela65b0f12017-03-16 00:36:55 -0700592 if (rc == STATE_UPDATE_NOT_ALLOWED) {
593 rc = 0;
Dhaval Patel824e9682017-05-01 23:31:22 -0700594 SDE_EVT32(caller_client->id, caller_client->current_state,
595 state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE1);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700596 goto clk_disable;
597 } else if (rc) {
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700598 pr_debug("state:%d update failed rc:%d\n", state, rc);
Dhaval Patel824e9682017-05-01 23:31:22 -0700599 SDE_EVT32(caller_client->id, caller_client->current_state,
600 state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE2);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700601 goto clk_disable;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800602 }
603
604 pr_debug("state switch successfully complete: %d\n", state);
605 rsc->current_state = state;
Dhaval Patel824e9682017-05-01 23:31:22 -0700606 SDE_EVT32(caller_client->id, caller_client->current_state,
607 state, rsc->current_state, SDE_EVTLOG_FUNC_EXIT);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800608
Dhaval Patela65b0f12017-03-16 00:36:55 -0700609clk_disable:
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700610 if (rsc->current_state == SDE_RSC_IDLE_STATE)
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700611 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800612end:
613 mutex_unlock(&rsc->client_lock);
614 return rc;
615}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700616EXPORT_SYMBOL(sde_rsc_client_state_update);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800617
618/**
619 * sde_rsc_client_vote() - ab/ib vote from rsc client
620 *
621 * @client: Client pointer provided by sde_rsc_client_create().
622 * @ab: aggregated bandwidth vote from client.
623 * @ib: instant bandwidth vote from client.
624 *
625 * Return: error code.
626 */
627int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
Dhaval Patel4d424602017-02-18 19:40:14 -0800628 u64 ab_vote, u64 ib_vote)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800629{
630 int rc = 0;
631 struct sde_rsc_priv *rsc;
632 bool amc_mode = false;
633 enum rpmh_state state;
634
635 if (!caller_client) {
636 pr_err("invalid client for ab/ib vote\n");
637 return -EINVAL;
638 } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
639 pr_err("invalid rsc index\n");
640 return -EINVAL;
641 }
642
643 rsc = rsc_prv_list[caller_client->rsc_index];
644 if (!rsc)
645 return -EINVAL;
646
647 if (caller_client != rsc->primary_client) {
648 pr_err("only primary client can use sde rsc:: curr client name:%s\n",
649 caller_client->name);
650 return -EINVAL;
651 }
652 pr_debug("client:%s ab:%llu ib:%llu\n",
653 caller_client->name, ab_vote, ib_vote);
654
655 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700656 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
657 if (rc)
658 goto clk_enable_fail;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800659
660 if (rsc->hw_ops.is_amc_mode)
661 amc_mode = rsc->hw_ops.is_amc_mode(rsc);
662
663 if (rsc->current_state == SDE_RSC_CMD_STATE)
Dhaval Patel4d424602017-02-18 19:40:14 -0800664 state = RPMH_WAKE_ONLY_STATE;
665 else if (amc_mode)
666 state = RPMH_ACTIVE_ONLY_STATE;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800667 else
Dhaval Patel4d424602017-02-18 19:40:14 -0800668 state = RPMH_AWAKE_STATE;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800669
670 if (rsc->hw_ops.tcs_wait) {
671 rc = rsc->hw_ops.tcs_wait(rsc);
672 if (rc) {
673 pr_err("tcs is still busy; can't send command\n");
674 if (rsc->hw_ops.tcs_use_ok)
675 rsc->hw_ops.tcs_use_ok(rsc);
676 goto end;
677 }
678 }
679
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700680 rpmh_invalidate(rsc->disp_rsc);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800681 sde_power_data_bus_set_quota(&rsc->phandle, rsc->pclient,
682 SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, ab_vote, ib_vote);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700683 rpmh_flush(rsc->disp_rsc);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800684
685 if (rsc->hw_ops.tcs_use_ok)
686 rsc->hw_ops.tcs_use_ok(rsc);
687
688end:
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700689 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
690clk_enable_fail:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800691 mutex_unlock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700692
Dhaval Patel020f7e122016-11-15 14:39:18 -0800693 return rc;
694}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700695EXPORT_SYMBOL(sde_rsc_client_vote);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800696
697static int _sde_debugfs_status_show(struct seq_file *s, void *data)
698{
699 struct sde_rsc_priv *rsc;
700 struct sde_rsc_client *client;
701 int ret;
702
703 if (!s || !s->private)
704 return -EINVAL;
705
706 rsc = s->private;
707
708 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700709 ret = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
710 if (ret)
711 goto end;
712
Dhaval Patel020f7e122016-11-15 14:39:18 -0800713 seq_printf(s, "rsc current state:%d\n", rsc->current_state);
714 seq_printf(s, "wraper backoff time(ns):%d\n",
715 rsc->timer_config.static_wakeup_time_ns);
716 seq_printf(s, "rsc backoff time(ns):%d\n",
717 rsc->timer_config.rsc_backoff_time_ns);
718 seq_printf(s, "pdc backoff time(ns):%d\n",
719 rsc->timer_config.pdc_backoff_time_ns);
720 seq_printf(s, "rsc mode threshold time(ns):%d\n",
721 rsc->timer_config.rsc_mode_threshold_time_ns);
722 seq_printf(s, "rsc time slot 0(ns):%d\n",
723 rsc->timer_config.rsc_time_slot_0_ns);
724 seq_printf(s, "rsc time slot 1(ns):%d\n",
725 rsc->timer_config.rsc_time_slot_1_ns);
726 seq_printf(s, "frame fps:%d jitter:%d vtotal:%d prefill lines:%d\n",
727 rsc->cmd_config.fps, rsc->cmd_config.jitter,
728 rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines);
729
730 seq_puts(s, "\n");
731
732 list_for_each_entry(client, &rsc->client_list, list)
733 seq_printf(s, "\t client:%s state:%d\n",
734 client->name, client->current_state);
735
Dhaval Patel020f7e122016-11-15 14:39:18 -0800736 if (rsc->hw_ops.debug_show) {
737 ret = rsc->hw_ops.debug_show(s, rsc);
738 if (ret)
739 pr_err("sde rsc: hw debug failed ret:%d\n", ret);
740 }
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700741 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800742
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700743end:
744 mutex_unlock(&rsc->client_lock);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800745 return 0;
746}
747
748static int _sde_debugfs_status_open(struct inode *inode, struct file *file)
749{
750 return single_open(file, _sde_debugfs_status_show, inode->i_private);
751}
752
753static int _sde_debugfs_mode_ctrl_open(struct inode *inode, struct file *file)
754{
755 /* non-seekable */
756 file->private_data = inode->i_private;
757 return nonseekable_open(inode, file);
758}
759
760static ssize_t _sde_debugfs_mode_ctrl_read(struct file *file, char __user *buf,
761 size_t count, loff_t *ppos)
762{
763 struct sde_rsc_priv *rsc = file->private_data;
764 char buffer[MAX_BUFFER_SIZE];
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700765 int blen = 0, rc;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800766
767 if (*ppos || !rsc || !rsc->hw_ops.mode_ctrl)
768 return 0;
769
770 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700771 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
772 if (rc)
773 goto end;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800774
775 blen = rsc->hw_ops.mode_ctrl(rsc, MODE_READ, buffer,
776 MAX_BUFFER_SIZE, 0);
777
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700778 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800779
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700780end:
781 mutex_unlock(&rsc->client_lock);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800782 if (blen < 0)
783 return 0;
784
785 if (copy_to_user(buf, buffer, blen))
786 return -EFAULT;
787
788 *ppos += blen;
789 return blen;
790}
791
792static ssize_t _sde_debugfs_mode_ctrl_write(struct file *file,
793 const char __user *p, size_t count, loff_t *ppos)
794{
795 struct sde_rsc_priv *rsc = file->private_data;
Dhaval Patel3d56f892017-05-05 12:21:08 -0700796 char *input;
797 u32 mode_state = 0;
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700798 int rc;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800799
Dhaval Patel3d56f892017-05-05 12:21:08 -0700800 if (!rsc || !rsc->hw_ops.mode_ctrl || !count ||
801 count > MAX_COUNT_SIZE_SUPPORTED)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800802 return 0;
803
Dhaval Patel3d56f892017-05-05 12:21:08 -0700804 input = kmalloc(count + 1, GFP_KERNEL);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800805 if (!input)
806 return -ENOMEM;
807
808 if (copy_from_user(input, p, count)) {
809 kfree(input);
810 return -EFAULT;
811 }
Dhaval Patel3d56f892017-05-05 12:21:08 -0700812 input[count] = '\0';
813
814 rc = kstrtoint(input, 0, &mode_state);
815 if (rc) {
816 pr_err("mode_state: int conversion failed rc:%d\n", rc);
817 goto end;
818 }
819
820 pr_debug("mode_state: %d\n", mode_state);
821 mode_state &= 0x7;
822 if (mode_state != ALL_MODES_DISABLED &&
823 mode_state != ALL_MODES_ENABLED &&
824 mode_state != ONLY_MODE_0_ENABLED &&
825 mode_state != ONLY_MODE_0_1_ENABLED) {
826 pr_err("invalid mode:%d combination\n", mode_state);
827 goto end;
828 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800829
830 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700831 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
832 if (rc)
833 goto clk_enable_fail;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800834
Dhaval Patel3d56f892017-05-05 12:21:08 -0700835 rsc->hw_ops.mode_ctrl(rsc, MODE_UPDATE, NULL, 0, mode_state);
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700836 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel3d56f892017-05-05 12:21:08 -0700837
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700838clk_enable_fail:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800839 mutex_unlock(&rsc->client_lock);
Dhaval Patel3d56f892017-05-05 12:21:08 -0700840end:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800841 kfree(input);
842 return count;
843}
844
845static int _sde_debugfs_vsync_mode_open(struct inode *inode, struct file *file)
846{
847 /* non-seekable */
848 file->private_data = inode->i_private;
849 return nonseekable_open(inode, file);
850}
851
852static ssize_t _sde_debugfs_vsync_mode_read(struct file *file, char __user *buf,
853 size_t count, loff_t *ppos)
854{
855 struct sde_rsc_priv *rsc = file->private_data;
856 char buffer[MAX_BUFFER_SIZE];
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700857 int blen = 0, rc;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800858
859 if (*ppos || !rsc || !rsc->hw_ops.hw_vsync)
860 return 0;
861
862 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700863 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
864 if (rc)
865 goto end;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800866
867 blen = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ, buffer,
868 MAX_BUFFER_SIZE, 0);
869
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700870 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800871
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700872end:
873 mutex_unlock(&rsc->client_lock);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800874 if (blen < 0)
875 return 0;
876
877 if (copy_to_user(buf, buffer, blen))
878 return -EFAULT;
879
880 *ppos += blen;
881 return blen;
882}
883
884static ssize_t _sde_debugfs_vsync_mode_write(struct file *file,
885 const char __user *p, size_t count, loff_t *ppos)
886{
887 struct sde_rsc_priv *rsc = file->private_data;
Dhaval Patel3d56f892017-05-05 12:21:08 -0700888 char *input;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800889 u32 vsync_state = 0;
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700890 int rc;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800891
Dhaval Patel3d56f892017-05-05 12:21:08 -0700892 if (!rsc || !rsc->hw_ops.hw_vsync || !count ||
893 count > MAX_COUNT_SIZE_SUPPORTED)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800894 return 0;
895
Dhaval Patel3d56f892017-05-05 12:21:08 -0700896 input = kmalloc(count + 1, GFP_KERNEL);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800897 if (!input)
898 return -ENOMEM;
899
900 if (copy_from_user(input, p, count)) {
901 kfree(input);
902 return -EFAULT;
903 }
Dhaval Patel3d56f892017-05-05 12:21:08 -0700904 input[count] = '\0';
Dhaval Patel020f7e122016-11-15 14:39:18 -0800905
Dhaval Patel3d56f892017-05-05 12:21:08 -0700906 rc = kstrtoint(input, 0, &vsync_state);
907 if (rc) {
908 pr_err("vsync_state: int conversion failed rc:%d\n", rc);
909 goto end;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800910 }
911
Dhaval Patel3d56f892017-05-05 12:21:08 -0700912 pr_debug("vsync_state: %d\n", vsync_state);
913 vsync_state &= 0x7;
914
Dhaval Patel020f7e122016-11-15 14:39:18 -0800915 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700916 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
917 if (rc)
Dhaval Patel3d56f892017-05-05 12:21:08 -0700918 goto clk_en_fail;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800919
920 if (vsync_state)
921 rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL,
922 0, vsync_state - 1);
923 else
924 rsc->hw_ops.hw_vsync(rsc, VSYNC_DISABLE, NULL, 0, 0);
925
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700926 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800927
Dhaval Patel3d56f892017-05-05 12:21:08 -0700928clk_en_fail:
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700929 mutex_unlock(&rsc->client_lock);
Dhaval Patel3d56f892017-05-05 12:21:08 -0700930end:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800931 kfree(input);
932 return count;
933}
934
935static const struct file_operations debugfs_status_fops = {
936 .open = _sde_debugfs_status_open,
937 .read = seq_read,
938 .llseek = seq_lseek,
939 .release = single_release,
940};
941
942static const struct file_operations mode_control_fops = {
943 .open = _sde_debugfs_mode_ctrl_open,
944 .read = _sde_debugfs_mode_ctrl_read,
945 .write = _sde_debugfs_mode_ctrl_write,
946};
947
948static const struct file_operations vsync_status_fops = {
949 .open = _sde_debugfs_vsync_mode_open,
950 .read = _sde_debugfs_vsync_mode_read,
951 .write = _sde_debugfs_vsync_mode_write,
952};
953
954static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name)
955{
956 rsc->debugfs_root = debugfs_create_dir(name, NULL);
957 if (!rsc->debugfs_root)
958 return;
959
960 /* don't error check these */
961 debugfs_create_file("status", 0444, rsc->debugfs_root, rsc,
962 &debugfs_status_fops);
963 debugfs_create_file("mode_control", 0644, rsc->debugfs_root, rsc,
964 &mode_control_fops);
965 debugfs_create_file("vsync_mode", 0644, rsc->debugfs_root, rsc,
966 &vsync_status_fops);
967 debugfs_create_x32("debug_mode", 0644, rsc->debugfs_root,
968 &rsc->debug_mode);
969}
970
971static void sde_rsc_deinit(struct platform_device *pdev,
972 struct sde_rsc_priv *rsc)
973{
974 if (!rsc)
975 return;
976
977 if (rsc->pclient)
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700978 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800979 if (rsc->fs)
980 devm_regulator_put(rsc->fs);
981 if (rsc->wrapper_io.base)
982 msm_dss_iounmap(&rsc->wrapper_io);
983 if (rsc->drv_io.base)
984 msm_dss_iounmap(&rsc->drv_io);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700985 if (rsc->disp_rsc)
986 rpmh_release(rsc->disp_rsc);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800987 if (rsc->pclient)
988 sde_power_client_destroy(&rsc->phandle, rsc->pclient);
989
990 sde_power_resource_deinit(pdev, &rsc->phandle);
991 debugfs_remove_recursive(rsc->debugfs_root);
992 kfree(rsc);
993}
994
995/**
996 * sde_rsc_bind - bind rsc device with controlling device
997 * @dev: Pointer to base of platform device
998 * @master: Pointer to container of drm device
999 * @data: Pointer to private data
1000 * Returns: Zero on success
1001 */
1002static int sde_rsc_bind(struct device *dev,
1003 struct device *master,
1004 void *data)
1005{
1006 struct sde_rsc_priv *rsc;
1007 struct drm_device *drm;
1008 struct platform_device *pdev = to_platform_device(dev);
1009
1010 if (!dev || !pdev || !master) {
1011 pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
1012 dev, pdev, master);
1013 return -EINVAL;
1014 }
1015
1016 drm = dev_get_drvdata(master);
1017 rsc = platform_get_drvdata(pdev);
1018 if (!drm || !rsc) {
1019 pr_err("invalid param(s), drm %pK, rsc %pK\n",
1020 drm, rsc);
1021 return -EINVAL;
1022 }
1023
1024 mutex_lock(&rsc->client_lock);
1025 rsc->master_drm = drm;
1026 mutex_unlock(&rsc->client_lock);
1027
1028 return 0;
1029}
1030
1031/**
1032 * sde_rsc_unbind - unbind rsc from controlling device
1033 * @dev: Pointer to base of platform device
1034 * @master: Pointer to container of drm device
1035 * @data: Pointer to private data
1036 */
1037static void sde_rsc_unbind(struct device *dev,
1038 struct device *master, void *data)
1039{
1040 struct sde_rsc_priv *rsc;
1041 struct platform_device *pdev = to_platform_device(dev);
1042
1043 if (!dev || !pdev) {
1044 pr_err("invalid param(s)\n");
1045 return;
1046 }
1047
1048 rsc = platform_get_drvdata(pdev);
1049 if (!rsc) {
1050 pr_err("invalid display rsc\n");
1051 return;
1052 }
1053
1054 mutex_lock(&rsc->client_lock);
1055 rsc->master_drm = NULL;
1056 mutex_unlock(&rsc->client_lock);
1057}
1058
1059static const struct component_ops sde_rsc_comp_ops = {
1060 .bind = sde_rsc_bind,
1061 .unbind = sde_rsc_unbind,
1062};
1063
1064static int sde_rsc_probe(struct platform_device *pdev)
1065{
1066 int ret;
1067 struct sde_rsc_priv *rsc;
1068 static int counter;
1069 char name[MAX_RSC_CLIENT_NAME_LEN];
1070
1071 rsc = kzalloc(sizeof(*rsc), GFP_KERNEL);
1072 if (!rsc) {
1073 ret = -ENOMEM;
1074 goto rsc_alloc_fail;
1075 }
1076
1077 platform_set_drvdata(pdev, rsc);
1078 of_property_read_u32(pdev->dev.of_node, "qcom,sde-rsc-version",
1079 &rsc->version);
1080
1081 ret = sde_power_resource_init(pdev, &rsc->phandle);
1082 if (ret) {
1083 pr_err("sde rsc:power resource init failed ret:%d\n", ret);
1084 goto sde_rsc_fail;
1085 }
1086
1087 rsc->pclient = sde_power_client_create(&rsc->phandle, "rsc");
1088 if (IS_ERR_OR_NULL(rsc->pclient)) {
1089 ret = PTR_ERR(rsc->pclient);
1090 rsc->pclient = NULL;
1091 pr_err("sde rsc:power client create failed ret:%d\n", ret);
1092 goto sde_rsc_fail;
1093 }
1094
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001095 rsc->disp_rsc = rpmh_get_byname(pdev, "disp_rsc");
1096 if (IS_ERR_OR_NULL(rsc->disp_rsc)) {
1097 ret = PTR_ERR(rsc->disp_rsc);
1098 rsc->disp_rsc = NULL;
1099 pr_err("sde rsc:get display rsc failed ret:%d\n", ret);
1100 goto sde_rsc_fail;
1101 }
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001102
Dhaval Patel020f7e122016-11-15 14:39:18 -08001103 ret = msm_dss_ioremap_byname(pdev, &rsc->wrapper_io, "wrapper");
1104 if (ret) {
1105 pr_err("sde rsc: wrapper io data mapping failed ret=%d\n", ret);
1106 goto sde_rsc_fail;
1107 }
1108
1109 ret = msm_dss_ioremap_byname(pdev, &rsc->drv_io, "drv");
1110 if (ret) {
1111 pr_err("sde rsc: drv io data mapping failed ret:%d\n", ret);
1112 goto sde_rsc_fail;
1113 }
1114
1115 rsc->fs = devm_regulator_get(&pdev->dev, "vdd");
1116 if (IS_ERR_OR_NULL(rsc->fs)) {
1117 rsc->fs = NULL;
1118 pr_err("unable to get regulator\n");
1119 goto sde_rsc_fail;
1120 }
1121
1122 ret = sde_rsc_hw_register(rsc);
1123 if (ret) {
1124 pr_err("sde rsc: hw register failed ret:%d\n", ret);
1125 goto sde_rsc_fail;
1126 }
1127
Dhaval Patelfcd9e912017-03-16 00:54:09 -07001128 if (sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true)) {
Dhaval Patel020f7e122016-11-15 14:39:18 -08001129 pr_err("failed to enable sde rsc power resources\n");
1130 goto sde_rsc_fail;
1131 }
1132
Dhaval Patel82c8dbc2017-02-18 23:15:10 -08001133 if (sde_rsc_timer_calculate(rsc, NULL))
1134 goto sde_rsc_fail;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001135
Dhaval Patelfcd9e912017-03-16 00:54:09 -07001136 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
1137
Dhaval Patel020f7e122016-11-15 14:39:18 -08001138 INIT_LIST_HEAD(&rsc->client_list);
Dhaval Patelfbb11f02017-04-06 13:43:28 -07001139 INIT_LIST_HEAD(&rsc->event_list);
Dhaval Patel020f7e122016-11-15 14:39:18 -08001140 mutex_init(&rsc->client_lock);
1141
1142 pr_info("sde rsc index:%d probed successfully\n",
1143 SDE_RSC_INDEX + counter);
1144
1145 rsc_prv_list[SDE_RSC_INDEX + counter] = rsc;
1146 snprintf(name, MAX_RSC_CLIENT_NAME_LEN, "%s%d", "sde_rsc", counter);
1147 _sde_rsc_init_debugfs(rsc, name);
1148 counter++;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001149
1150 ret = component_add(&pdev->dev, &sde_rsc_comp_ops);
1151 if (ret)
1152 pr_debug("component add failed, ret=%d\n", ret);
1153 ret = 0;
1154
1155 return ret;
1156
1157sde_rsc_fail:
1158 sde_rsc_deinit(pdev, rsc);
1159rsc_alloc_fail:
1160 return ret;
1161}
1162
1163static int sde_rsc_remove(struct platform_device *pdev)
1164{
1165 struct sde_rsc_priv *rsc = platform_get_drvdata(pdev);
1166
1167 sde_rsc_deinit(pdev, rsc);
1168 return 0;
1169}
1170
1171static const struct of_device_id dt_match[] = {
1172 { .compatible = "qcom,sde-rsc"},
1173 {}
1174};
1175
1176MODULE_DEVICE_TABLE(of, dt_match);
1177
1178static struct platform_driver sde_rsc_platform_driver = {
1179 .probe = sde_rsc_probe,
1180 .remove = sde_rsc_remove,
1181 .driver = {
1182 .name = "sde_rsc",
1183 .of_match_table = dt_match,
1184 },
1185};
1186
1187static int __init sde_rsc_register(void)
1188{
1189 return platform_driver_register(&sde_rsc_platform_driver);
1190}
1191
1192static void __exit sde_rsc_unregister(void)
1193{
1194 platform_driver_unregister(&sde_rsc_platform_driver);
1195}
1196
1197module_init(sde_rsc_register);
1198module_exit(sde_rsc_unregister);