blob: 82b1199c0b1d7d5c70fbdc9bfebc59ae080d3cd4 [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 Patela2430842017-06-15 14:32:36 -070033#define SDE_RSC_DRV_DBG_NAME "sde_rsc_drv"
34#define SDE_RSC_WRAPPER_DBG_NAME "sde_rsc_wrapper"
35
Dhaval Patelc063d1f2017-06-08 13:19:26 -070036/* worst case time to execute the one tcs vote(sleep/wake) - ~1ms */
37#define SINGLE_TCS_EXECUTION_TIME 1064000
Dhaval Patel020f7e122016-11-15 14:39:18 -080038
Dhaval Patel824e9682017-05-01 23:31:22 -070039/* this time is ~1ms - only wake tcs in any mode */
Dhaval Patel9e3bfe42017-05-25 22:32:55 -070040#define RSC_BACKOFF_TIME_NS (SINGLE_TCS_EXECUTION_TIME + 100)
Dhaval Patel020f7e122016-11-15 14:39:18 -080041
Dhaval Patel824e9682017-05-01 23:31:22 -070042/* this time is ~1ms - only wake TCS in mode-0 */
Dhaval Patelc063d1f2017-06-08 13:19:26 -070043#define RSC_MODE_THRESHOLD_TIME_IN_NS (SINGLE_TCS_EXECUTION_TIME + 100)
Dhaval Patel824e9682017-05-01 23:31:22 -070044
45/* this time is ~2ms - sleep+ wake TCS in mode-1 */
Dhaval Patel9e3bfe42017-05-25 22:32:55 -070046#define RSC_TIME_SLOT_0_NS ((SINGLE_TCS_EXECUTION_TIME * 2) + 100)
Dhaval Patel020f7e122016-11-15 14:39:18 -080047
48#define DEFAULT_PANEL_FPS 60
Dhaval Patelf5cc5a32017-07-10 17:33:23 -070049#define DEFAULT_PANEL_JITTER_NUMERATOR 2
50#define DEFAULT_PANEL_JITTER_DENOMINATOR 1
51#define DEFAULT_PANEL_PREFILL_LINES 25
Dhaval Patel020f7e122016-11-15 14:39:18 -080052#define DEFAULT_PANEL_VTOTAL (480 + DEFAULT_PANEL_PREFILL_LINES)
53#define TICKS_IN_NANO_SECOND 1000000000
54
55#define MAX_BUFFER_SIZE 256
56
57#define TRY_CMD_MODE_SWITCH 0xFFFF
Dhaval Patela65b0f12017-03-16 00:36:55 -070058#define TRY_CLK_MODE_SWITCH 0xFFFE
59#define STATE_UPDATE_NOT_ALLOWED 0xFFFD
Dhaval Patel020f7e122016-11-15 14:39:18 -080060
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -040061/* Primary panel worst case VSYNC expected to be no less than 30fps */
62#define PRIMARY_VBLANK_WORST_CASE_MS 34
Lloyd Atkinson16147ea2017-07-17 10:16:30 -040063
Dhaval Patel020f7e122016-11-15 14:39:18 -080064static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT];
65
66/**
67 * sde_rsc_client_create() - create the client for sde rsc.
68 * Different displays like DSI, HDMI, DP, WB, etc should call this
69 * api to register their vote for rpmh. They still need to vote for
70 * power handle to get the clocks.
71
72 * @rsc_index: A client will be created on this RSC. As of now only
73 * SDE_RSC_INDEX is valid rsc index.
74 * @name: Caller needs to provide some valid string to identify
75 * the client. "primary", "dp", "hdmi" are suggested name.
76 * @is_primary: Caller needs to provide information if client is primary
77 * or not. Primary client votes will be redirected to
78 * display rsc.
79 *
80 * Return: client node pointer.
81 */
82struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *client_name,
83 bool is_primary_client)
84{
85 struct sde_rsc_client *client;
86 struct sde_rsc_priv *rsc;
Dhaval Patel824e9682017-05-01 23:31:22 -070087 static int id;
Dhaval Patel020f7e122016-11-15 14:39:18 -080088
89 if (!client_name) {
90 pr_err("client name is null- not supported\n");
91 return ERR_PTR(-EINVAL);
92 } else if (rsc_index >= MAX_RSC_COUNT) {
93 pr_err("invalid rsc index\n");
94 return ERR_PTR(-EINVAL);
95 } else if (!rsc_prv_list[rsc_index]) {
96 pr_err("rsc not probed yet or not available\n");
Dhaval Patel824e9682017-05-01 23:31:22 -070097 return NULL;
Dhaval Patel020f7e122016-11-15 14:39:18 -080098 }
99
100 rsc = rsc_prv_list[rsc_index];
101 client = kzalloc(sizeof(struct sde_rsc_client), GFP_KERNEL);
102 if (!client)
103 return ERR_PTR(-ENOMEM);
104
105 mutex_lock(&rsc->client_lock);
106 strlcpy(client->name, client_name, MAX_RSC_CLIENT_NAME_LEN);
107 client->current_state = SDE_RSC_IDLE_STATE;
108 client->rsc_index = rsc_index;
Dhaval Patel824e9682017-05-01 23:31:22 -0700109 client->id = id;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800110 if (is_primary_client)
111 rsc->primary_client = client;
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800112 pr_debug("client %s rsc index:%d primary:%d\n", client_name,
113 rsc_index, is_primary_client);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800114
115 list_add(&client->list, &rsc->client_list);
Dhaval Patel824e9682017-05-01 23:31:22 -0700116 id++;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800117 mutex_unlock(&rsc->client_lock);
118
119 return client;
120}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700121EXPORT_SYMBOL(sde_rsc_client_create);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800122
123/**
124 * sde_rsc_client_destroy() - Destroy the sde rsc client.
125 *
126 * @client: Client pointer provided by sde_rsc_client_create().
127 *
128 * Return: none
129 */
130void sde_rsc_client_destroy(struct sde_rsc_client *client)
131{
132 struct sde_rsc_priv *rsc;
Dhaval Patelbd8bbfe2017-05-22 10:55:37 -0700133 enum sde_rsc_state state;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800134
135 if (!client) {
136 pr_debug("invalid client\n");
137 goto end;
138 } else if (client->rsc_index >= MAX_RSC_COUNT) {
139 pr_err("invalid rsc index\n");
140 goto end;
141 }
142
143 pr_debug("client %s destroyed\n", client->name);
144 rsc = rsc_prv_list[client->rsc_index];
145 if (!rsc)
146 goto end;
147
148 mutex_lock(&rsc->client_lock);
Dhaval Patelbd8bbfe2017-05-22 10:55:37 -0700149 state = client->current_state;
150 mutex_unlock(&rsc->client_lock);
151
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400152 if (state != SDE_RSC_IDLE_STATE) {
153 int wait_vblank_crtc_id;
154
155 sde_rsc_client_state_update(client, SDE_RSC_IDLE_STATE, NULL,
156 SDE_RSC_INVALID_CRTC_ID, &wait_vblank_crtc_id);
157
158 /* if vblank wait required at shutdown, use a simple sleep */
159 if (wait_vblank_crtc_id != SDE_RSC_INVALID_CRTC_ID) {
160 pr_err("unexpected sleep required on crtc %d at rsc client destroy\n",
161 wait_vblank_crtc_id);
162 SDE_EVT32(client->id, state, rsc->current_state,
163 client->crtc_id, wait_vblank_crtc_id,
164 SDE_EVTLOG_ERROR);
165 msleep(PRIMARY_VBLANK_WORST_CASE_MS);
166 }
167 }
Dhaval Patelbd8bbfe2017-05-22 10:55:37 -0700168 mutex_lock(&rsc->client_lock);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800169 list_del_init(&client->list);
170 mutex_unlock(&rsc->client_lock);
171
172 kfree(client);
173end:
174 return;
175}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700176EXPORT_SYMBOL(sde_rsc_client_destroy);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800177
Dhaval Patel031b4152017-03-16 13:03:18 -0700178struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
179 void (*cb_func)(uint32_t event_type, void *usr), void *usr)
180{
181 struct sde_rsc_event *evt;
182 struct sde_rsc_priv *rsc;
183
184 if (rsc_index >= MAX_RSC_COUNT) {
185 pr_err("invalid rsc index:%d\n", rsc_index);
186 return ERR_PTR(-EINVAL);
187 } else if (!rsc_prv_list[rsc_index]) {
188 pr_err("rsc idx:%d not probed yet or not available\n",
189 rsc_index);
190 return ERR_PTR(-EINVAL);
191 } else if (!cb_func || !event_type) {
192 pr_err("no event or cb func\n");
193 return ERR_PTR(-EINVAL);
194 }
195
196 rsc = rsc_prv_list[rsc_index];
197 evt = kzalloc(sizeof(struct sde_rsc_event), GFP_KERNEL);
198 if (!evt)
199 return ERR_PTR(-ENOMEM);
200
201 evt->event_type = event_type;
202 evt->rsc_index = rsc_index;
203 evt->usr = usr;
204 evt->cb_func = cb_func;
205 pr_debug("event register type:%d rsc index:%d\n",
206 event_type, rsc_index);
207
208 mutex_lock(&rsc->client_lock);
209 list_add(&evt->list, &rsc->event_list);
210 mutex_unlock(&rsc->client_lock);
211
212 return evt;
213}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700214EXPORT_SYMBOL(sde_rsc_register_event);
Dhaval Patel031b4152017-03-16 13:03:18 -0700215
216void sde_rsc_unregister_event(struct sde_rsc_event *event)
217{
218 struct sde_rsc_priv *rsc;
219
220 if (!event) {
221 pr_debug("invalid event client\n");
222 goto end;
223 } else if (event->rsc_index >= MAX_RSC_COUNT) {
224 pr_err("invalid rsc index\n");
225 goto end;
226 }
227
228 pr_debug("event client destroyed\n");
229 rsc = rsc_prv_list[event->rsc_index];
230 if (!rsc)
231 goto end;
232
233 mutex_lock(&rsc->client_lock);
234 list_del_init(&event->list);
235 mutex_unlock(&rsc->client_lock);
236
237 kfree(event);
238end:
239 return;
240}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700241EXPORT_SYMBOL(sde_rsc_unregister_event);
Dhaval Patel031b4152017-03-16 13:03:18 -0700242
Dhaval Pateldd2032a2017-04-11 10:50:36 -0700243bool is_sde_rsc_available(int rsc_index)
244{
245 if (rsc_index >= MAX_RSC_COUNT) {
246 pr_err("invalid rsc index:%d\n", rsc_index);
247 return false;
248 } else if (!rsc_prv_list[rsc_index]) {
249 pr_err("rsc idx:%d not probed yet or not available\n",
250 rsc_index);
251 return false;
252 }
253
254 return true;
255}
256EXPORT_SYMBOL(is_sde_rsc_available);
257
258enum sde_rsc_state get_sde_rsc_current_state(int rsc_index)
259{
260 struct sde_rsc_priv *rsc;
261
262 if (rsc_index >= MAX_RSC_COUNT) {
263 pr_err("invalid rsc index:%d\n", rsc_index);
264 return SDE_RSC_IDLE_STATE;
265 } else if (!rsc_prv_list[rsc_index]) {
266 pr_err("rsc idx:%d not probed yet or not available\n",
267 rsc_index);
268 return SDE_RSC_IDLE_STATE;
269 }
270
271 rsc = rsc_prv_list[rsc_index];
272 return rsc->current_state;
273}
274EXPORT_SYMBOL(get_sde_rsc_current_state);
275
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700276static int sde_rsc_clk_enable(struct sde_power_handle *phandle,
277 struct sde_power_client *pclient, bool enable)
278{
279 int rc = 0;
280 struct dss_module_power *mp;
281
282 if (!phandle || !pclient) {
283 pr_err("invalid input argument\n");
284 return -EINVAL;
285 }
286
287 mp = &phandle->mp;
288
289 if (enable)
290 pclient->refcount++;
291 else if (pclient->refcount)
292 pclient->refcount--;
293
294 if (pclient->refcount)
295 pclient->usecase_ndx = VOTE_INDEX_LOW;
296 else
297 pclient->usecase_ndx = VOTE_INDEX_DISABLE;
298
299 if (phandle->current_usecase_ndx == pclient->usecase_ndx)
300 goto end;
301
302 if (enable) {
303 rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
304 if (rc) {
305 pr_err("clock enable failed rc:%d\n", rc);
306 goto end;
307 }
308 } else {
309 msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
310 }
311
312 phandle->current_usecase_ndx = pclient->usecase_ndx;
313
314end:
315 return rc;
316}
317
Dhaval Patel020f7e122016-11-15 14:39:18 -0800318static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800319 struct sde_rsc_cmd_config *cmd_config)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800320{
321 const u32 cxo_period_ns = 52;
322 u64 rsc_backoff_time_ns = RSC_BACKOFF_TIME_NS;
323 u64 rsc_mode_threshold_time_ns = RSC_MODE_THRESHOLD_TIME_IN_NS;
324 u64 rsc_time_slot_0_ns = RSC_TIME_SLOT_0_NS;
325 u64 rsc_time_slot_1_ns;
326 const u64 pdc_jitter = 20; /* 20% more */
327
328 u64 frame_time_ns, frame_jitter;
329 u64 line_time_ns, prefill_time_ns;
330 u64 pdc_backoff_time_ns;
331 s64 total;
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800332 int ret = 0;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800333
334 if (cmd_config)
335 memcpy(&rsc->cmd_config, cmd_config, sizeof(*cmd_config));
336
337 /* calculate for 640x480 60 fps resolution by default */
338 if (!rsc->cmd_config.fps)
339 rsc->cmd_config.fps = DEFAULT_PANEL_FPS;
Dhaval Patelf5cc5a32017-07-10 17:33:23 -0700340 if (!rsc->cmd_config.jitter_numer)
341 rsc->cmd_config.jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
342 if (!rsc->cmd_config.jitter_denom)
343 rsc->cmd_config.jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800344 if (!rsc->cmd_config.vtotal)
345 rsc->cmd_config.vtotal = DEFAULT_PANEL_VTOTAL;
346 if (!rsc->cmd_config.prefill_lines)
347 rsc->cmd_config.prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
Dhaval Patelf5cc5a32017-07-10 17:33:23 -0700348 pr_debug("frame fps:%d jitter_numer:%d jitter_denom:%d vtotal:%d prefill lines:%d\n",
349 rsc->cmd_config.fps, rsc->cmd_config.jitter_numer,
350 rsc->cmd_config.jitter_denom, rsc->cmd_config.vtotal,
351 rsc->cmd_config.prefill_lines);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800352
353 /* 1 nano second */
354 frame_time_ns = TICKS_IN_NANO_SECOND;
355 frame_time_ns = div_u64(frame_time_ns, rsc->cmd_config.fps);
356
Dhaval Patelf5cc5a32017-07-10 17:33:23 -0700357 frame_jitter = frame_time_ns * rsc->cmd_config.jitter_numer;
358 frame_jitter = div_u64(frame_jitter, rsc->cmd_config.jitter_denom);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800359 /* convert it to percentage */
360 frame_jitter = div_u64(frame_jitter, 100);
361
362 line_time_ns = frame_time_ns;
363 line_time_ns = div_u64(line_time_ns, rsc->cmd_config.vtotal);
364 prefill_time_ns = line_time_ns * rsc->cmd_config.prefill_lines;
365
366 total = frame_time_ns - frame_jitter - prefill_time_ns;
367 if (total < 0) {
368 pr_err("invalid total time period time:%llu jiter_time:%llu blanking time:%llu\n",
369 frame_time_ns, frame_jitter, prefill_time_ns);
370 total = 0;
371 }
372
373 total = div_u64(total, cxo_period_ns);
374 rsc->timer_config.static_wakeup_time_ns = total;
375
376 pr_debug("frame time:%llu frame jiter_time:%llu\n",
377 frame_time_ns, frame_jitter);
378 pr_debug("line time:%llu prefill time ps:%llu\n",
379 line_time_ns, prefill_time_ns);
380 pr_debug("static wakeup time:%lld cxo:%u\n", total, cxo_period_ns);
381
382 pdc_backoff_time_ns = rsc_backoff_time_ns;
383 rsc_backoff_time_ns = div_u64(rsc_backoff_time_ns, cxo_period_ns);
384 rsc->timer_config.rsc_backoff_time_ns = (u32) rsc_backoff_time_ns;
385
386 pdc_backoff_time_ns *= pdc_jitter;
387 pdc_backoff_time_ns = div_u64(pdc_backoff_time_ns, 100);
388 rsc->timer_config.pdc_backoff_time_ns = (u32) pdc_backoff_time_ns;
389
390 rsc_mode_threshold_time_ns =
391 div_u64(rsc_mode_threshold_time_ns, cxo_period_ns);
392 rsc->timer_config.rsc_mode_threshold_time_ns
393 = (u32) rsc_mode_threshold_time_ns;
394
395 /* time_slot_0 for mode0 latency */
396 rsc_time_slot_0_ns = div_u64(rsc_time_slot_0_ns, cxo_period_ns);
397 rsc->timer_config.rsc_time_slot_0_ns = (u32) rsc_time_slot_0_ns;
398
399 /* time_slot_1 for mode1 latency */
400 rsc_time_slot_1_ns = frame_time_ns;
401 rsc_time_slot_1_ns = div_u64(rsc_time_slot_1_ns, cxo_period_ns);
402 rsc->timer_config.rsc_time_slot_1_ns = (u32) rsc_time_slot_1_ns;
403
404 /* mode 2 is infinite */
405 rsc->timer_config.rsc_time_slot_2_ns = 0xFFFFFFFF;
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800406
Dhaval Patelf9c5c602017-08-01 12:32:04 -0700407 /* timer update should be called with client call */
408 if (cmd_config && rsc->hw_ops.timer_update) {
409 ret = rsc->hw_ops.timer_update(rsc);
410 if (ret)
411 pr_err("sde rsc: hw timer update failed ret:%d\n", ret);
412 /* rsc init should be called during rsc probe - one time only */
413 } else if (rsc->hw_ops.init) {
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800414 ret = rsc->hw_ops.init(rsc);
415 if (ret)
416 pr_err("sde rsc: hw init failed ret:%d\n", ret);
417 }
418
419 return ret;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800420}
421
422static int sde_rsc_switch_to_idle(struct sde_rsc_priv *rsc)
423{
424 struct sde_rsc_client *client;
Dhaval Patela65b0f12017-03-16 00:36:55 -0700425 int rc = STATE_UPDATE_NOT_ALLOWED;
426 bool idle_switch = true;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800427
428 list_for_each_entry(client, &rsc->client_list, list)
Dhaval Patela65b0f12017-03-16 00:36:55 -0700429 if (client->current_state != SDE_RSC_IDLE_STATE) {
430 idle_switch = false;
431 break;
432 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800433
Dhaval Patela65b0f12017-03-16 00:36:55 -0700434 if (!idle_switch) {
435 /**
436 * following code needs to run the loop through each
437 * client because they might be in different order
438 * sorting is not possible; only preference is available
439 */
440
441 /* first check if any vid client active */
442 list_for_each_entry(client, &rsc->client_list, list)
443 if (client->current_state == SDE_RSC_VID_STATE)
444 return rc;
445
446 /* now try cmd state switch */
447 list_for_each_entry(client, &rsc->client_list, list)
448 if (client->current_state == SDE_RSC_CMD_STATE)
449 return TRY_CMD_MODE_SWITCH;
450
451 /* now try clk state switch */
452 list_for_each_entry(client, &rsc->client_list, list)
453 if (client->current_state == SDE_RSC_CLK_STATE)
454 return TRY_CLK_MODE_SWITCH;
455
456 } else if (rsc->hw_ops.state_update) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800457 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_IDLE_STATE);
Dhaval Patel52ec1192017-05-02 23:13:24 -0700458 if (!rc)
Dhaval Patel1b62c002017-09-22 12:19:11 -0700459 rpmh_mode_solver_set(rsc->disp_rsc, true);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700460 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800461
462 return rc;
463}
464
Dhaval Patela65b0f12017-03-16 00:36:55 -0700465static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800466 struct sde_rsc_cmd_config *config,
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400467 struct sde_rsc_client *caller_client,
468 int *wait_vblank_crtc_id)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800469{
470 struct sde_rsc_client *client;
Dhaval Patela65b0f12017-03-16 00:36:55 -0700471 int rc = STATE_UPDATE_NOT_ALLOWED;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800472
473 if (!rsc->primary_client) {
474 pr_err("primary client not available for cmd state switch\n");
475 rc = -EINVAL;
476 goto end;
477 } else if (caller_client != rsc->primary_client) {
478 pr_err("primary client state:%d not cmd state request\n",
479 rsc->primary_client->current_state);
480 rc = -EINVAL;
481 goto end;
482 }
483
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800484 /* update timers - might not be available at next switch */
485 if (config)
486 sde_rsc_timer_calculate(rsc, config);
487
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400488 /**
489 * rsc clients can still send config at any time. If a config is
490 * received during cmd_state then vsync_wait will execute with the logic
491 * below. If a config is received when rsc is in AMC mode; A mode
492 * switch will do the vsync wait. updated checks still support all cases
493 * for dynamic mode switch and inline rotation.
494 */
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700495 if (rsc->current_state == SDE_RSC_CMD_STATE) {
496 rc = 0;
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400497 if (config)
498 goto vsync_wait;
499 else
500 goto end;
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700501 }
502
Dhaval Patel020f7e122016-11-15 14:39:18 -0800503 /* any one client in video state blocks the cmd state switch */
504 list_for_each_entry(client, &rsc->client_list, list)
505 if (client->current_state == SDE_RSC_VID_STATE)
506 goto end;
507
Dhaval Patel52ec1192017-05-02 23:13:24 -0700508 if (rsc->hw_ops.state_update) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800509 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CMD_STATE);
Dhaval Patel52ec1192017-05-02 23:13:24 -0700510 if (!rc)
511 rpmh_mode_solver_set(rsc->disp_rsc, true);
512 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800513
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700514vsync_wait:
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400515 /* indicate wait for vsync for vid to cmd state switch & cfg update */
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700516 if (!rc && (rsc->current_state == SDE_RSC_VID_STATE ||
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400517 rsc->current_state == SDE_RSC_CMD_STATE)) {
518 /* clear VSYNC timestamp for indication when update completes */
519 if (rsc->hw_ops.hw_vsync)
520 rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0);
521 if (!wait_vblank_crtc_id) {
522 pr_err("invalid crtc id wait pointer, client %d\n",
523 caller_client->id);
524 SDE_EVT32(caller_client->id, rsc->current_state,
525 caller_client->crtc_id,
526 wait_vblank_crtc_id, SDE_EVTLOG_ERROR);
527 msleep(PRIMARY_VBLANK_WORST_CASE_MS);
528 } else {
529 *wait_vblank_crtc_id = rsc->primary_client->crtc_id;
530 }
531 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800532end:
533 return rc;
534}
535
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400536static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc,
537 int *wait_vblank_crtc_id)
Dhaval Patela65b0f12017-03-16 00:36:55 -0700538{
539 struct sde_rsc_client *client;
540 int rc = STATE_UPDATE_NOT_ALLOWED;
541
542 list_for_each_entry(client, &rsc->client_list, list)
543 if ((client->current_state == SDE_RSC_VID_STATE) ||
544 (client->current_state == SDE_RSC_CMD_STATE))
545 goto end;
546
Dhaval Patel52ec1192017-05-02 23:13:24 -0700547 if (rsc->hw_ops.state_update) {
Dhaval Patelfbb11f02017-04-06 13:43:28 -0700548 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CLK_STATE);
Dhaval Patel52ec1192017-05-02 23:13:24 -0700549 if (!rc)
550 rpmh_mode_solver_set(rsc->disp_rsc, false);
551 }
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700552
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400553 /* indicate wait for vsync for cmd to clk state switch */
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700554 if (!rc && rsc->primary_client &&
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400555 (rsc->current_state == SDE_RSC_CMD_STATE)) {
556 /* clear VSYNC timestamp for indication when update completes */
557 if (rsc->hw_ops.hw_vsync)
558 rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0);
559 if (!wait_vblank_crtc_id) {
560 pr_err("invalid crtc id wait pointer provided\n");
561 msleep(PRIMARY_VBLANK_WORST_CASE_MS);
562 } else {
563 *wait_vblank_crtc_id = rsc->primary_client->crtc_id;
564 }
565 }
Dhaval Patela65b0f12017-03-16 00:36:55 -0700566end:
567 return rc;
568}
569
Clarence Ip56e33492017-05-18 13:43:45 -0400570static int sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800571 struct sde_rsc_cmd_config *config,
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400572 struct sde_rsc_client *caller_client,
573 int *wait_vblank_crtc_id)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800574{
575 int rc = 0;
576
577 /* update timers - might not be available at next switch */
578 if (config && (caller_client == rsc->primary_client))
579 sde_rsc_timer_calculate(rsc, config);
580
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700581 /* early exit without vsync wait for vid state */
582 if (rsc->current_state == SDE_RSC_VID_STATE)
583 goto end;
584
Dhaval Patel020f7e122016-11-15 14:39:18 -0800585 /* video state switch should be done immediately */
Dhaval Patel52ec1192017-05-02 23:13:24 -0700586 if (rsc->hw_ops.state_update) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800587 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE);
Dhaval Patel52ec1192017-05-02 23:13:24 -0700588 if (!rc)
589 rpmh_mode_solver_set(rsc->disp_rsc, false);
590 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800591
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400592 /* indicate wait for vsync for cmd to vid state switch */
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700593 if (!rc && rsc->primary_client &&
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400594 (rsc->current_state == SDE_RSC_CMD_STATE)) {
595 /* clear VSYNC timestamp for indication when update completes */
596 if (rsc->hw_ops.hw_vsync)
597 rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0);
598 if (!wait_vblank_crtc_id) {
599 pr_err("invalid crtc id wait pointer provided\n");
600 msleep(PRIMARY_VBLANK_WORST_CASE_MS);
601 } else {
602 *wait_vblank_crtc_id = rsc->primary_client->crtc_id;
603 }
604 }
Dhaval Patel1c1397d2017-05-16 18:37:34 -0700605
606end:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800607 return rc;
608}
609
610/**
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400611 * sde_rsc_client_is_state_update_complete() - check if state update is complete
612 * RSC state transition is not complete until HW receives VBLANK signal. This
613 * function checks RSC HW to determine whether that signal has been received.
614 * @client: Client pointer provided by sde_rsc_client_create().
615 *
616 * Return: true if the state update has completed.
617 */
618bool sde_rsc_client_is_state_update_complete(
619 struct sde_rsc_client *caller_client)
620{
621 struct sde_rsc_priv *rsc;
622 u32 vsync_timestamp0 = 0;
623
624 if (!caller_client) {
625 pr_err("invalid client for rsc state update\n");
626 return false;
627 } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
628 pr_err("invalid rsc index\n");
629 return false;
630 }
631
632 rsc = rsc_prv_list[caller_client->rsc_index];
633 if (!rsc)
634 return false;
635
636 /**
637 * state updates clear VSYNC timestamp, check if a new one arrived.
638 * use VSYNC mode 0 (CMD TE) always for this, per HW recommendation.
639 */
640 if (rsc->hw_ops.hw_vsync)
641 vsync_timestamp0 = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ_VSYNC0,
642 NULL, 0, 0);
643
644 return vsync_timestamp0 != 0;
645}
646
647/**
Dhaval Patel020f7e122016-11-15 14:39:18 -0800648 * sde_rsc_client_state_update() - rsc client state update
Dhaval Patela65b0f12017-03-16 00:36:55 -0700649 * Video mode, cmd mode and clk state are suppoed as modes. A client need to
Dhaval Patel020f7e122016-11-15 14:39:18 -0800650 * set this property during panel config time. A switching client can set the
651 * property to change the state
652 *
653 * @client: Client pointer provided by sde_rsc_client_create().
654 * @state: Client state - video/cmd
655 * @config: fps, vtotal, porches, etc configuration for command mode
656 * panel
657 * @crtc_id: current client's crtc id
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400658 * @wait_vblank_crtc_id: Output parameter. If set to non-zero, rsc hw
659 * state update requires a wait for one vblank on
660 * the primary crtc. In that case, this output
661 * param will be set to the crtc on which to wait.
662 * If SDE_RSC_INVALID_CRTC_ID, no wait necessary
Dhaval Patel020f7e122016-11-15 14:39:18 -0800663 *
664 * Return: error code.
665 */
666int sde_rsc_client_state_update(struct sde_rsc_client *caller_client,
667 enum sde_rsc_state state,
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400668 struct sde_rsc_cmd_config *config, int crtc_id,
669 int *wait_vblank_crtc_id)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800670{
671 int rc = 0;
672 struct sde_rsc_priv *rsc;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800673
674 if (!caller_client) {
675 pr_err("invalid client for rsc state update\n");
676 return -EINVAL;
677 } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
678 pr_err("invalid rsc index\n");
679 return -EINVAL;
680 }
681
682 rsc = rsc_prv_list[caller_client->rsc_index];
683 if (!rsc)
684 return -EINVAL;
685
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400686 if (wait_vblank_crtc_id)
687 *wait_vblank_crtc_id = SDE_RSC_INVALID_CRTC_ID;
688
Dhaval Patel020f7e122016-11-15 14:39:18 -0800689 mutex_lock(&rsc->client_lock);
Dhaval Patela5f75952017-07-25 11:17:41 -0700690 SDE_EVT32_VERBOSE(caller_client->id, caller_client->current_state,
Dhaval Patel824e9682017-05-01 23:31:22 -0700691 state, rsc->current_state, SDE_EVTLOG_FUNC_ENTRY);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800692 caller_client->crtc_id = crtc_id;
693 caller_client->current_state = state;
694
695 if (rsc->master_drm == NULL) {
696 pr_err("invalid master component binding\n");
697 rc = -EINVAL;
698 goto end;
Dhaval Patela65b0f12017-03-16 00:36:55 -0700699 } else if ((rsc->current_state == state) && !config) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800700 pr_debug("no state change: %d\n", state);
701 goto end;
702 }
703
704 pr_debug("%pS: rsc state:%d request client:%s state:%d\n",
705 __builtin_return_address(0), rsc->current_state,
706 caller_client->name, state);
707
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700708 if (rsc->current_state == SDE_RSC_IDLE_STATE)
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700709 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800710
711 switch (state) {
712 case SDE_RSC_IDLE_STATE:
713 rc = sde_rsc_switch_to_idle(rsc);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700714
Dhaval Patel020f7e122016-11-15 14:39:18 -0800715 /* video state client might be exiting; try cmd state switch */
Dhaval Patela65b0f12017-03-16 00:36:55 -0700716 if (rc == TRY_CMD_MODE_SWITCH) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800717 rc = sde_rsc_switch_to_cmd(rsc, NULL,
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400718 rsc->primary_client,
719 wait_vblank_crtc_id);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700720 if (!rc)
721 state = SDE_RSC_CMD_STATE;
722
723 /* cmd state client might be exiting; try clk state switch */
724 } else if (rc == TRY_CLK_MODE_SWITCH) {
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400725 rc = sde_rsc_switch_to_clk(rsc, wait_vblank_crtc_id);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700726 if (!rc)
727 state = SDE_RSC_CLK_STATE;
728 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800729 break;
730
731 case SDE_RSC_CMD_STATE:
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400732 rc = sde_rsc_switch_to_cmd(rsc, config, caller_client,
733 wait_vblank_crtc_id);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800734 break;
735
736 case SDE_RSC_VID_STATE:
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400737 rc = sde_rsc_switch_to_vid(rsc, config, caller_client,
738 wait_vblank_crtc_id);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800739 break;
740
Dhaval Patela65b0f12017-03-16 00:36:55 -0700741 case SDE_RSC_CLK_STATE:
Lloyd Atkinsonf68a2132017-07-17 10:16:30 -0400742 rc = sde_rsc_switch_to_clk(rsc, wait_vblank_crtc_id);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700743 break;
744
Dhaval Patel020f7e122016-11-15 14:39:18 -0800745 default:
746 pr_err("invalid state handling %d\n", state);
747 break;
748 }
749
Dhaval Patela65b0f12017-03-16 00:36:55 -0700750 if (rc == STATE_UPDATE_NOT_ALLOWED) {
751 rc = 0;
Dhaval Patel824e9682017-05-01 23:31:22 -0700752 SDE_EVT32(caller_client->id, caller_client->current_state,
753 state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE1);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700754 goto clk_disable;
755 } else if (rc) {
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700756 pr_debug("state:%d update failed rc:%d\n", state, rc);
Dhaval Patel824e9682017-05-01 23:31:22 -0700757 SDE_EVT32(caller_client->id, caller_client->current_state,
758 state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE2);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700759 goto clk_disable;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800760 }
761
762 pr_debug("state switch successfully complete: %d\n", state);
763 rsc->current_state = state;
Dhaval Patel824e9682017-05-01 23:31:22 -0700764 SDE_EVT32(caller_client->id, caller_client->current_state,
765 state, rsc->current_state, SDE_EVTLOG_FUNC_EXIT);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800766
Dhaval Patela65b0f12017-03-16 00:36:55 -0700767clk_disable:
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700768 if (rsc->current_state == SDE_RSC_IDLE_STATE)
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700769 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800770end:
771 mutex_unlock(&rsc->client_lock);
772 return rc;
773}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700774EXPORT_SYMBOL(sde_rsc_client_state_update);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800775
776/**
777 * sde_rsc_client_vote() - ab/ib vote from rsc client
778 *
779 * @client: Client pointer provided by sde_rsc_client_create().
Alan Kwong0230a102017-05-16 11:36:44 -0700780 * @bus_id: data bus for which to be voted
Dhaval Patel020f7e122016-11-15 14:39:18 -0800781 * @ab: aggregated bandwidth vote from client.
782 * @ib: instant bandwidth vote from client.
783 *
784 * Return: error code.
785 */
786int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
Alan Kwong0230a102017-05-16 11:36:44 -0700787 u32 bus_id, u64 ab_vote, u64 ib_vote)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800788{
789 int rc = 0;
790 struct sde_rsc_priv *rsc;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800791
792 if (!caller_client) {
793 pr_err("invalid client for ab/ib vote\n");
794 return -EINVAL;
795 } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
796 pr_err("invalid rsc index\n");
797 return -EINVAL;
798 }
799
800 rsc = rsc_prv_list[caller_client->rsc_index];
801 if (!rsc)
802 return -EINVAL;
803
Dhaval Patel020f7e122016-11-15 14:39:18 -0800804 pr_debug("client:%s ab:%llu ib:%llu\n",
805 caller_client->name, ab_vote, ib_vote);
806
807 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700808 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
809 if (rc)
810 goto clk_enable_fail;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800811
Dhaval Patel020f7e122016-11-15 14:39:18 -0800812 if (rsc->hw_ops.tcs_wait) {
813 rc = rsc->hw_ops.tcs_wait(rsc);
814 if (rc) {
815 pr_err("tcs is still busy; can't send command\n");
816 if (rsc->hw_ops.tcs_use_ok)
817 rsc->hw_ops.tcs_use_ok(rsc);
818 goto end;
819 }
820 }
821
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700822 rpmh_invalidate(rsc->disp_rsc);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800823 sde_power_data_bus_set_quota(&rsc->phandle, rsc->pclient,
Alan Kwong0230a102017-05-16 11:36:44 -0700824 SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT,
825 bus_id, ab_vote, ib_vote);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700826 rpmh_flush(rsc->disp_rsc);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800827
828 if (rsc->hw_ops.tcs_use_ok)
829 rsc->hw_ops.tcs_use_ok(rsc);
830
831end:
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700832 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
833clk_enable_fail:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800834 mutex_unlock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700835
Dhaval Patel020f7e122016-11-15 14:39:18 -0800836 return rc;
837}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700838EXPORT_SYMBOL(sde_rsc_client_vote);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800839
Dhaval Patelc5a2e5d2017-09-18 12:39:41 -0700840#if defined(CONFIG_DEBUG_FS)
841void sde_rsc_debug_dump(u32 mux_sel)
842{
843 struct sde_rsc_priv *rsc;
844
845 rsc = rsc_prv_list[SDE_RSC_INDEX];
846 if (!rsc)
847 return;
848
849 /* this must be called with rsc clocks enabled */
850 if (rsc->hw_ops.debug_dump)
851 rsc->hw_ops.debug_dump(rsc, mux_sel);
852}
853#endif /* defined(CONFIG_DEBUG_FS) */
854
Dhaval Patel020f7e122016-11-15 14:39:18 -0800855static int _sde_debugfs_status_show(struct seq_file *s, void *data)
856{
857 struct sde_rsc_priv *rsc;
858 struct sde_rsc_client *client;
859 int ret;
860
861 if (!s || !s->private)
862 return -EINVAL;
863
864 rsc = s->private;
865
866 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700867 ret = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
868 if (ret)
869 goto end;
870
Dhaval Patel020f7e122016-11-15 14:39:18 -0800871 seq_printf(s, "rsc current state:%d\n", rsc->current_state);
872 seq_printf(s, "wraper backoff time(ns):%d\n",
873 rsc->timer_config.static_wakeup_time_ns);
874 seq_printf(s, "rsc backoff time(ns):%d\n",
875 rsc->timer_config.rsc_backoff_time_ns);
876 seq_printf(s, "pdc backoff time(ns):%d\n",
877 rsc->timer_config.pdc_backoff_time_ns);
878 seq_printf(s, "rsc mode threshold time(ns):%d\n",
879 rsc->timer_config.rsc_mode_threshold_time_ns);
880 seq_printf(s, "rsc time slot 0(ns):%d\n",
881 rsc->timer_config.rsc_time_slot_0_ns);
882 seq_printf(s, "rsc time slot 1(ns):%d\n",
883 rsc->timer_config.rsc_time_slot_1_ns);
Dhaval Patelf5cc5a32017-07-10 17:33:23 -0700884 seq_printf(s, "frame fps:%d jitter_numer:%d jitter_denom:%d vtotal:%d prefill lines:%d\n",
885 rsc->cmd_config.fps, rsc->cmd_config.jitter_numer,
886 rsc->cmd_config.jitter_denom,
Dhaval Patel020f7e122016-11-15 14:39:18 -0800887 rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines);
888
889 seq_puts(s, "\n");
890
891 list_for_each_entry(client, &rsc->client_list, list)
892 seq_printf(s, "\t client:%s state:%d\n",
893 client->name, client->current_state);
894
Dhaval Patel020f7e122016-11-15 14:39:18 -0800895 if (rsc->hw_ops.debug_show) {
896 ret = rsc->hw_ops.debug_show(s, rsc);
897 if (ret)
898 pr_err("sde rsc: hw debug failed ret:%d\n", ret);
899 }
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700900 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800901
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700902end:
903 mutex_unlock(&rsc->client_lock);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800904 return 0;
905}
906
907static int _sde_debugfs_status_open(struct inode *inode, struct file *file)
908{
909 return single_open(file, _sde_debugfs_status_show, inode->i_private);
910}
911
912static int _sde_debugfs_mode_ctrl_open(struct inode *inode, struct file *file)
913{
914 /* non-seekable */
915 file->private_data = inode->i_private;
916 return nonseekable_open(inode, file);
917}
918
919static ssize_t _sde_debugfs_mode_ctrl_read(struct file *file, char __user *buf,
920 size_t count, loff_t *ppos)
921{
922 struct sde_rsc_priv *rsc = file->private_data;
923 char buffer[MAX_BUFFER_SIZE];
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700924 int blen = 0, rc;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800925
926 if (*ppos || !rsc || !rsc->hw_ops.mode_ctrl)
927 return 0;
928
929 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700930 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
931 if (rc)
932 goto end;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800933
934 blen = rsc->hw_ops.mode_ctrl(rsc, MODE_READ, buffer,
935 MAX_BUFFER_SIZE, 0);
936
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700937 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800938
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700939end:
940 mutex_unlock(&rsc->client_lock);
Dhaval Patelf9c5c602017-08-01 12:32:04 -0700941 if (blen <= 0)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800942 return 0;
943
944 if (copy_to_user(buf, buffer, blen))
945 return -EFAULT;
946
947 *ppos += blen;
948 return blen;
949}
950
951static ssize_t _sde_debugfs_mode_ctrl_write(struct file *file,
952 const char __user *p, size_t count, loff_t *ppos)
953{
954 struct sde_rsc_priv *rsc = file->private_data;
Dhaval Patel3d56f892017-05-05 12:21:08 -0700955 char *input;
956 u32 mode_state = 0;
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700957 int rc;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800958
Dhaval Patel3d56f892017-05-05 12:21:08 -0700959 if (!rsc || !rsc->hw_ops.mode_ctrl || !count ||
960 count > MAX_COUNT_SIZE_SUPPORTED)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800961 return 0;
962
Dhaval Patel3d56f892017-05-05 12:21:08 -0700963 input = kmalloc(count + 1, GFP_KERNEL);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800964 if (!input)
965 return -ENOMEM;
966
967 if (copy_from_user(input, p, count)) {
968 kfree(input);
969 return -EFAULT;
970 }
Dhaval Patel3d56f892017-05-05 12:21:08 -0700971 input[count] = '\0';
972
973 rc = kstrtoint(input, 0, &mode_state);
974 if (rc) {
975 pr_err("mode_state: int conversion failed rc:%d\n", rc);
976 goto end;
977 }
978
979 pr_debug("mode_state: %d\n", mode_state);
980 mode_state &= 0x7;
981 if (mode_state != ALL_MODES_DISABLED &&
982 mode_state != ALL_MODES_ENABLED &&
983 mode_state != ONLY_MODE_0_ENABLED &&
984 mode_state != ONLY_MODE_0_1_ENABLED) {
985 pr_err("invalid mode:%d combination\n", mode_state);
986 goto end;
987 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800988
989 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700990 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
991 if (rc)
992 goto clk_enable_fail;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800993
Dhaval Patel3d56f892017-05-05 12:21:08 -0700994 rsc->hw_ops.mode_ctrl(rsc, MODE_UPDATE, NULL, 0, mode_state);
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700995 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel3d56f892017-05-05 12:21:08 -0700996
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -0700997clk_enable_fail:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800998 mutex_unlock(&rsc->client_lock);
Dhaval Patel3d56f892017-05-05 12:21:08 -0700999end:
Dhaval Patel020f7e122016-11-15 14:39:18 -08001000 kfree(input);
1001 return count;
1002}
1003
1004static int _sde_debugfs_vsync_mode_open(struct inode *inode, struct file *file)
1005{
1006 /* non-seekable */
1007 file->private_data = inode->i_private;
1008 return nonseekable_open(inode, file);
1009}
1010
1011static ssize_t _sde_debugfs_vsync_mode_read(struct file *file, char __user *buf,
1012 size_t count, loff_t *ppos)
1013{
1014 struct sde_rsc_priv *rsc = file->private_data;
1015 char buffer[MAX_BUFFER_SIZE];
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001016 int blen = 0, rc;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001017
1018 if (*ppos || !rsc || !rsc->hw_ops.hw_vsync)
1019 return 0;
1020
1021 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001022 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
1023 if (rc)
1024 goto end;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001025
1026 blen = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ, buffer,
1027 MAX_BUFFER_SIZE, 0);
1028
Dhaval Patelfcd9e912017-03-16 00:54:09 -07001029 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -08001030
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001031end:
1032 mutex_unlock(&rsc->client_lock);
Dhaval Patelf9c5c602017-08-01 12:32:04 -07001033 if (blen <= 0)
Dhaval Patel020f7e122016-11-15 14:39:18 -08001034 return 0;
1035
1036 if (copy_to_user(buf, buffer, blen))
1037 return -EFAULT;
1038
1039 *ppos += blen;
1040 return blen;
1041}
1042
1043static ssize_t _sde_debugfs_vsync_mode_write(struct file *file,
1044 const char __user *p, size_t count, loff_t *ppos)
1045{
1046 struct sde_rsc_priv *rsc = file->private_data;
Dhaval Patel3d56f892017-05-05 12:21:08 -07001047 char *input;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001048 u32 vsync_state = 0;
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001049 int rc;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001050
Dhaval Patel3d56f892017-05-05 12:21:08 -07001051 if (!rsc || !rsc->hw_ops.hw_vsync || !count ||
1052 count > MAX_COUNT_SIZE_SUPPORTED)
Dhaval Patel020f7e122016-11-15 14:39:18 -08001053 return 0;
1054
Dhaval Patel3d56f892017-05-05 12:21:08 -07001055 input = kmalloc(count + 1, GFP_KERNEL);
Dhaval Patel020f7e122016-11-15 14:39:18 -08001056 if (!input)
1057 return -ENOMEM;
1058
1059 if (copy_from_user(input, p, count)) {
1060 kfree(input);
1061 return -EFAULT;
1062 }
Dhaval Patel3d56f892017-05-05 12:21:08 -07001063 input[count] = '\0';
Dhaval Patel020f7e122016-11-15 14:39:18 -08001064
Dhaval Patel3d56f892017-05-05 12:21:08 -07001065 rc = kstrtoint(input, 0, &vsync_state);
1066 if (rc) {
1067 pr_err("vsync_state: int conversion failed rc:%d\n", rc);
1068 goto end;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001069 }
1070
Dhaval Patel3d56f892017-05-05 12:21:08 -07001071 pr_debug("vsync_state: %d\n", vsync_state);
1072 vsync_state &= 0x7;
1073
Dhaval Patel020f7e122016-11-15 14:39:18 -08001074 mutex_lock(&rsc->client_lock);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001075 rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
1076 if (rc)
Dhaval Patel3d56f892017-05-05 12:21:08 -07001077 goto clk_en_fail;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001078
1079 if (vsync_state)
1080 rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL,
1081 0, vsync_state - 1);
1082 else
1083 rsc->hw_ops.hw_vsync(rsc, VSYNC_DISABLE, NULL, 0, 0);
1084
Dhaval Patelfcd9e912017-03-16 00:54:09 -07001085 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -08001086
Dhaval Patel3d56f892017-05-05 12:21:08 -07001087clk_en_fail:
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001088 mutex_unlock(&rsc->client_lock);
Dhaval Patel3d56f892017-05-05 12:21:08 -07001089end:
Dhaval Patel020f7e122016-11-15 14:39:18 -08001090 kfree(input);
1091 return count;
1092}
1093
1094static const struct file_operations debugfs_status_fops = {
1095 .open = _sde_debugfs_status_open,
1096 .read = seq_read,
1097 .llseek = seq_lseek,
1098 .release = single_release,
1099};
1100
1101static const struct file_operations mode_control_fops = {
1102 .open = _sde_debugfs_mode_ctrl_open,
1103 .read = _sde_debugfs_mode_ctrl_read,
1104 .write = _sde_debugfs_mode_ctrl_write,
1105};
1106
1107static const struct file_operations vsync_status_fops = {
1108 .open = _sde_debugfs_vsync_mode_open,
1109 .read = _sde_debugfs_vsync_mode_read,
1110 .write = _sde_debugfs_vsync_mode_write,
1111};
1112
1113static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name)
1114{
1115 rsc->debugfs_root = debugfs_create_dir(name, NULL);
1116 if (!rsc->debugfs_root)
1117 return;
1118
1119 /* don't error check these */
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001120 debugfs_create_file("status", 0400, rsc->debugfs_root, rsc,
Dhaval Patel020f7e122016-11-15 14:39:18 -08001121 &debugfs_status_fops);
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001122 debugfs_create_file("mode_control", 0600, rsc->debugfs_root, rsc,
Dhaval Patel020f7e122016-11-15 14:39:18 -08001123 &mode_control_fops);
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001124 debugfs_create_file("vsync_mode", 0600, rsc->debugfs_root, rsc,
Dhaval Patel020f7e122016-11-15 14:39:18 -08001125 &vsync_status_fops);
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001126 debugfs_create_x32("debug_mode", 0600, rsc->debugfs_root,
Dhaval Patel020f7e122016-11-15 14:39:18 -08001127 &rsc->debug_mode);
1128}
1129
1130static void sde_rsc_deinit(struct platform_device *pdev,
1131 struct sde_rsc_priv *rsc)
1132{
1133 if (!rsc)
1134 return;
1135
1136 if (rsc->pclient)
Dhaval Patelfcd9e912017-03-16 00:54:09 -07001137 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -08001138 if (rsc->fs)
1139 devm_regulator_put(rsc->fs);
1140 if (rsc->wrapper_io.base)
1141 msm_dss_iounmap(&rsc->wrapper_io);
1142 if (rsc->drv_io.base)
1143 msm_dss_iounmap(&rsc->drv_io);
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001144 if (rsc->disp_rsc)
1145 rpmh_release(rsc->disp_rsc);
Dhaval Patel020f7e122016-11-15 14:39:18 -08001146 if (rsc->pclient)
1147 sde_power_client_destroy(&rsc->phandle, rsc->pclient);
1148
1149 sde_power_resource_deinit(pdev, &rsc->phandle);
1150 debugfs_remove_recursive(rsc->debugfs_root);
1151 kfree(rsc);
1152}
1153
1154/**
1155 * sde_rsc_bind - bind rsc device with controlling device
1156 * @dev: Pointer to base of platform device
1157 * @master: Pointer to container of drm device
1158 * @data: Pointer to private data
1159 * Returns: Zero on success
1160 */
1161static int sde_rsc_bind(struct device *dev,
1162 struct device *master,
1163 void *data)
1164{
1165 struct sde_rsc_priv *rsc;
1166 struct drm_device *drm;
1167 struct platform_device *pdev = to_platform_device(dev);
1168
1169 if (!dev || !pdev || !master) {
1170 pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
1171 dev, pdev, master);
1172 return -EINVAL;
1173 }
1174
1175 drm = dev_get_drvdata(master);
1176 rsc = platform_get_drvdata(pdev);
1177 if (!drm || !rsc) {
1178 pr_err("invalid param(s), drm %pK, rsc %pK\n",
1179 drm, rsc);
1180 return -EINVAL;
1181 }
1182
1183 mutex_lock(&rsc->client_lock);
1184 rsc->master_drm = drm;
1185 mutex_unlock(&rsc->client_lock);
1186
Dhaval Patela2430842017-06-15 14:32:36 -07001187 sde_dbg_reg_register_base(SDE_RSC_DRV_DBG_NAME, rsc->drv_io.base,
1188 rsc->drv_io.len);
1189 sde_dbg_reg_register_base(SDE_RSC_WRAPPER_DBG_NAME,
1190 rsc->wrapper_io.base, rsc->wrapper_io.len);
Dhaval Patel020f7e122016-11-15 14:39:18 -08001191 return 0;
1192}
1193
1194/**
1195 * sde_rsc_unbind - unbind rsc from controlling device
1196 * @dev: Pointer to base of platform device
1197 * @master: Pointer to container of drm device
1198 * @data: Pointer to private data
1199 */
1200static void sde_rsc_unbind(struct device *dev,
1201 struct device *master, void *data)
1202{
1203 struct sde_rsc_priv *rsc;
1204 struct platform_device *pdev = to_platform_device(dev);
1205
1206 if (!dev || !pdev) {
1207 pr_err("invalid param(s)\n");
1208 return;
1209 }
1210
1211 rsc = platform_get_drvdata(pdev);
1212 if (!rsc) {
1213 pr_err("invalid display rsc\n");
1214 return;
1215 }
1216
1217 mutex_lock(&rsc->client_lock);
1218 rsc->master_drm = NULL;
1219 mutex_unlock(&rsc->client_lock);
1220}
1221
1222static const struct component_ops sde_rsc_comp_ops = {
1223 .bind = sde_rsc_bind,
1224 .unbind = sde_rsc_unbind,
1225};
1226
1227static int sde_rsc_probe(struct platform_device *pdev)
1228{
1229 int ret;
1230 struct sde_rsc_priv *rsc;
1231 static int counter;
1232 char name[MAX_RSC_CLIENT_NAME_LEN];
1233
1234 rsc = kzalloc(sizeof(*rsc), GFP_KERNEL);
1235 if (!rsc) {
1236 ret = -ENOMEM;
1237 goto rsc_alloc_fail;
1238 }
1239
1240 platform_set_drvdata(pdev, rsc);
1241 of_property_read_u32(pdev->dev.of_node, "qcom,sde-rsc-version",
1242 &rsc->version);
1243
1244 ret = sde_power_resource_init(pdev, &rsc->phandle);
1245 if (ret) {
1246 pr_err("sde rsc:power resource init failed ret:%d\n", ret);
1247 goto sde_rsc_fail;
1248 }
1249
1250 rsc->pclient = sde_power_client_create(&rsc->phandle, "rsc");
1251 if (IS_ERR_OR_NULL(rsc->pclient)) {
1252 ret = PTR_ERR(rsc->pclient);
1253 rsc->pclient = NULL;
1254 pr_err("sde rsc:power client create failed ret:%d\n", ret);
1255 goto sde_rsc_fail;
1256 }
1257
Dhaval Patelc4f1c7c2017-08-16 12:02:21 -07001258 /**
1259 * sde rsc should always vote through enable path, sleep vote is
1260 * set to "0" by default.
1261 */
1262 sde_power_data_bus_state_update(&rsc->phandle, true);
1263
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001264 rsc->disp_rsc = rpmh_get_byname(pdev, "disp_rsc");
1265 if (IS_ERR_OR_NULL(rsc->disp_rsc)) {
1266 ret = PTR_ERR(rsc->disp_rsc);
1267 rsc->disp_rsc = NULL;
1268 pr_err("sde rsc:get display rsc failed ret:%d\n", ret);
1269 goto sde_rsc_fail;
1270 }
Dhaval Pateld2dd1ad2017-03-29 16:13:17 -07001271
Dhaval Patel020f7e122016-11-15 14:39:18 -08001272 ret = msm_dss_ioremap_byname(pdev, &rsc->wrapper_io, "wrapper");
1273 if (ret) {
1274 pr_err("sde rsc: wrapper io data mapping failed ret=%d\n", ret);
1275 goto sde_rsc_fail;
1276 }
1277
1278 ret = msm_dss_ioremap_byname(pdev, &rsc->drv_io, "drv");
1279 if (ret) {
1280 pr_err("sde rsc: drv io data mapping failed ret:%d\n", ret);
1281 goto sde_rsc_fail;
1282 }
1283
1284 rsc->fs = devm_regulator_get(&pdev->dev, "vdd");
1285 if (IS_ERR_OR_NULL(rsc->fs)) {
1286 rsc->fs = NULL;
1287 pr_err("unable to get regulator\n");
1288 goto sde_rsc_fail;
1289 }
1290
1291 ret = sde_rsc_hw_register(rsc);
1292 if (ret) {
1293 pr_err("sde rsc: hw register failed ret:%d\n", ret);
1294 goto sde_rsc_fail;
1295 }
1296
Dhaval Patelfcd9e912017-03-16 00:54:09 -07001297 if (sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true)) {
Dhaval Patel020f7e122016-11-15 14:39:18 -08001298 pr_err("failed to enable sde rsc power resources\n");
1299 goto sde_rsc_fail;
1300 }
1301
Dhaval Patel82c8dbc2017-02-18 23:15:10 -08001302 if (sde_rsc_timer_calculate(rsc, NULL))
1303 goto sde_rsc_fail;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001304
Dhaval Patelfcd9e912017-03-16 00:54:09 -07001305 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
1306
Dhaval Patel020f7e122016-11-15 14:39:18 -08001307 INIT_LIST_HEAD(&rsc->client_list);
Dhaval Patelfbb11f02017-04-06 13:43:28 -07001308 INIT_LIST_HEAD(&rsc->event_list);
Dhaval Patel020f7e122016-11-15 14:39:18 -08001309 mutex_init(&rsc->client_lock);
1310
1311 pr_info("sde rsc index:%d probed successfully\n",
1312 SDE_RSC_INDEX + counter);
1313
1314 rsc_prv_list[SDE_RSC_INDEX + counter] = rsc;
1315 snprintf(name, MAX_RSC_CLIENT_NAME_LEN, "%s%d", "sde_rsc", counter);
1316 _sde_rsc_init_debugfs(rsc, name);
1317 counter++;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001318
1319 ret = component_add(&pdev->dev, &sde_rsc_comp_ops);
1320 if (ret)
1321 pr_debug("component add failed, ret=%d\n", ret);
1322 ret = 0;
1323
1324 return ret;
1325
1326sde_rsc_fail:
1327 sde_rsc_deinit(pdev, rsc);
1328rsc_alloc_fail:
1329 return ret;
1330}
1331
1332static int sde_rsc_remove(struct platform_device *pdev)
1333{
1334 struct sde_rsc_priv *rsc = platform_get_drvdata(pdev);
1335
1336 sde_rsc_deinit(pdev, rsc);
1337 return 0;
1338}
1339
1340static const struct of_device_id dt_match[] = {
1341 { .compatible = "qcom,sde-rsc"},
1342 {}
1343};
1344
1345MODULE_DEVICE_TABLE(of, dt_match);
1346
1347static struct platform_driver sde_rsc_platform_driver = {
1348 .probe = sde_rsc_probe,
1349 .remove = sde_rsc_remove,
1350 .driver = {
1351 .name = "sde_rsc",
1352 .of_match_table = dt_match,
1353 },
1354};
1355
1356static int __init sde_rsc_register(void)
1357{
1358 return platform_driver_register(&sde_rsc_platform_driver);
1359}
1360
1361static void __exit sde_rsc_unregister(void)
1362{
1363 platform_driver_unregister(&sde_rsc_platform_driver);
1364}
1365
1366module_init(sde_rsc_register);
1367module_exit(sde_rsc_unregister);