blob: 7c1b7d9f41a02eda586aef20ccabb106e1be5a22 [file] [log] [blame]
Shiraz Hashimd740ab42020-02-04 13:41:20 +05301/* Copyright (c) 2013-2019, 2020, The Linux Foundation. All rights reserved.
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/dma-mapping.h>
17#include <linux/errno.h>
18#include <linux/kernel.h>
19#include <linux/major.h>
20#include <linux/module.h>
21#include <linux/uaccess.h>
22#include <linux/delay.h>
23#include <linux/dma-buf.h>
24#include <linux/pm_runtime.h>
Sachin Bhayareeeb88892018-01-02 16:36:01 +053025#include <linux/iommu.h>
Arun kumardb962812018-05-30 16:31:52 +053026#include <linux/msm_ion.h>
Sachin Bhayareeeb88892018-01-02 16:36:01 +053027
28#include "mdp3_ctrl.h"
29#include "mdp3.h"
30#include "mdp3_ppp.h"
31#include "mdss_smmu.h"
Arun kumardb962812018-05-30 16:31:52 +053032#include "mdss_spi_panel.h"
Arun kumar47145e02018-03-23 22:07:51 +053033#include "mdss_sync.h"
Sachin Bhayareeeb88892018-01-02 16:36:01 +053034
Sachin Bhayareeeb88892018-01-02 16:36:01 +053035static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
36static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx);
37static int mdp3_histogram_stop(struct mdp3_session_data *session,
38 u32 block);
39static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable);
40static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable);
41static int mdp3_ctrl_get_intf_type(struct msm_fb_data_type *mfd);
42static int mdp3_ctrl_lut_read(struct msm_fb_data_type *mfd,
43 struct mdp_rgb_lut_data *cfg);
44static int mdp3_ctrl_lut_config(struct msm_fb_data_type *mfd,
45 struct mdp_rgb_lut_data *cfg);
46static void mdp3_ctrl_pp_resume(struct msm_fb_data_type *mfd);
47
48u32 mdp_lut_inverse16[MDP_LUT_SIZE] = {
490, 65536, 32768, 21845, 16384, 13107, 10923, 9362, 8192, 7282, 6554, 5958,
505461, 5041, 4681, 4369, 4096, 3855, 3641, 3449, 3277, 3121, 2979, 2849, 2731,
512621, 2521, 2427, 2341, 2260, 2185, 2114, 2048, 1986, 1928, 1872, 1820, 1771,
521725, 1680, 1638, 1598, 1560, 1524, 1489, 1456, 1425, 1394, 1365, 1337, 1311,
531285, 1260, 1237, 1214, 1192, 1170, 1150, 1130, 1111, 1092, 1074, 1057, 1040,
541024, 1008, 993, 978, 964, 950, 936, 923, 910, 898, 886, 874, 862, 851, 840,
55830, 819, 809, 799, 790, 780, 771, 762, 753, 745, 736, 728, 720, 712, 705, 697,
56690, 683, 676, 669, 662, 655, 649, 643, 636, 630, 624, 618, 612, 607, 601, 596,
57590, 585, 580, 575, 570, 565, 560, 555, 551, 546, 542, 537, 533, 529, 524, 520,
58516, 512, 508, 504, 500, 496, 493, 489, 485, 482, 478, 475, 471, 468, 465, 462,
59458, 455, 452, 449, 446, 443, 440, 437, 434, 431, 428, 426, 423, 420, 417, 415,
60412, 410, 407, 405, 402, 400, 397, 395, 392, 390, 388, 386, 383, 381, 379, 377,
61374, 372, 370, 368, 366, 364, 362, 360, 358, 356, 354, 352, 350, 349, 347, 345,
62343, 341, 340, 338, 336, 334, 333, 331, 329, 328, 326, 324, 323, 321, 320, 318,
63317, 315, 314, 312, 311, 309, 308, 306, 305, 303, 302, 301, 299, 298, 297, 295,
64294, 293, 291, 290, 289, 287, 286, 285, 284, 282, 281, 280, 279, 278, 277, 275,
65274, 273, 272, 271, 270, 269, 267, 266, 265, 264, 263, 262, 261, 260, 259, 258,
66257};
67
68static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
69{
70 bufq->count = 0;
71 bufq->push_idx = 0;
72 bufq->pop_idx = 0;
73}
74
Arun kumardb962812018-05-30 16:31:52 +053075void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq, int client)
Sachin Bhayareeeb88892018-01-02 16:36:01 +053076{
77 int count = bufq->count;
78
79 if (!count)
80 return;
81
82 while (count-- && (bufq->pop_idx >= 0)) {
83 struct mdp3_img_data *data = &bufq->img_data[bufq->pop_idx];
84
85 bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE;
Arun kumardb962812018-05-30 16:31:52 +053086 mdp3_put_img(data, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +053087 }
88 bufq->count = 0;
89 bufq->push_idx = 0;
90 bufq->pop_idx = 0;
91}
92
93int mdp3_bufq_push(struct mdp3_buffer_queue *bufq,
94 struct mdp3_img_data *data)
95{
96 if (bufq->count >= MDP3_MAX_BUF_QUEUE) {
97 pr_err("bufq full\n");
98 return -EPERM;
99 }
100
101 bufq->img_data[bufq->push_idx] = *data;
102 bufq->push_idx = (bufq->push_idx + 1) % MDP3_MAX_BUF_QUEUE;
103 bufq->count++;
104 return 0;
105}
106
107static struct mdp3_img_data *mdp3_bufq_pop(struct mdp3_buffer_queue *bufq)
108{
109 struct mdp3_img_data *data;
110
111 if (bufq->count == 0)
112 return NULL;
113
114 data = &bufq->img_data[bufq->pop_idx];
115 bufq->count--;
116 bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE;
117 return data;
118}
119
120static int mdp3_bufq_count(struct mdp3_buffer_queue *bufq)
121{
122 return bufq->count;
123}
124
Arun kumardb962812018-05-30 16:31:52 +0530125int mdp3_get_ion_client(struct msm_fb_data_type *mfd)
126{
127 int intf_type;
128
129 intf_type = mdp3_ctrl_get_intf_type(mfd);
130
131 if (intf_type == MDP3_DMA_OUTPUT_SEL_SPI_CMD)
132 return MDP3_CLIENT_SPI;
133 else
134 return MDP3_CLIENT_DMA_P;
135}
136
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530137void mdp3_ctrl_notifier_register(struct mdp3_session_data *ses,
138 struct notifier_block *notifier)
139{
140 blocking_notifier_chain_register(&ses->notifier_head, notifier);
141}
142
143void mdp3_ctrl_notifier_unregister(struct mdp3_session_data *ses,
144 struct notifier_block *notifier)
145{
146 blocking_notifier_chain_unregister(&ses->notifier_head, notifier);
147}
148
149int mdp3_ctrl_notify(struct mdp3_session_data *ses, int event)
150{
151 return blocking_notifier_call_chain(&ses->notifier_head, event, ses);
152}
153
Animesh Kishore3650a562018-11-16 00:26:26 +0530154static void __mdp3_dispatch_dma_done(struct mdp3_session_data *session)
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530155{
Animesh Kishore3650a562018-11-16 00:26:26 +0530156 int cnt;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530157
158 cnt = atomic_read(&session->dma_done_cnt);
159 MDSS_XLOG(cnt);
160 while (cnt > 0) {
161 mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE);
162 atomic_dec(&session->dma_done_cnt);
163 cnt--;
164 }
165}
166
Animesh Kishore3650a562018-11-16 00:26:26 +0530167void mdp3_flush_dma_done(struct mdp3_session_data *session)
168{
169 if (!session)
170 return;
171
172 pr_debug("%s\n", __func__);
173
174 __mdp3_dispatch_dma_done(session);
175}
176
177static void mdp3_dispatch_dma_done(struct kthread_work *work)
178{
179 struct mdp3_session_data *session;
180
181 pr_debug("%s\n", __func__);
182 session = container_of(work, struct mdp3_session_data,
183 dma_done_work);
184 if (!session)
185 return;
186
187 __mdp3_dispatch_dma_done(session);
188}
189
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530190static void mdp3_dispatch_clk_off(struct work_struct *work)
191{
192 struct mdp3_session_data *session;
193 int rc;
194 bool dmap_busy;
195 int retry_count = 2;
196
197 pr_debug("%s\n", __func__);
198 MDSS_XLOG(XLOG_FUNC_ENTRY, __LINE__);
199 session = container_of(work, struct mdp3_session_data,
200 clk_off_work);
201 if (!session)
202 return;
203
204 mutex_lock(&session->lock);
Abhijith Desaib502b282018-09-12 14:48:22 +0530205 MDSS_XLOG(0x111, atomic_read(&session->vsync_countdown),
206 session->dma->vsync_period);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530207 if (session->vsync_enabled ||
208 atomic_read(&session->vsync_countdown) > 0) {
209 mutex_unlock(&session->lock);
210 pr_debug("%s: Ignoring clk shut down\n", __func__);
211 MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__);
212 return;
213 }
214
Arun kumar04d4a922018-05-23 16:22:45 +0530215 if (!session->clk_on) {
216 mutex_unlock(&session->lock);
217 pr_debug("%s: Clk shut down is done\n", __func__);
218 MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__);
219 return;
220 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530221 if (session->intf->active) {
222retry_dma_done:
223 rc = wait_for_completion_timeout(&session->dma_completion,
Abhijith Desaib502b282018-09-12 14:48:22 +0530224 dma_timeout_value(session->dma));
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530225 if (rc <= 0) {
226 struct mdss_panel_data *panel;
227
228 panel = session->panel;
229 pr_debug("cmd kickoff timed out (%d)\n", rc);
230 dmap_busy = session->dma->busy();
Abhijith Desaib502b282018-09-12 14:48:22 +0530231 MDSS_XLOG(0x222, dmap_busy);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530232 if (dmap_busy) {
233 if (--retry_count) {
234 pr_err("dmap is busy, retry %d\n",
235 retry_count);
Arun kumar04d4a922018-05-23 16:22:45 +0530236 MDSS_XLOG(__LINE__, retry_count);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530237 goto retry_dma_done;
238 }
239 pr_err("dmap is still busy, bug_on\n");
Abhijith Desaib502b282018-09-12 14:48:22 +0530240 BUG_ON(1);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530241 } else {
242 pr_debug("dmap is not busy, continue\n");
243 }
244 }
245 }
246 mdp3_ctrl_vsync_enable(session->mfd, 0);
247 mdp3_ctrl_clk_enable(session->mfd, 0);
248 MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__);
249 mutex_unlock(&session->lock);
250}
251
252static void mdp3_vsync_retire_handle_vsync(void *arg)
253{
254 struct mdp3_session_data *mdp3_session;
255
256 mdp3_session = (struct mdp3_session_data *)arg;
257
258 if (!mdp3_session) {
259 pr_warn("Invalid handle for vsync\n");
260 return;
261 }
262
263 schedule_work(&mdp3_session->retire_work);
264}
265
Animesh Kishore8b42bd92018-12-04 18:57:13 +0530266void mdp3_vsync_retire_signal(struct msm_fb_data_type *mfd, int val)
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530267{
268 struct mdp3_session_data *mdp3_session;
269
270 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
271
272 mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
273 if (mdp3_session->retire_cnt > 0) {
Arun kumar47145e02018-03-23 22:07:51 +0530274 mdss_inc_timeline(mfd->mdp_sync_pt_data.timeline_retire, val);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530275 mdp3_session->retire_cnt -= min(val, mdp3_session->retire_cnt);
Animesh Kishore8b42bd92018-12-04 18:57:13 +0530276 pr_debug("Retire signaled! timeline val=%d remaining=%d\n",
277 mdss_get_timeline_retire_ts(
278 mfd->mdp_sync_pt_data.timeline_retire),
279 mdp3_session->retire_cnt);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530280 }
281 mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
282}
283
284static void mdp3_vsync_retire_work_handler(struct work_struct *work)
285{
286 struct mdp3_session_data *mdp3_session =
287 container_of(work, struct mdp3_session_data, retire_work);
288
289 if (!mdp3_session)
290 return;
291
292 mdp3_vsync_retire_signal(mdp3_session->mfd, 1);
293}
294
295void mdp3_hist_intr_notify(struct mdp3_dma *dma)
296{
297 dma->hist_events++;
298 sysfs_notify_dirent(dma->hist_event_sd);
299 pr_debug("%s:: hist_events = %u\n", __func__, dma->hist_events);
300}
301
302void vsync_notify_handler(void *arg)
303{
304 struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
305
306 session->vsync_time = ktime_get();
307 MDSS_XLOG(ktime_to_ms(session->vsync_time));
308 sysfs_notify_dirent(session->vsync_event_sd);
309}
310
311void dma_done_notify_handler(void *arg)
312{
313 struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
314
315 atomic_inc(&session->dma_done_cnt);
Sachin Bhayare3d3767e2018-01-02 21:10:57 +0530316 kthread_queue_work(&session->worker, &session->dma_done_work);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530317 complete_all(&session->dma_completion);
318}
319
320void vsync_count_down(void *arg)
321{
322 struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
323
324 /* We are counting down to turn off clocks */
Abhijith Desaib502b282018-09-12 14:48:22 +0530325 if (atomic_read(&session->vsync_countdown) > 0) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530326 atomic_dec(&session->vsync_countdown);
Abhijith Desaib502b282018-09-12 14:48:22 +0530327 MDSS_XLOG(atomic_read(&session->vsync_countdown),
328 session->dma->vsync_period);
Abhijith Desai88a830c2018-09-11 14:54:21 +0530329 if (atomic_read(&session->vsync_countdown) == 0)
330 schedule_work(&session->clk_off_work);
Abhijith Desaib502b282018-09-12 14:48:22 +0530331 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530332}
333
334void mdp3_ctrl_reset_countdown(struct mdp3_session_data *session,
335 struct msm_fb_data_type *mfd)
336{
337 if (mdp3_ctrl_get_intf_type(mfd) == MDP3_DMA_OUTPUT_SEL_DSI_CMD)
338 atomic_set(&session->vsync_countdown, VSYNC_EXPIRE_TICK);
Abhijith Desaib502b282018-09-12 14:48:22 +0530339
340 MDSS_XLOG(atomic_read(&session->vsync_countdown));
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530341}
342
343static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
344{
345 struct mdp3_session_data *mdp3_session;
346 struct mdp3_notification vsync_client;
347 struct mdp3_notification *arg = NULL;
348 bool mod_vsync_timer = false;
Arun kumardb962812018-05-30 16:31:52 +0530349 int intf_type;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530350
351 pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
Arun kumardb962812018-05-30 16:31:52 +0530352
353 intf_type = mdp3_ctrl_get_intf_type(mfd);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530354 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
355 if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
356 !mdp3_session->intf)
357 return -ENODEV;
358
359 if (!mdp3_session->status) {
360 pr_debug("fb%d is not on yet", mfd->index);
361 return -EINVAL;
362 }
363 if (enable) {
364 vsync_client.handler = vsync_notify_handler;
365 vsync_client.arg = mdp3_session;
366 arg = &vsync_client;
367 } else if (atomic_read(&mdp3_session->vsync_countdown) > 0) {
368 /*
369 * Now that vsync is no longer needed we will
370 * shutdown dsi clocks as soon as cnt down == 0
371 * for cmd mode panels
372 */
373 vsync_client.handler = vsync_count_down;
374 vsync_client.arg = mdp3_session;
375 arg = &vsync_client;
376 enable = 1;
377 }
378
379 if (enable) {
380 if (mdp3_session->status == 1 &&
381 (mdp3_session->vsync_before_commit ||
382 !mdp3_session->intf->active)) {
383 mod_vsync_timer = true;
384 } else if (!mdp3_session->clk_on) {
385 /* Enable clocks before enabling the vsync interrupt */
386 mdp3_ctrl_reset_countdown(mdp3_session, mfd);
387 mdp3_ctrl_clk_enable(mfd, 1);
388 }
389 }
390
Arun kumardb962812018-05-30 16:31:52 +0530391 if (intf_type == MDP3_DMA_OUTPUT_SEL_SPI_CMD) {
392 mdp3_spi_vsync_enable(mdp3_session->panel, arg);
393 } else {
394 mdp3_clk_enable(1, 0);
395 mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
396 mdp3_clk_enable(0, 0);
397 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530398
399 /*
400 * Need to fake vsync whenever dsi interface is not
401 * active or when dsi clocks are currently off
402 */
Arun kumardb962812018-05-30 16:31:52 +0530403 if (mod_vsync_timer && (intf_type != MDP3_DMA_OUTPUT_SEL_SPI_CMD)) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530404 mod_timer(&mdp3_session->vsync_timer,
Abhijith Desaib502b282018-09-12 14:48:22 +0530405 jiffies + msecs_to_jiffies(mdp3_session->dma->vsync_period));
Arun kumardb962812018-05-30 16:31:52 +0530406 } else if (enable && !mdp3_session->clk_on) {
407 mdp3_ctrl_reset_countdown(mdp3_session, mfd);
408 mdp3_ctrl_clk_enable(mfd, 1);
409 } else if (!enable && (intf_type != MDP3_DMA_OUTPUT_SEL_SPI_CMD)) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530410 del_timer(&mdp3_session->vsync_timer);
411 }
412
413 return 0;
414}
415
416void mdp3_vsync_timer_func(unsigned long arg)
417{
418 struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
419
420 if (session->status == 1 && (session->vsync_before_commit ||
421 !session->intf->active)) {
422 pr_debug("mdp3_vsync_timer_func trigger\n");
423 vsync_notify_handler(session);
424 mod_timer(&session->vsync_timer,
Abhijith Desaib502b282018-09-12 14:48:22 +0530425 jiffies + msecs_to_jiffies(session->dma->vsync_period));
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530426 }
427}
428
429static int mdp3_ctrl_async_blit_req(struct msm_fb_data_type *mfd,
430 void __user *p)
431{
432 struct mdp_async_blit_req_list req_list_header;
433 int rc, count;
434 void __user *p_req;
435
436 if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
437 return -EFAULT;
438 p_req = p + sizeof(req_list_header);
439 count = req_list_header.count;
Arun kumar98917ce2018-05-23 15:50:25 +0530440 if (count < 0 || count > MAX_BLIT_REQ)
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530441 return -EINVAL;
442 rc = mdp3_ppp_parse_req(p_req, &req_list_header, 1);
443 if (!rc)
444 rc = copy_to_user(p, &req_list_header, sizeof(req_list_header));
445 return rc;
446}
447
448static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p)
449{
450 struct mdp_async_blit_req_list req_list_header;
451 int rc, count;
452 void __user *p_req;
453
454 if (copy_from_user(&(req_list_header.count), p,
455 sizeof(struct mdp_blit_req_list)))
456 return -EFAULT;
457 p_req = p + sizeof(struct mdp_blit_req_list);
458 count = req_list_header.count;
Arun kumar98917ce2018-05-23 15:50:25 +0530459 if (count < 0 || count > MAX_BLIT_REQ)
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530460 return -EINVAL;
461 req_list_header.sync.acq_fen_fd_cnt = 0;
462 rc = mdp3_ppp_parse_req(p_req, &req_list_header, 0);
463 return rc;
464}
465
466static ssize_t mdp3_bl_show_event(struct device *dev,
467 struct device_attribute *attr, char *buf)
468{
469 struct fb_info *fbi = dev_get_drvdata(dev);
470 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
471 struct mdp3_session_data *mdp3_session = NULL;
472 int ret;
473
474 if (!mfd || !mfd->mdp.private1)
475 return -EAGAIN;
476
477 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
478 ret = scnprintf(buf, PAGE_SIZE, "%d\n", mdp3_session->bl_events);
479 return ret;
480}
481
482static ssize_t mdp3_hist_show_event(struct device *dev,
483 struct device_attribute *attr, char *buf)
484{
485 struct fb_info *fbi = dev_get_drvdata(dev);
486 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
487 struct mdp3_session_data *mdp3_session = NULL;
488 struct mdp3_dma *dma = NULL;
489 int ret;
490
491 if (!mfd || !mfd->mdp.private1)
492 return -EAGAIN;
493
494 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
495 dma = (struct mdp3_dma *)mdp3_session->dma;
496 ret = scnprintf(buf, PAGE_SIZE, "%d\n", dma->hist_events);
497 return ret;
498}
499
500static ssize_t mdp3_vsync_show_event(struct device *dev,
501 struct device_attribute *attr, char *buf)
502{
503 struct fb_info *fbi = dev_get_drvdata(dev);
504 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
505 struct mdp3_session_data *mdp3_session = NULL;
506 u64 vsync_ticks;
507 int rc;
508
509 if (!mfd || !mfd->mdp.private1)
510 return -EAGAIN;
511
512 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
513
514 vsync_ticks = ktime_to_ns(mdp3_session->vsync_time);
515
516 pr_debug("fb%d vsync=%llu\n", mfd->index, vsync_ticks);
517 rc = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu\n", vsync_ticks);
518 return rc;
519}
520
521static ssize_t mdp3_packpattern_show(struct device *dev,
522 struct device_attribute *attr, char *buf)
523{
524 struct fb_info *fbi = dev_get_drvdata(dev);
525 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
526 struct mdp3_session_data *mdp3_session = NULL;
527 int rc;
528 u32 pattern = 0;
529
530 if (!mfd || !mfd->mdp.private1)
531 return -EAGAIN;
532
533 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
534
535 pattern = mdp3_session->dma->output_config.pack_pattern;
536
537 /* If pattern was found to be 0 then get pattern for fb imagetype */
538 if (!pattern)
539 pattern = mdp3_ctrl_get_pack_pattern(mfd->fb_imgType);
540
541 pr_debug("fb%d pack_pattern c= %d.", mfd->index, pattern);
542 rc = scnprintf(buf, PAGE_SIZE, "packpattern=%d\n", pattern);
543 return rc;
544}
545
546static ssize_t mdp3_dyn_pu_show(struct device *dev,
547 struct device_attribute *attr, char *buf)
548{
549 struct fb_info *fbi = dev_get_drvdata(dev);
550 struct msm_fb_data_type *mfd = fbi->par;
551 struct mdp3_session_data *mdp3_session = NULL;
552 int ret, state;
553
554 if (!mfd || !mfd->mdp.private1)
555 return -EAGAIN;
556
557 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
558 state = (mdp3_session->dyn_pu_state >= 0) ?
559 mdp3_session->dyn_pu_state : -1;
560 ret = scnprintf(buf, PAGE_SIZE, "%d", state);
561 return ret;
562}
563
564static ssize_t mdp3_dyn_pu_store(struct device *dev,
565 struct device_attribute *attr, const char *buf, size_t count)
566{
567 struct fb_info *fbi = dev_get_drvdata(dev);
568 struct msm_fb_data_type *mfd = fbi->par;
569 struct mdp3_session_data *mdp3_session = NULL;
570 int ret, dyn_pu;
571
572 if (!mfd || !mfd->mdp.private1)
573 return -EAGAIN;
574
575 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
576 ret = kstrtoint(buf, 10, &dyn_pu);
577 if (ret) {
578 pr_err("Invalid input for partial update: ret = %d\n", ret);
579 return ret;
580 }
581
582 mdp3_session->dyn_pu_state = dyn_pu;
583 sysfs_notify(&dev->kobj, NULL, "dyn_pu");
584 return count;
585}
586
587static DEVICE_ATTR(hist_event, 0444, mdp3_hist_show_event, NULL);
588static DEVICE_ATTR(bl_event, 0444, mdp3_bl_show_event, NULL);
589static DEVICE_ATTR(vsync_event, 0444, mdp3_vsync_show_event, NULL);
590static DEVICE_ATTR(packpattern, 0444, mdp3_packpattern_show, NULL);
591static DEVICE_ATTR(dyn_pu, 0664, mdp3_dyn_pu_show,
592 mdp3_dyn_pu_store);
593
594static struct attribute *generic_attrs[] = {
595 &dev_attr_packpattern.attr,
596 &dev_attr_dyn_pu.attr,
597 &dev_attr_hist_event.attr,
598 &dev_attr_bl_event.attr,
599 NULL,
600};
601
602static struct attribute *vsync_fs_attrs[] = {
603 &dev_attr_vsync_event.attr,
604 NULL,
605};
606
607static struct attribute_group vsync_fs_attr_group = {
608 .attrs = vsync_fs_attrs,
609};
610
611static struct attribute_group generic_attr_group = {
612 .attrs = generic_attrs,
613};
614
615static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable)
616{
617 struct mdp3_session_data *session;
618 struct mdss_panel_data *panel;
619 struct dsi_panel_clk_ctrl clk_ctrl;
620 int rc = 0;
621
622 pr_debug("mdp3_ctrl_clk_enable %d\n", enable);
623
624 session = mfd->mdp.private1;
625 panel = session->panel;
626
627 if (!panel->event_handler)
628 return 0;
629
630 if ((enable && session->clk_on == 0) ||
631 (!enable && session->clk_on == 1)) {
632 clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT;
633 clk_ctrl.state = enable;
634 rc = panel->event_handler(panel,
635 MDSS_EVENT_PANEL_CLK_CTRL, (void *)&clk_ctrl);
636 rc |= mdp3_res_update(enable, 1, MDP3_CLIENT_DMA_P);
637 } else {
638 pr_debug("enable = %d, clk_on=%d\n", enable, session->clk_on);
639 }
640
641 session->clk_on = enable;
642 return rc;
643}
644
645static int mdp3_ctrl_res_req_bus(struct msm_fb_data_type *mfd, int status)
646{
647 int rc = 0;
Arun kumardb962812018-05-30 16:31:52 +0530648 u32 vtotal = 0;
649 int frame_rate = DEFAULT_FRAME_RATE;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530650
651 if (status) {
Arun kumardb962812018-05-30 16:31:52 +0530652 struct mdss_panel_info *panel_info = mfd->panel_info;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530653 u64 ab = 0;
654 u64 ib = 0;
655
Arun kumardb962812018-05-30 16:31:52 +0530656 frame_rate = mdss_panel_get_framerate(mfd->panel_info,
657 FPS_RESOLUTION_HZ);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530658 mdp3_calc_dma_res(mfd->panel_info, NULL, &ab, &ib,
659 ppp_bpp(mfd->fb_imgType));
Arun kumardb962812018-05-30 16:31:52 +0530660 vtotal = panel_info->yres + panel_info->lcdc.v_back_porch +
661 panel_info->lcdc.v_front_porch +
662 panel_info->lcdc.v_pulse_width;
663 ab = panel_info->xres * vtotal * ppp_bpp(mfd->fb_imgType);
664 ab *= frame_rate;
665 ib = ab;
666
667 /*DMA not used on SPI interface, remove DMA bus voting*/
668 if (mdp3_ctrl_get_intf_type(mfd) ==
669 MDP3_DMA_OUTPUT_SEL_SPI_CMD)
670 rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, 0, 0);
671 else
672 rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P,
673 ab, ib);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530674 } else {
675 rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, 0, 0);
676 }
677 return rc;
678}
679
680static int mdp3_ctrl_res_req_clk(struct msm_fb_data_type *mfd, int status)
681{
682 int rc = 0;
683
684 if (status) {
685 u64 mdp_clk_rate = 0;
686
687 mdp3_calc_dma_res(mfd->panel_info, &mdp_clk_rate,
688 NULL, NULL, 0);
689
690 mdp3_clk_set_rate(MDP3_CLK_MDP_SRC, mdp_clk_rate,
691 MDP3_CLIENT_DMA_P);
692 mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
693 MDP3_CLIENT_DMA_P);
694
695 rc = mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P);
696 if (rc) {
697 pr_err("mdp3 clk enable fail\n");
698 return rc;
699 }
700 } else {
701 rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);
702 if (rc)
703 pr_err("mdp3 clk disable fail\n");
704 }
705 return rc;
706}
707
708static int mdp3_ctrl_get_intf_type(struct msm_fb_data_type *mfd)
709{
710 int type;
711
712 switch (mfd->panel.type) {
713 case MIPI_VIDEO_PANEL:
714 type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
715 break;
716 case MIPI_CMD_PANEL:
717 type = MDP3_DMA_OUTPUT_SEL_DSI_CMD;
718 break;
719 case LCDC_PANEL:
720 type = MDP3_DMA_OUTPUT_SEL_LCDC;
721 break;
Arun kumardb962812018-05-30 16:31:52 +0530722 case SPI_PANEL:
723 type = MDP3_DMA_OUTPUT_SEL_SPI_CMD;
724 break;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530725 default:
726 type = MDP3_DMA_OUTPUT_SEL_MAX;
727 }
728 return type;
729}
730
731int mdp3_ctrl_get_source_format(u32 imgType)
732{
733 int format;
734
735 switch (imgType) {
736 case MDP_RGB_565:
737 format = MDP3_DMA_IBUF_FORMAT_RGB565;
738 break;
739 case MDP_RGB_888:
740 format = MDP3_DMA_IBUF_FORMAT_RGB888;
741 break;
Arun kumarcf595c42018-05-23 16:03:55 +0530742 case MDP_XRGB_8888:
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530743 case MDP_ARGB_8888:
744 case MDP_RGBA_8888:
Arun kumarcf595c42018-05-23 16:03:55 +0530745 case MDP_BGRA_8888:
746 case MDP_RGBX_8888:
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530747 format = MDP3_DMA_IBUF_FORMAT_XRGB8888;
748 break;
749 default:
750 format = MDP3_DMA_IBUF_FORMAT_UNDEFINED;
751 }
752 return format;
753}
754
755int mdp3_ctrl_get_pack_pattern(u32 imgType)
756{
757 int packPattern = MDP3_DMA_OUTPUT_PACK_PATTERN_RGB;
758
759 if (imgType == MDP_RGBA_8888 || imgType == MDP_RGB_888)
760 packPattern = MDP3_DMA_OUTPUT_PACK_PATTERN_BGR;
761 return packPattern;
762}
763
764static int mdp3_ctrl_intf_init(struct msm_fb_data_type *mfd,
765 struct mdp3_intf *intf)
766{
767 int rc = 0;
768 struct mdp3_intf_cfg cfg;
769 struct mdp3_video_intf_cfg *video = &cfg.video;
770 struct mdss_panel_info *p = mfd->panel_info;
771 int h_back_porch = p->lcdc.h_back_porch;
772 int h_front_porch = p->lcdc.h_front_porch;
773 int w = p->xres;
774 int v_back_porch = p->lcdc.v_back_porch;
775 int v_front_porch = p->lcdc.v_front_porch;
776 int h = p->yres;
777 int h_sync_skew = p->lcdc.hsync_skew;
778 int h_pulse_width = p->lcdc.h_pulse_width;
779 int v_pulse_width = p->lcdc.v_pulse_width;
780 int hsync_period = h_front_porch + h_back_porch + w + h_pulse_width;
781 int vsync_period = v_front_porch + v_back_porch + h + v_pulse_width;
782 struct mdp3_session_data *mdp3_session;
783
784 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
785 vsync_period *= hsync_period;
786
787 cfg.type = mdp3_ctrl_get_intf_type(mfd);
788 if (cfg.type == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
Arun kumardb962812018-05-30 16:31:52 +0530789 cfg.type == MDP3_DMA_OUTPUT_SEL_LCDC ||
790 cfg.type == MDP3_DMA_OUTPUT_SEL_SPI_CMD) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530791 video->hsync_period = hsync_period;
792 video->hsync_pulse_width = h_pulse_width;
793 video->vsync_period = vsync_period;
794 video->vsync_pulse_width = v_pulse_width * hsync_period;
795 video->display_start_x = h_back_porch + h_pulse_width;
796 video->display_end_x = hsync_period - h_front_porch - 1;
797 video->display_start_y =
798 (v_back_porch + v_pulse_width) * hsync_period;
799 video->display_end_y =
800 vsync_period - v_front_porch * hsync_period - 1;
801 video->active_start_x = video->display_start_x;
802 video->active_end_x = video->display_end_x;
803 video->active_h_enable = true;
804 video->active_start_y = video->display_start_y;
805 video->active_end_y = video->display_end_y;
806 video->active_v_enable = true;
807 video->hsync_skew = h_sync_skew;
808 video->hsync_polarity = 1;
809 video->vsync_polarity = 1;
810 video->de_polarity = 1;
811 video->underflow_color = p->lcdc.underflow_clr;
812 } else if (cfg.type == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
813 cfg.dsi_cmd.primary_dsi_cmd_id = 0;
814 cfg.dsi_cmd.secondary_dsi_cmd_id = 1;
815 cfg.dsi_cmd.dsi_cmd_tg_intf_sel = 0;
816 } else
817 return -EINVAL;
818
819 if (!(mdp3_session->in_splash_screen)) {
820 if (intf->config)
821 rc = intf->config(intf, &cfg);
822 else
823 rc = -EINVAL;
824 }
825 return rc;
826}
827
828static int mdp3_ctrl_dma_init(struct msm_fb_data_type *mfd,
829 struct mdp3_dma *dma)
830{
831 int rc;
832 struct mdss_panel_info *panel_info = mfd->panel_info;
833 struct fb_info *fbi = mfd->fbi;
834 struct fb_fix_screeninfo *fix;
835 struct fb_var_screeninfo *var;
836 struct mdp3_dma_output_config outputConfig;
837 struct mdp3_dma_source sourceConfig;
Arun kumardb962812018-05-30 16:31:52 +0530838 int frame_rate = DEFAULT_FRAME_RATE;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530839 int vbp, vfp, vspw;
840 int vtotal, vporch;
841 struct mdp3_notification dma_done_callback;
842 struct mdp3_tear_check te;
843 struct mdp3_session_data *mdp3_session;
844
845 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
846
Arun kumardb962812018-05-30 16:31:52 +0530847 frame_rate = mdss_panel_get_framerate(panel_info, FPS_RESOLUTION_HZ);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530848 vbp = panel_info->lcdc.v_back_porch;
849 vfp = panel_info->lcdc.v_front_porch;
850 vspw = panel_info->lcdc.v_pulse_width;
851 vporch = vbp + vfp + vspw;
852 vtotal = vporch + panel_info->yres;
853
854 fix = &fbi->fix;
855 var = &fbi->var;
856
857 sourceConfig.width = panel_info->xres;
858 sourceConfig.height = panel_info->yres;
859 sourceConfig.x = 0;
860 sourceConfig.y = 0;
861 sourceConfig.buf = mfd->iova;
862 sourceConfig.vporch = vporch;
863 sourceConfig.vsync_count =
864 MDP_VSYNC_CLK_RATE / (frame_rate * vtotal);
865
866 outputConfig.dither_en = 0;
867 outputConfig.out_sel = mdp3_ctrl_get_intf_type(mfd);
868 outputConfig.bit_mask_polarity = 0;
869 outputConfig.color_components_flip = 0;
870 outputConfig.pack_align = MDP3_DMA_OUTPUT_PACK_ALIGN_LSB;
871 outputConfig.color_comp_out_bits = (MDP3_DMA_OUTPUT_COMP_BITS_8 << 4) |
872 (MDP3_DMA_OUTPUT_COMP_BITS_8 << 2)|
873 MDP3_DMA_OUTPUT_COMP_BITS_8;
874
875 if (dma->update_src_cfg) {
876 /* configuration has been updated through PREPARE call */
877 sourceConfig.format = dma->source_config.format;
878 sourceConfig.stride = dma->source_config.stride;
879 outputConfig.pack_pattern = dma->output_config.pack_pattern;
880 } else {
881 sourceConfig.format =
882 mdp3_ctrl_get_source_format(mfd->fb_imgType);
883 outputConfig.pack_pattern =
884 mdp3_ctrl_get_pack_pattern(mfd->fb_imgType);
885 sourceConfig.stride = fix->line_length;
886 }
887
Arun kumardb962812018-05-30 16:31:52 +0530888 te.frame_rate = frame_rate;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530889 te.hw_vsync_mode = panel_info->mipi.hw_vsync_mode;
890 te.tear_check_en = panel_info->te.tear_check_en;
891 te.sync_cfg_height = panel_info->te.sync_cfg_height;
Krishna Manikandan8a532a12018-07-06 15:55:09 +0530892
893 /* For mdp3, max. value of CFG_HEIGHT is 0x7ff,
894 * for mdp5, max. value of CFG_HEIGHT is 0xffff.
895 */
896 if (te.sync_cfg_height > 0x7ff)
897 te.sync_cfg_height = 0x7ff;
898
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530899 te.vsync_init_val = panel_info->te.vsync_init_val;
900 te.sync_threshold_start = panel_info->te.sync_threshold_start;
901 te.sync_threshold_continue = panel_info->te.sync_threshold_continue;
902 te.start_pos = panel_info->te.start_pos;
903 te.rd_ptr_irq = panel_info->te.rd_ptr_irq;
904 te.refx100 = panel_info->te.refx100;
905
906 if (dma->dma_config) {
907 if (!panel_info->partial_update_enabled) {
908 dma->roi.w = sourceConfig.width;
909 dma->roi.h = sourceConfig.height;
910 dma->roi.x = sourceConfig.x;
911 dma->roi.y = sourceConfig.y;
912 }
913 rc = dma->dma_config(dma, &sourceConfig, &outputConfig,
914 mdp3_session->in_splash_screen);
915 } else {
916 pr_err("%s: dma config failed\n", __func__);
917 rc = -EINVAL;
918 }
919
920 if (outputConfig.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
921 if (dma->dma_sync_config)
922 rc = dma->dma_sync_config(dma,
923 &sourceConfig, &te);
924 else
925 rc = -EINVAL;
926 dma_done_callback.handler = dma_done_notify_handler;
927 dma_done_callback.arg = mfd->mdp.private1;
928 dma->dma_done_notifier(dma, &dma_done_callback);
929 }
930
931 return rc;
932}
933
934static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
935{
936 int rc = 0;
937 struct mdp3_session_data *mdp3_session;
938 struct mdss_panel_data *panel;
Abhijith Desaib502b282018-09-12 14:48:22 +0530939 u32 framerate = 0;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530940
941 pr_debug("mdp3_ctrl_on\n");
942 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
943 if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
944 !mdp3_session->intf) {
945 pr_err("mdp3_ctrl_on no device");
946 return -ENODEV;
947 }
948 mutex_lock(&mdp3_session->lock);
949
950 MDSS_XLOG(XLOG_FUNC_ENTRY, __LINE__, mfd->panel_power_state);
Krishna Manikandan695632e2020-03-04 20:50:28 +0530951 mdp3_res->secure_update_bl = false;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530952 panel = mdp3_session->panel;
953 /* make sure DSI host is initialized properly */
954 if (panel) {
955 pr_debug("%s : dsi host init, power state = %d Splash %d\n",
956 __func__, mfd->panel_power_state,
957 mdp3_session->in_splash_screen);
958 if (mdss_fb_is_power_on_lp(mfd) ||
959 mdp3_session->in_splash_screen) {
960 /* Turn on panel so that it can exit low power mode */
961 mdp3_clk_enable(1, 0);
Animesh Kishore6f7576b2019-03-11 16:51:14 +0530962 rc = panel->event_handler(panel,
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530963 MDSS_EVENT_LINK_READY, NULL);
Animesh Kishore6f7576b2019-03-11 16:51:14 +0530964 rc |= panel->event_handler(panel,
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530965 MDSS_EVENT_UNBLANK, NULL);
Animesh Kishore6f7576b2019-03-11 16:51:14 +0530966 rc |= panel->event_handler(panel,
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530967 MDSS_EVENT_PANEL_ON, NULL);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530968 mdp3_clk_enable(0, 0);
969 }
970 }
971
972 if (mdp3_session->status) {
973 pr_debug("fb%d is on already\n", mfd->index);
974 MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__, mfd->panel_power_state);
975 goto end;
976 }
977
978 if (mdp3_session->intf->active) {
979 pr_debug("continuous splash screen, initialized already\n");
980 mdp3_session->status = 1;
981 goto end;
982 }
983
984 /*
985 * Get a reference to the runtime pm device.
986 * If idle pc feature is enabled, it will be released
987 * at end of this routine else, when device is turned off.
988 */
989 pm_runtime_get_sync(&mdp3_res->pdev->dev);
990
991 /* Increment the overlay active count */
992 atomic_inc(&mdp3_res->active_intf_cnt);
993 mdp3_ctrl_notifier_register(mdp3_session,
994 &mdp3_session->mfd->mdp_sync_pt_data.notifier);
995
996 /* request bus bandwidth before DSI DMA traffic */
997 rc = mdp3_ctrl_res_req_bus(mfd, 1);
998 if (rc) {
999 pr_err("fail to request bus resource\n");
1000 goto on_error;
1001 }
1002
1003 rc = mdp3_dynamic_clock_gating_ctrl(0);
1004 if (rc) {
1005 pr_err("fail to disable dynamic clock gating\n");
1006 goto on_error;
1007 }
1008 mdp3_qos_remapper_setup(panel);
1009
1010 rc = mdp3_ctrl_res_req_clk(mfd, 1);
1011 if (rc) {
1012 pr_err("fail to request mdp clk resource\n");
1013 goto on_error;
1014 }
1015
1016 if (panel->event_handler) {
1017 rc = panel->event_handler(panel, MDSS_EVENT_LINK_READY, NULL);
1018 rc |= panel->event_handler(panel, MDSS_EVENT_UNBLANK, NULL);
1019 rc |= panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
1020 if (panel->panel_info.type == MIPI_CMD_PANEL) {
1021 struct dsi_panel_clk_ctrl clk_ctrl;
1022
1023 clk_ctrl.state = MDSS_DSI_CLK_ON;
1024 clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT;
1025 rc |= panel->event_handler(panel,
1026 MDSS_EVENT_PANEL_CLK_CTRL,
1027 (void *)&clk_ctrl);
1028 }
1029 }
1030 if (rc) {
1031 pr_err("fail to turn on the panel\n");
1032 goto on_error;
1033 }
1034
1035 rc = mdp3_ctrl_dma_init(mfd, mdp3_session->dma);
1036 if (rc) {
1037 pr_err("dma init failed\n");
1038 goto on_error;
1039 }
1040
1041 rc = mdp3_ppp_init();
1042 if (rc) {
1043 pr_err("ppp init failed\n");
1044 goto on_error;
1045 }
1046
1047 rc = mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
1048 if (rc) {
1049 pr_err("display interface init failed\n");
1050 goto on_error;
1051 }
1052 mdp3_session->clk_on = 1;
1053
1054 mdp3_session->first_commit = true;
1055 if (mfd->panel_info->panel_dead)
1056 mdp3_session->esd_recovery = true;
1057
1058 mdp3_session->status = 1;
1059
1060 mdp3_ctrl_pp_resume(mfd);
Abhijith Desaib502b282018-09-12 14:48:22 +05301061
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301062on_error:
1063 if (rc || (mdp3_res->idle_pc_enabled &&
1064 (mfd->panel_info->type == MIPI_CMD_PANEL))) {
1065 if (rc) {
1066 pr_err("Failed to turn on fb%d\n", mfd->index);
1067 atomic_dec(&mdp3_res->active_intf_cnt);
1068 }
1069 pm_runtime_put(&mdp3_res->pdev->dev);
1070 }
1071end:
Abhijith Desaib502b282018-09-12 14:48:22 +05301072 framerate = mdss_panel_get_framerate(mfd->panel_info,
1073 FPS_RESOLUTION_HZ);
1074 if (framerate != 0)
1075 mdp3_session->dma->vsync_period = DIV_ROUND_UP(1000, framerate);
1076
1077 MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__, mfd->panel_power_state, framerate);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301078 mutex_unlock(&mdp3_session->lock);
1079 return rc;
1080}
1081
Arun kumar162db222018-05-09 17:28:40 +05301082static bool mdp3_is_twm_en(void)
1083{
1084 return mdp3_res->twm_en;
1085}
1086
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301087static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
1088{
1089 int rc = 0;
Arun kumardb962812018-05-30 16:31:52 +05301090 int client = 0;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301091 bool intf_stopped = true;
1092 struct mdp3_session_data *mdp3_session;
1093 struct mdss_panel_data *panel;
Abhijith Desaib502b282018-09-12 14:48:22 +05301094 u32 framerate = 0;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301095
1096 pr_debug("mdp3_ctrl_off\n");
1097 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
1098 if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
1099 !mdp3_session->intf) {
1100 pr_err("mdp3_ctrl_on no device");
1101 return -ENODEV;
1102 }
1103
1104 /*
1105 * Keep a reference to the runtime pm until the overlay is turned
1106 * off, and then release this last reference at the end. This will
1107 * help in distinguishing between idle power collapse versus suspend
1108 * power collapse
1109 */
1110 pm_runtime_get_sync(&mdp3_res->pdev->dev);
1111
Animesh Kishore96d4f7e2018-11-26 17:53:53 +05301112 MDSS_XLOG(XLOG_FUNC_ENTRY, __LINE__, mdss_fb_is_power_on_lp(mfd),
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301113 mfd->panel_power_state);
1114 panel = mdp3_session->panel;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301115
Arun kumar04d4a922018-05-23 16:22:45 +05301116 cancel_work_sync(&mdp3_session->clk_off_work);
Arun kumarcefb7d12018-05-23 18:12:25 +05301117 mutex_lock(&mdp3_session->lock);
1118 MDSS_XLOG(0x111);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301119 pr_debug("Requested power state = %d\n", mfd->panel_power_state);
1120 if (mdss_fb_is_power_on_lp(mfd)) {
1121 /*
1122 * Transition to low power
1123 * As display updates are expected in low power mode,
1124 * keep the interface and clocks on.
1125 */
1126 intf_stopped = false;
1127 } else {
1128 /* Transition to display off */
1129 if (!mdp3_session->status) {
1130 pr_debug("fb%d is off already", mfd->index);
1131 goto off_error;
1132 }
Arun kumar162db222018-05-09 17:28:40 +05301133 if (panel && panel->set_backlight) {
1134 if (!mdp3_is_twm_en())
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301135 panel->set_backlight(panel, 0);
Arun kumar162db222018-05-09 17:28:40 +05301136 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301137 }
1138
1139 /*
1140 * While transitioning from interactive to low power,
1141 * events need to be sent to the interface so that the
1142 * panel can be configured in low power mode
1143 */
Arun kumaraa11bb22018-05-09 16:05:42 +05301144 if (!mdp3_is_twm_en()) {
1145 if (panel->event_handler)
1146 rc = panel->event_handler(panel, MDSS_EVENT_BLANK,
1147 (void *) (long int)mfd->panel_power_state);
1148 if (rc)
1149 pr_err("EVENT_BLANK error (%d)\n", rc);
1150 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301151 if (intf_stopped) {
1152 if (!mdp3_session->clk_on)
1153 mdp3_ctrl_clk_enable(mfd, 1);
1154 /* PP related programming for ctrl off */
1155 mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
1156 mutex_lock(&mdp3_session->dma->pp_lock);
1157 mdp3_session->dma->ccs_config.ccs_dirty = false;
1158 mdp3_session->dma->lut_config.lut_dirty = false;
1159 mutex_unlock(&mdp3_session->dma->pp_lock);
1160
1161 rc = mdp3_session->dma->stop(mdp3_session->dma,
1162 mdp3_session->intf);
1163 if (rc)
1164 pr_debug("fail to stop the MDP3 dma\n");
1165 /* Wait to ensure TG to turn off */
1166 msleep(20);
1167 mfd->panel_info->cont_splash_enabled = 0;
1168
1169 /* Disable Auto refresh once continuous splash disabled */
1170 mdp3_autorefresh_disable(mfd->panel_info);
1171 mdp3_splash_done(mfd->panel_info);
1172
1173 mdp3_irq_deregister();
1174 }
1175
Arun kumar162db222018-05-09 17:28:40 +05301176 if (panel->event_handler) {
Arun kumarec570b72018-05-09 20:23:38 +05301177 if (mdp3_is_twm_en()) {
1178 pr_info("TWM active skip panel off, disable disp_en\n");
1179 if (gpio_is_valid(panel->panel_en_gpio)) {
1180 rc = gpio_direction_output(
1181 panel->panel_en_gpio, 1);
1182 if (rc) {
1183 pr_err("%s:set dir for gpio(%d) FAIL\n",
1184 __func__, panel->panel_en_gpio);
1185 } else {
1186 gpio_set_value((panel->panel_en_gpio), 0);
1187 usleep_range(100, 110);
1188 pr_debug("%s:set disp_en_gpio_%d Low\n",
1189 __func__, panel->panel_en_gpio);
1190 }
1191 }
1192 } else {
Arun kumar162db222018-05-09 17:28:40 +05301193 rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF,
1194 (void *) (long int)mfd->panel_power_state);
Arun kumarec570b72018-05-09 20:23:38 +05301195 }
Arun kumar162db222018-05-09 17:28:40 +05301196 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301197 if (rc)
1198 pr_err("EVENT_PANEL_OFF error (%d)\n", rc);
1199
1200 if (intf_stopped) {
1201 if (mdp3_session->clk_on) {
1202 pr_debug("mdp3_ctrl_off stop clock\n");
1203 if (panel->event_handler &&
1204 (panel->panel_info.type == MIPI_CMD_PANEL)) {
1205 struct dsi_panel_clk_ctrl clk_ctrl;
1206
1207 clk_ctrl.state = MDSS_DSI_CLK_OFF;
1208 clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT;
1209 rc |= panel->event_handler(panel,
1210 MDSS_EVENT_PANEL_CLK_CTRL,
1211 (void *)&clk_ctrl);
1212 }
1213
1214 rc = mdp3_dynamic_clock_gating_ctrl(1);
1215 rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);
1216 if (rc)
1217 pr_err("mdp clock resource release failed\n");
1218 }
1219
1220 mdp3_ctrl_notifier_unregister(mdp3_session,
1221 &mdp3_session->mfd->mdp_sync_pt_data.notifier);
1222
1223 mdp3_session->vsync_enabled = 0;
1224 atomic_set(&mdp3_session->vsync_countdown, 0);
1225 atomic_set(&mdp3_session->dma_done_cnt, 0);
1226 mdp3_session->clk_on = 0;
1227 mdp3_session->in_splash_screen = 0;
1228 mdp3_res->solid_fill_vote_en = false;
1229 mdp3_session->status = 0;
1230 if (atomic_dec_return(&mdp3_res->active_intf_cnt) != 0) {
1231 pr_warn("active_intf_cnt unbalanced\n");
1232 atomic_set(&mdp3_res->active_intf_cnt, 0);
1233 }
1234 /*
1235 * Release the pm runtime reference held when
1236 * idle pc feature is not enabled
1237 */
1238 if (!mdp3_res->idle_pc_enabled ||
1239 (mfd->panel_info->type != MIPI_CMD_PANEL)) {
1240 rc = pm_runtime_put(&mdp3_res->pdev->dev);
1241 if (rc)
1242 pr_err("%s: pm_runtime_put failed (rc %d)\n",
1243 __func__, rc);
1244 }
Arun kumardb962812018-05-30 16:31:52 +05301245 client = mdp3_get_ion_client(mfd);
1246 mdp3_bufq_deinit(&mdp3_session->bufq_out, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301247 if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
1248 mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
Arun kumardb962812018-05-30 16:31:52 +05301249 mdp3_bufq_deinit(&mdp3_session->bufq_in, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301250 }
1251 }
1252
Animesh Kishore96d4f7e2018-11-26 17:53:53 +05301253 if (mdss_fb_is_power_on_lp(mfd) &&
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301254 (mfd->panel.type == MIPI_CMD_PANEL)) {
Animesh Kishore96d4f7e2018-11-26 17:53:53 +05301255 pr_debug("%s: Disable MDP3 clocks in LP\n", __func__);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301256 if (!mdp3_session->clk_on)
1257 mdp3_ctrl_clk_enable(mfd, 1);
1258 /*
1259 * STOP DMA transfer first and signal vsync notification
1260 * Before releasing the resource in ULP state.
1261 */
1262 rc = mdp3_session->dma->stop(mdp3_session->dma,
1263 mdp3_session->intf);
1264 if (rc)
Animesh Kishore96d4f7e2018-11-26 17:53:53 +05301265 pr_warn("fail to stop the MDP3 dma in LP\n");
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301266 /* Wait to ensure TG to turn off */
1267 msleep(20);
1268 /*
1269 * Handle ULP request initiated from fb_pm_suspend.
1270 * For ULP panel power state disabling vsync and set
1271 * vsync_count to zero and Turn off MDP3 clocks
1272 */
1273 atomic_set(&mdp3_session->vsync_countdown, 0);
1274 mdp3_session->vsync_enabled = 0;
1275 mdp3_ctrl_vsync_enable(mdp3_session->mfd, 0);
1276 mdp3_ctrl_clk_enable(mdp3_session->mfd, 0);
1277 }
1278off_error:
Arun kumardb962812018-05-30 16:31:52 +05301279 if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
1280 mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
1281 mdp3_bufq_deinit(&mdp3_session->bufq_in, client);
1282 }
Abhijith Desaib502b282018-09-12 14:48:22 +05301283
1284 framerate = mdss_panel_get_framerate(mfd->panel_info,
1285 FPS_RESOLUTION_HZ);
1286 if (framerate != 0)
1287 mdp3_session->dma->vsync_period = DIV_ROUND_UP(1000, framerate);
1288
1289 MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__, framerate);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301290 mutex_unlock(&mdp3_session->lock);
1291 /* Release the last reference to the runtime device */
1292 pm_runtime_put(&mdp3_res->pdev->dev);
1293
1294 return 0;
1295}
1296
1297int mdp3_ctrl_reset(struct msm_fb_data_type *mfd)
1298{
1299 int rc = 0;
1300 struct mdp3_session_data *mdp3_session;
1301 struct mdp3_dma *mdp3_dma;
1302 struct mdss_panel_data *panel;
1303 struct mdp3_notification vsync_client;
1304
1305 pr_debug("mdp3_ctrl_reset\n");
1306 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
1307 if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
1308 !mdp3_session->intf) {
1309 pr_err("mdp3_ctrl_reset no device");
1310 return -ENODEV;
1311 }
1312
1313 panel = mdp3_session->panel;
1314 mdp3_dma = mdp3_session->dma;
1315 mutex_lock(&mdp3_session->lock);
1316 pr_debug("mdp3_ctrl_reset idle_pc %s FS_EN %s\n",
1317 mdp3_res->idle_pc ? "True":"False",
1318 mdp3_res->fs_ena ? "True":"False");
1319 if (mdp3_res->idle_pc) {
1320 mdp3_clk_enable(1, 0);
1321 mdp3_dynamic_clock_gating_ctrl(0);
1322 mdp3_qos_remapper_setup(panel);
1323 }
1324
1325 /*Map the splash addr for VIDEO mode panel before smmu attach*/
1326 if ((mfd->panel.type == MIPI_VIDEO_PANEL) &&
1327 (mdp3_session->in_splash_screen)) {
1328 rc = mdss_smmu_map(MDSS_IOMMU_DOMAIN_UNSECURE,
1329 mdp3_res->splash_mem_addr,
1330 mdp3_res->splash_mem_addr,
1331 mdp3_res->splash_mem_size,
1332 IOMMU_READ | IOMMU_NOEXEC);
1333 }
1334
1335 rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
1336 if (rc) {
1337 pr_err("fail to attach dma iommu\n");
1338 if (mdp3_res->idle_pc)
1339 mdp3_clk_enable(0, 0);
1340 goto reset_error;
1341 }
1342
1343 vsync_client = mdp3_dma->vsync_client;
1344
1345 mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
1346 mdp3_ctrl_dma_init(mfd, mdp3_dma);
1347 mdp3_ppp_init();
1348 mdp3_ctrl_pp_resume(mfd);
1349 if (vsync_client.handler)
1350 mdp3_dma->vsync_enable(mdp3_dma, &vsync_client);
1351
1352 if (!mdp3_res->idle_pc) {
1353 mdp3_session->first_commit = true;
1354 mfd->panel_info->cont_splash_enabled = 0;
1355 mdp3_session->in_splash_screen = 0;
1356 mdp3_splash_done(mfd->panel_info);
1357 /* Disable Auto refresh */
1358 mdp3_autorefresh_disable(mfd->panel_info);
1359 } else {
1360 mdp3_res->idle_pc = false;
1361 mdp3_clk_enable(0, 0);
1362 mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
1363 }
1364
1365reset_error:
1366 mutex_unlock(&mdp3_session->lock);
1367 return rc;
1368}
1369
1370static int mdp3_overlay_get(struct msm_fb_data_type *mfd,
1371 struct mdp_overlay *req)
1372{
1373 int rc = 0;
1374 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1375
1376 mutex_lock(&mdp3_session->lock);
1377
1378 if (mdp3_session->overlay.id == req->id)
1379 *req = mdp3_session->overlay;
1380 else
1381 rc = -EINVAL;
1382
1383 mutex_unlock(&mdp3_session->lock);
1384
1385 return rc;
1386}
1387
1388static int mdp3_overlay_set(struct msm_fb_data_type *mfd,
1389 struct mdp_overlay *req)
1390{
1391 int rc = 0;
1392 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1393 struct mdp3_dma *dma = mdp3_session->dma;
1394 struct fb_fix_screeninfo *fix;
1395 struct fb_info *fbi = mfd->fbi;
1396 int stride;
1397 int format;
1398
1399 fix = &fbi->fix;
1400 stride = req->src.width * ppp_bpp(req->src.format);
1401 format = mdp3_ctrl_get_source_format(req->src.format);
1402
1403
1404 if (mdp3_session->overlay.id != req->id)
1405 pr_err("overlay was not released, continue to recover\n");
1406 /*
1407 * A change in overlay structure will always come with
1408 * MSMFB_NEW_REQUEST for MDP3
1409 */
1410 if (req->id == MSMFB_NEW_REQUEST) {
1411 mutex_lock(&mdp3_session->lock);
1412 if (dma->source_config.stride != stride ||
1413 dma->source_config.format != format) {
1414 dma->source_config.format = format;
1415 dma->source_config.stride = stride;
1416 dma->output_config.pack_pattern =
1417 mdp3_ctrl_get_pack_pattern(req->src.format);
1418 dma->update_src_cfg = true;
1419 }
1420 mdp3_session->overlay = *req;
1421 mdp3_session->overlay.id = 1;
1422 req->id = 1;
1423 mutex_unlock(&mdp3_session->lock);
1424 }
1425
1426 return rc;
1427}
1428
1429static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
1430{
1431 int rc = 0;
1432 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1433 struct fb_info *fbi = mfd->fbi;
1434 struct fb_fix_screeninfo *fix;
1435 int format;
Arun kumardb962812018-05-30 16:31:52 +05301436 int client;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301437
1438 fix = &fbi->fix;
1439 format = mdp3_ctrl_get_source_format(mfd->fb_imgType);
1440 mutex_lock(&mdp3_session->lock);
1441
Arun kumardb962812018-05-30 16:31:52 +05301442 client = mdp3_get_ion_client(mfd);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301443 if (mdp3_session->overlay.id == ndx && ndx == 1) {
1444 mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
Arun kumardb962812018-05-30 16:31:52 +05301445 mdp3_bufq_deinit(&mdp3_session->bufq_in, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301446 } else {
1447 rc = -EINVAL;
1448 }
1449
1450 mutex_unlock(&mdp3_session->lock);
1451
1452 return rc;
1453}
1454
1455static int mdp3_overlay_queue_buffer(struct msm_fb_data_type *mfd,
1456 struct msmfb_overlay_data *req)
1457{
1458 int rc;
1459 bool is_panel_type_cmd = false;
1460 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1461 struct msmfb_data *img = &req->data;
1462 struct mdp3_img_data data;
1463 struct mdp3_dma *dma = mdp3_session->dma;
Arun kumardb962812018-05-30 16:31:52 +05301464 int client;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301465
Arun kumardb962812018-05-30 16:31:52 +05301466 client = mdp3_get_ion_client(mfd);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301467 memset(&data, 0, sizeof(struct mdp3_img_data));
Arun kumardb962812018-05-30 16:31:52 +05301468 if (mfd->panel.type == MIPI_CMD_PANEL || client == MDP3_CLIENT_SPI)
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301469 is_panel_type_cmd = true;
1470 if (is_panel_type_cmd) {
Arun kumardb962812018-05-30 16:31:52 +05301471 rc = mdp3_iommu_enable(client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301472 if (rc) {
1473 pr_err("fail to enable iommu\n");
1474 return rc;
1475 }
1476 }
Arun kumardb962812018-05-30 16:31:52 +05301477 rc = mdp3_get_img(img, &data, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301478 if (rc) {
1479 pr_err("fail to get overlay buffer\n");
1480 goto err;
1481 }
1482
1483 if (data.len < dma->source_config.stride * dma->source_config.height) {
1484 pr_err("buf size(0x%lx) is smaller than dma config(0x%x)\n",
1485 data.len, (dma->source_config.stride *
1486 dma->source_config.height));
Arun kumardb962812018-05-30 16:31:52 +05301487 mdp3_put_img(&data, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301488 rc = -EINVAL;
1489 goto err;
1490 }
1491 rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data);
1492 if (rc) {
1493 pr_err("fail to queue the overlay buffer, buffer drop\n");
Arun kumardb962812018-05-30 16:31:52 +05301494 mdp3_put_img(&data, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301495 goto err;
1496 }
1497 rc = 0;
1498err:
1499 if (is_panel_type_cmd)
1500 mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
1501 return rc;
1502}
1503
1504static int mdp3_overlay_play(struct msm_fb_data_type *mfd,
1505 struct msmfb_overlay_data *req)
1506{
1507 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1508 int rc = 0;
1509
1510 pr_debug("mdp3_overlay_play req id=%x mem_id=%d\n",
1511 req->id, req->data.memory_id);
1512
1513 mutex_lock(&mdp3_session->lock);
1514
1515 if (mdp3_session->overlay.id == MSMFB_NEW_REQUEST) {
1516 pr_err("overlay play without overlay set first\n");
1517 mutex_unlock(&mdp3_session->lock);
1518 return -EINVAL;
1519 }
1520
1521 if (mdss_fb_is_power_on(mfd))
1522 rc = mdp3_overlay_queue_buffer(mfd, req);
1523 else
1524 rc = -EPERM;
1525
1526 mutex_unlock(&mdp3_session->lock);
1527
1528 return rc;
1529}
1530
1531bool update_roi(struct mdp3_rect oldROI, struct mdp_rect newROI)
1532{
1533 return ((newROI.x != oldROI.x) || (newROI.y != oldROI.y) ||
1534 (newROI.w != oldROI.w) || (newROI.h != oldROI.h));
1535}
1536
1537bool is_roi_valid(struct mdp3_dma_source source_config, struct mdp_rect roi)
1538{
1539 return (roi.w > 0) && (roi.h > 0) &&
1540 (roi.x >= source_config.x) &&
1541 ((roi.x + roi.w) <= source_config.width) &&
1542 (roi.y >= source_config.y) &&
1543 ((roi.y + roi.h) <= source_config.height);
1544}
1545
1546static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd,
1547 struct mdp_display_commit *cmt_data)
1548{
1549 struct mdp3_session_data *mdp3_session;
1550 struct mdp3_img_data *data;
1551 struct mdss_panel_info *panel_info;
1552 int rc = 0;
Arun kumardb962812018-05-30 16:31:52 +05301553 int client;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301554 static bool splash_done;
1555 struct mdss_panel_data *panel;
Arun kumardb962812018-05-30 16:31:52 +05301556 int frame_rate = DEFAULT_FRAME_RATE;
1557 int stride;
Abhijith Desai49898e72018-09-11 16:03:34 +05301558 int prev_bl;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301559
1560 if (!mfd || !mfd->mdp.private1)
1561 return -EINVAL;
1562
1563 panel_info = mfd->panel_info;
1564 mdp3_session = mfd->mdp.private1;
1565 if (!mdp3_session || !mdp3_session->dma)
1566 return -EINVAL;
1567
Arun kumardb962812018-05-30 16:31:52 +05301568 frame_rate = mdss_panel_get_framerate(panel_info, FPS_RESOLUTION_HZ);
1569 client = mdp3_get_ion_client(mfd);
1570
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301571 if (mdp3_bufq_count(&mdp3_session->bufq_in) == 0) {
1572 pr_debug("no buffer in queue yet\n");
1573 return -EPERM;
1574 }
1575
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301576 panel = mdp3_session->panel;
1577 mutex_lock(&mdp3_res->fs_idle_pc_lock);
1578 if (mdp3_session->in_splash_screen ||
1579 mdp3_res->idle_pc) {
1580 pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__,
1581 mdp3_session->in_splash_screen, mdp3_res->idle_pc);
1582 rc = mdp3_ctrl_reset(mfd);
1583 if (rc) {
1584 pr_err("fail to reset display\n");
1585 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
1586 return -EINVAL;
1587 }
Abhijith Desaib7dabd92018-09-11 17:07:19 +05301588 if ((mdp3_session->dma->roi.x || mdp3_session->dma->roi.y) &&
1589 panel_info->partial_update_enabled)
1590 mdp3_session->dma->update_src_cfg = true;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301591 }
1592 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
1593
Arun kumarcefb7d12018-05-23 18:12:25 +05301594 cancel_work_sync(&mdp3_session->clk_off_work);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301595 mutex_lock(&mdp3_session->lock);
1596
1597 if (!mdp3_session->status) {
1598 pr_err("%s, display off!\n", __func__);
1599 mutex_unlock(&mdp3_session->lock);
1600 return -EPERM;
1601 }
Abhijith Desaib502b282018-09-12 14:48:22 +05301602 MDSS_XLOG(0x111, mdp3_session->dma->vsync_period);
1603
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301604 mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
1605 data = mdp3_bufq_pop(&mdp3_session->bufq_in);
1606 if (data) {
1607 mdp3_ctrl_reset_countdown(mdp3_session, mfd);
1608 mdp3_ctrl_clk_enable(mfd, 1);
Arun kumardb962812018-05-30 16:31:52 +05301609 stride = mdp3_session->dma->source_config.stride;
1610 if (mdp3_ctrl_get_intf_type(mfd) ==
1611 MDP3_DMA_OUTPUT_SEL_SPI_CMD){
1612 mdp3_session->intf->active = false;
1613 msm_ion_do_cache_op(mdp3_res->ion_client,
1614 data->srcp_ihdl, (void *)(int)data->addr,
1615 data->len, ION_IOC_INV_CACHES);
1616 rc = mdss_spi_panel_kickoff(mdp3_session->panel,
1617 (void *)(int)data->addr, (int)data->len,
1618 stride);
1619 } else if (mdp3_session->dma->update_src_cfg &&
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301620 panel_info->partial_update_enabled) {
1621 panel->panel_info.roi.x = mdp3_session->dma->roi.x;
1622 panel->panel_info.roi.y = mdp3_session->dma->roi.y;
1623 panel->panel_info.roi.w = mdp3_session->dma->roi.w;
1624 panel->panel_info.roi.h = mdp3_session->dma->roi.h;
1625 rc = mdp3_session->dma->update(mdp3_session->dma,
1626 (void *)(int)data->addr,
1627 mdp3_session->intf, (void *)panel);
1628 } else {
1629 rc = mdp3_session->dma->update(mdp3_session->dma,
1630 (void *)(int)data->addr,
1631 mdp3_session->intf, NULL);
1632 }
1633 /* This is for the previous frame */
1634 if (rc < 0) {
1635 mdp3_ctrl_notify(mdp3_session,
1636 MDP_NOTIFY_FRAME_TIMEOUT);
1637 } else {
1638 if (mdp3_ctrl_get_intf_type(mfd) ==
Arun kumardb962812018-05-30 16:31:52 +05301639 MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
1640 mdp3_ctrl_get_intf_type(mfd) ==
1641 MDP3_DMA_OUTPUT_SEL_SPI_CMD) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301642 mdp3_ctrl_notify(mdp3_session,
1643 MDP_NOTIFY_FRAME_DONE);
1644 }
1645 }
1646 mdp3_session->dma_active = 1;
Arun kumar52b7f182018-05-23 15:12:27 +05301647 reinit_completion(&mdp3_session->dma_completion);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301648 mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
1649 mdp3_bufq_push(&mdp3_session->bufq_out, data);
1650 }
1651
1652 if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
1653 mdp3_release_splash_memory(mfd);
1654 data = mdp3_bufq_pop(&mdp3_session->bufq_out);
1655 if (data)
Arun kumardb962812018-05-30 16:31:52 +05301656 mdp3_put_img(data, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301657 }
1658
1659 if (mdp3_session->first_commit) {
1660 /*wait to ensure frame is sent to panel*/
1661 if (panel_info->mipi.post_init_delay)
Arun kumardb962812018-05-30 16:31:52 +05301662 msleep(((1000 / frame_rate) + 1) *
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301663 panel_info->mipi.post_init_delay);
1664 else
Arun kumardb962812018-05-30 16:31:52 +05301665 msleep((1000 / frame_rate) + 1);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301666 mdp3_session->first_commit = false;
1667 if (panel)
1668 rc |= panel->event_handler(panel,
1669 MDSS_EVENT_POST_PANEL_ON, NULL);
1670 }
1671
1672 mdp3_session->vsync_before_commit = 0;
Abhijith Desai49898e72018-09-11 16:03:34 +05301673 prev_bl = mfd->bl_level;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301674 if (!splash_done || mdp3_session->esd_recovery == true) {
Abhijith Desai49898e72018-09-11 16:03:34 +05301675 if (panel && panel->set_backlight) {
1676 if (mdp3_session->esd_recovery == true && prev_bl > 0)
1677 panel->set_backlight(panel, prev_bl);
1678 else
1679 panel->set_backlight(panel,
1680 panel->panel_info.bl_max);
1681 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301682 splash_done = true;
1683 mdp3_session->esd_recovery = false;
1684 }
1685
Arun kumardb962812018-05-30 16:31:52 +05301686 /*Update backlight only if its changed*/
1687 if (mdp3_res->bklt_level && mdp3_res->bklt_update) {
1688 mdss_spi_panel_bl_ctrl_update(panel, mdp3_res->bklt_level);
1689 mdp3_res->bklt_update = false;
1690 }
1691
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301692 /* start vsync tick countdown for cmd mode if vsync isn't enabled */
1693 if (mfd->panel.type == MIPI_CMD_PANEL && !mdp3_session->vsync_enabled)
1694 mdp3_ctrl_vsync_enable(mdp3_session->mfd, 0);
1695
1696 mutex_unlock(&mdp3_session->lock);
1697
1698 mdss_fb_update_notify_update(mfd);
1699
1700 return 0;
1701}
1702
1703static int mdp3_map_pan_buff_immediate(struct msm_fb_data_type *mfd)
1704{
1705 int rc = 0;
1706 unsigned long length;
1707 dma_addr_t addr;
1708 int domain = mfd->mdp.fb_mem_get_iommu_domain();
1709
1710 rc = mdss_smmu_map_dma_buf(mfd->fbmem_buf, mfd->fb_table, domain,
1711 &addr, &length, DMA_BIDIRECTIONAL);
1712 if (IS_ERR_VALUE(rc))
1713 goto err_unmap;
1714 else
1715 mfd->iova = addr;
1716
1717 pr_debug("%s : smmu map dma buf VA: (%llx) MFD->iova %llx\n",
1718 __func__, (u64) addr, (u64) mfd->iova);
1719 return rc;
1720
1721err_unmap:
1722 pr_err("smmu map dma buf failed: (%d)\n", rc);
1723 dma_buf_unmap_attachment(mfd->fb_attachment, mfd->fb_table,
1724 mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL));
1725 dma_buf_detach(mfd->fbmem_buf, mfd->fb_attachment);
1726 dma_buf_put(mfd->fbmem_buf);
1727 return rc;
1728}
1729
1730static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
1731{
1732 struct fb_info *fbi;
1733 struct mdp3_session_data *mdp3_session;
1734 u32 offset;
1735 int bpp;
1736 struct mdss_panel_info *panel_info;
1737 static bool splash_done;
1738 struct mdss_panel_data *panel;
1739
1740 int rc;
1741
1742 pr_debug("mdp3_ctrl_pan_display\n");
1743 if (!mfd || !mfd->mdp.private1)
1744 return;
1745
1746 panel_info = mfd->panel_info;
1747 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
1748 if (!mdp3_session || !mdp3_session->dma)
1749 return;
1750
1751 mutex_lock(&mdp3_res->fs_idle_pc_lock);
1752 if (mdp3_session->in_splash_screen ||
1753 mdp3_res->idle_pc) {
1754 pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__,
1755 mdp3_session->in_splash_screen, mdp3_res->idle_pc);
1756 rc = mdp3_ctrl_reset(mfd);
1757 if (rc) {
1758 pr_err("fail to reset display\n");
1759 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
1760 return;
1761 }
1762 }
1763 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
1764
1765 mutex_lock(&mdp3_session->lock);
1766
1767 if (!mdp3_session->status) {
1768 pr_err("mdp3_ctrl_pan_display, display off!\n");
1769 goto pan_error;
1770 }
1771
1772 fbi = mfd->fbi;
1773
1774 bpp = fbi->var.bits_per_pixel / 8;
1775 offset = fbi->var.xoffset * bpp +
1776 fbi->var.yoffset * fbi->fix.line_length;
1777
1778 if (offset > fbi->fix.smem_len) {
1779 pr_err("invalid fb offset=%u total length=%u\n",
1780 offset, fbi->fix.smem_len);
1781 goto pan_error;
1782 }
1783
1784 if (mfd->fbi->screen_base) {
1785 mdp3_ctrl_reset_countdown(mdp3_session, mfd);
1786 mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
1787 mdp3_ctrl_clk_enable(mfd, 1);
1788 if (mdp3_session->first_commit) {
1789 rc = mdp3_map_pan_buff_immediate(mfd);
1790 if (IS_ERR_VALUE(rc))
1791 goto pan_error;
1792 }
1793 rc = mdp3_session->dma->update(mdp3_session->dma,
1794 (void *)(int)(mfd->iova + offset),
1795 mdp3_session->intf, NULL);
1796 /* This is for the previous frame */
1797 if (rc < 0) {
1798 mdp3_ctrl_notify(mdp3_session,
1799 MDP_NOTIFY_FRAME_TIMEOUT);
1800 } else {
1801 if (mdp3_ctrl_get_intf_type(mfd) ==
1802 MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
1803 mdp3_ctrl_notify(mdp3_session,
1804 MDP_NOTIFY_FRAME_DONE);
1805 }
1806 }
1807 mdp3_session->dma_active = 1;
Arun kumar52b7f182018-05-23 15:12:27 +05301808 reinit_completion(&mdp3_session->dma_completion);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301809 mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
1810 } else {
1811 pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
1812 mdp3_clk_enable(1, 0);
1813 mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
1814 mdp3_clk_enable(0, 0);
1815 }
1816
1817 panel = mdp3_session->panel;
Arun kumardb962812018-05-30 16:31:52 +05301818 if (mdp3_ctrl_get_intf_type(mfd) != MDP3_DMA_OUTPUT_SEL_SPI_CMD) {
1819 if (mdp3_session->first_commit) {
1820 if (panel_info->mipi.init_delay)
1821 msleep(((1000 / panel_info->mipi.frame_rate)
1822 + 1) * panel_info->mipi.post_init_delay);
1823 else
1824 msleep(1000 / panel_info->mipi.frame_rate);
1825 mdp3_session->first_commit = false;
1826 if (panel)
1827 panel->event_handler(panel,
1828 MDSS_EVENT_POST_PANEL_ON, NULL);
1829 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301830 }
1831
1832 mdp3_session->vsync_before_commit = 0;
1833 if (!splash_done || mdp3_session->esd_recovery == true) {
Venkata Prahlad Valluru727b9a32020-03-13 17:28:45 +05301834 if (panel && panel->set_backlight) {
1835 if (mfd->bl_level > 0)
1836 panel->set_backlight(panel, mfd->bl_level);
1837 else
1838 panel->set_backlight(panel,
1839 panel->panel_info.bl_max);
1840 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301841 splash_done = true;
1842 mdp3_session->esd_recovery = false;
1843 }
1844
Arun kumardb962812018-05-30 16:31:52 +05301845 /*Update backlight only if its changed*/
1846 if (mdp3_res->bklt_level && mdp3_res->bklt_update) {
1847 mdss_spi_panel_bl_ctrl_update(panel, mdp3_res->bklt_level);
1848 mdp3_res->bklt_update = false;
1849 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301850
1851pan_error:
1852 mutex_unlock(&mdp3_session->lock);
1853}
1854
1855static int mdp3_set_metadata(struct msm_fb_data_type *mfd,
1856 struct msmfb_metadata *metadata_ptr)
1857{
1858 int ret = 0;
1859
1860 switch (metadata_ptr->op) {
1861 case metadata_op_crc:
1862 ret = mdp3_ctrl_res_req_clk(mfd, 1);
1863 if (ret) {
1864 pr_err("failed to turn on mdp clks\n");
1865 return ret;
1866 }
1867 ret = mdp3_misr_set(&metadata_ptr->data.misr_request);
1868 ret = mdp3_ctrl_res_req_clk(mfd, 0);
1869 if (ret) {
1870 pr_err("failed to release mdp clks\n");
1871 return ret;
1872 }
1873 break;
Krishna Manikandan695632e2020-03-04 20:50:28 +05301874 case metadata_op_secure_bl_set:
1875 if (mdss_panel_is_power_off(mfd->panel_power_state) &&
1876 mfd->panel.type == SPI_PANEL) {
1877 mfd->allow_secure_bl_update =
1878 metadata_ptr->data.sec_bl_update_en;
1879 mdp3_res->secure_update_bl =
1880 mfd->allow_secure_bl_update;
1881 }
1882 pr_debug("Secure backlight = %d,panel power state = %d\n",
1883 mfd->allow_secure_bl_update, mfd->panel_power_state);
1884 break;
1885 case metadata_op_secure_reg:
1886 if (mfd->panel.type == SPI_PANEL) {
1887 mdp3_res->secure_reg_on = metadata_ptr->data.sec_reg_on;
1888 pr_debug("Secure regulator_on flag is %d\n",
1889 mdp3_res->secure_reg_on);
1890 }
1891 break;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301892 default:
1893 pr_warn("Unsupported request to MDP SET META IOCTL.\n");
1894 ret = -EINVAL;
1895 break;
1896 }
1897 return ret;
1898}
1899
1900static int mdp3_get_metadata(struct msm_fb_data_type *mfd,
1901 struct msmfb_metadata *metadata)
1902{
1903 int ret = 0;
1904
1905 switch (metadata->op) {
1906 case metadata_op_frame_rate:
1907 metadata->data.panel_frame_rate =
Arun kumardb962812018-05-30 16:31:52 +05301908 mdss_panel_get_framerate(mfd->panel_info,
1909 FPS_RESOLUTION_HZ);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301910 break;
1911 case metadata_op_get_caps:
1912 metadata->data.caps.mdp_rev = 305;
1913 metadata->data.caps.rgb_pipes = 0;
1914 metadata->data.caps.vig_pipes = 0;
1915 metadata->data.caps.dma_pipes = 1;
1916 break;
1917 case metadata_op_crc:
1918 ret = mdp3_ctrl_res_req_clk(mfd, 1);
1919 if (ret) {
1920 pr_err("failed to turn on mdp clks\n");
1921 return ret;
1922 }
1923 ret = mdp3_misr_get(&metadata->data.misr_request);
1924 ret = mdp3_ctrl_res_req_clk(mfd, 0);
1925 if (ret) {
1926 pr_err("failed to release mdp clks\n");
1927 return ret;
1928 }
1929 break;
1930 case metadata_op_get_ion_fd:
Sachin Bhayaref4932612018-04-03 20:09:12 +05301931 if (mfd->fb_ion_handle && mfd->fb_ion_client) {
Sachin Bhayare5fb6b9b2018-04-12 18:57:52 +05301932 get_dma_buf(mfd->fbmem_buf);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301933 metadata->data.fbmem_ionfd =
Sachin Bhayaref4932612018-04-03 20:09:12 +05301934 ion_share_dma_buf_fd(mfd->fb_ion_client,
1935 mfd->fb_ion_handle);
Sachin Bhayare5fb6b9b2018-04-12 18:57:52 +05301936 if (metadata->data.fbmem_ionfd < 0) {
1937 dma_buf_put(mfd->fbmem_buf);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301938 pr_err("fd allocation failed. fd = %d\n",
Sachin Bhayare5fb6b9b2018-04-12 18:57:52 +05301939 metadata->data.fbmem_ionfd);
1940 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301941 }
1942 break;
1943 default:
1944 pr_warn("Unsupported request to MDP GET META IOCTL.\n");
1945 ret = -EINVAL;
1946 break;
1947 }
1948 return ret;
1949}
1950
1951int mdp3_validate_start_req(struct mdp_histogram_start_req *req)
1952{
1953 if (req->frame_cnt >= MDP_HISTOGRAM_FRAME_COUNT_MAX) {
1954 pr_err("%s invalid req frame_cnt\n", __func__);
1955 return -EINVAL;
1956 }
1957 if (req->bit_mask >= MDP_HISTOGRAM_BIT_MASK_MAX) {
1958 pr_err("%s invalid req bit mask\n", __func__);
1959 return -EINVAL;
1960 }
1961 if (req->block != MDP_BLOCK_DMA_P ||
1962 req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
1963 pr_err("mdp3_histogram_start invalid request\n");
1964 return -EINVAL;
1965 }
1966 return 0;
1967}
1968
1969int mdp3_validate_scale_config(struct mdp_bl_scale_data *data)
1970{
1971 if (data->scale > MDP_HISTOGRAM_BL_SCALE_MAX) {
1972 pr_err("%s invalid bl_scale\n", __func__);
1973 return -EINVAL;
1974 }
1975 if (data->min_lvl > MDP_HISTOGRAM_BL_LEVEL_MAX) {
1976 pr_err("%s invalid bl_min_lvl\n", __func__);
1977 return -EINVAL;
1978 }
1979 return 0;
1980}
1981
1982int mdp3_validate_csc_data(struct mdp_csc_cfg_data *data)
1983{
1984 int i;
1985 bool mv_valid = false;
1986
1987 for (i = 0; i < 9; i++) {
1988 if (data->csc_data.csc_mv[i] >=
1989 MDP_HISTOGRAM_CSC_MATRIX_MAX)
1990 return -EINVAL;
1991 if ((!mv_valid) && (data->csc_data.csc_mv[i] != 0))
1992 mv_valid = true;
1993 }
1994 if (!mv_valid) {
1995 pr_err("%s: black screen data! csc_mv is all 0s\n", __func__);
1996 return -EINVAL;
1997 }
1998 for (i = 0; i < 3; i++) {
1999 if (data->csc_data.csc_pre_bv[i] >=
2000 MDP_HISTOGRAM_CSC_VECTOR_MAX)
2001 return -EINVAL;
2002 if (data->csc_data.csc_post_bv[i] >=
2003 MDP_HISTOGRAM_CSC_VECTOR_MAX)
2004 return -EINVAL;
2005 }
2006 for (i = 0; i < 6; i++) {
2007 if (data->csc_data.csc_pre_lv[i] >=
2008 MDP_HISTOGRAM_CSC_VECTOR_MAX)
2009 return -EINVAL;
2010 if (data->csc_data.csc_post_lv[i] >=
2011 MDP_HISTOGRAM_CSC_VECTOR_MAX)
2012 return -EINVAL;
2013 }
2014 return 0;
2015}
2016
2017static int mdp3_histogram_start(struct mdp3_session_data *session,
2018 struct mdp_histogram_start_req *req)
2019{
2020 int ret;
2021 struct mdp3_dma_histogram_config histo_config;
2022
2023 mutex_lock(&session->lock);
2024 if (!session->status) {
2025 mutex_unlock(&session->lock);
2026 return -EPERM;
2027 }
2028
2029 pr_debug("mdp3_histogram_start\n");
2030
2031 ret = mdp3_validate_start_req(req);
2032 if (ret) {
2033 mutex_unlock(&session->lock);
2034 return ret;
2035 }
2036
2037 if (!session->dma->histo_op ||
2038 !session->dma->config_histo) {
2039 pr_err("mdp3_histogram_start not supported\n");
2040 mutex_unlock(&session->lock);
2041 return -EINVAL;
2042 }
2043
2044 mutex_lock(&session->histo_lock);
2045
2046 if (session->histo_status) {
2047 pr_info("mdp3_histogram_start already started\n");
2048 mutex_unlock(&session->histo_lock);
2049 mutex_unlock(&session->lock);
2050 return 0;
2051 }
2052
2053 mdp3_res_update(1, 0, MDP3_CLIENT_DMA_P);
2054 ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_RESET);
2055 if (ret) {
2056 pr_err("mdp3_histogram_start reset error\n");
2057 goto histogram_start_err;
2058 }
2059
2060 histo_config.frame_count = req->frame_cnt;
2061 histo_config.bit_mask = req->bit_mask;
2062 histo_config.auto_clear_en = 1;
2063 histo_config.bit_mask_polarity = 0;
2064 ret = session->dma->config_histo(session->dma, &histo_config);
2065 if (ret) {
2066 pr_err("mdp3_histogram_start config error\n");
2067 goto histogram_start_err;
2068 }
2069
2070 ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_START);
2071 if (ret) {
2072 pr_err("mdp3_histogram_start config error\n");
2073 goto histogram_start_err;
2074 }
2075
2076 session->histo_status = 1;
2077
2078histogram_start_err:
2079 mdp3_res_update(0, 0, MDP3_CLIENT_DMA_P);
2080 mutex_unlock(&session->histo_lock);
2081 mutex_unlock(&session->lock);
2082 return ret;
2083}
2084
2085static int mdp3_histogram_stop(struct mdp3_session_data *session,
2086 u32 block)
2087{
2088 int ret;
2089
2090 pr_debug("mdp3_histogram_stop\n");
2091
2092 if (!session->dma->histo_op || block != MDP_BLOCK_DMA_P) {
2093 pr_err("mdp3_histogram_stop not supported\n");
2094 return -EINVAL;
2095 }
2096
2097 mutex_lock(&session->histo_lock);
2098
2099 if (!session->histo_status) {
2100 pr_debug("mdp3_histogram_stop already stopped!");
2101 ret = 0;
2102 goto histogram_stop_err;
2103 }
2104
2105 mdp3_clk_enable(1, 0);
2106 ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_CANCEL);
2107 mdp3_clk_enable(0, 0);
2108 if (ret)
2109 pr_err("mdp3_histogram_stop error\n");
2110
2111 session->histo_status = 0;
2112
2113histogram_stop_err:
2114 mutex_unlock(&session->histo_lock);
2115 return ret;
2116}
2117
2118static int mdp3_histogram_collect(struct mdp3_session_data *session,
2119 struct mdp_histogram_data *hist)
2120{
2121 int ret;
2122 struct mdp3_dma_histogram_data *mdp3_histo;
2123
2124 pr_debug("%s\n", __func__);
2125 if (!session->dma->get_histo) {
2126 pr_err("mdp3_histogram_collect not supported\n");
2127 return -EINVAL;
2128 }
2129
2130 mutex_lock(&session->histo_lock);
2131
2132 if (!session->histo_status) {
2133 pr_debug("mdp3_histogram_collect not started\n");
2134 mutex_unlock(&session->histo_lock);
2135 return -EPROTO;
2136 }
2137
2138 mutex_unlock(&session->histo_lock);
2139
2140 if (!session->clk_on) {
2141 pr_debug("mdp/dsi clock off currently\n");
2142 return -EPERM;
2143 }
2144
2145 mdp3_clk_enable(1, 0);
2146 ret = session->dma->get_histo(session->dma);
2147 mdp3_clk_enable(0, 0);
2148 if (ret) {
2149 pr_debug("mdp3_histogram_collect error = %d\n", ret);
2150 return ret;
2151 }
2152
2153 mdp3_histo = &session->dma->histo_data;
2154
2155 ret = copy_to_user(hist->c0, mdp3_histo->r_data,
2156 sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM);
2157 if (ret)
2158 return ret;
2159
2160 ret = copy_to_user(hist->c1, mdp3_histo->g_data,
2161 sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM);
2162 if (ret)
2163 return ret;
2164
2165 ret = copy_to_user(hist->c2, mdp3_histo->b_data,
2166 sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM);
2167 if (ret)
2168 return ret;
2169
2170 ret = copy_to_user(hist->extra_info, mdp3_histo->extra,
2171 sizeof(uint32_t) * 2);
2172 if (ret)
2173 return ret;
2174
2175 hist->bin_cnt = MDP_HISTOGRAM_BIN_NUM;
2176 hist->block = MDP_BLOCK_DMA_P;
2177 return ret;
2178}
2179
2180static int mdp3_bl_scale_config(struct msm_fb_data_type *mfd,
2181 struct mdp_bl_scale_data *data)
2182{
2183 int ret = 0;
2184 int curr_bl;
2185
2186 mutex_lock(&mfd->bl_lock);
2187 curr_bl = mfd->bl_level;
2188 mfd->bl_scale = data->scale;
2189 mfd->bl_min_lvl = data->min_lvl;
2190 pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
2191 mfd->bl_min_lvl);
2192
2193 /* update current backlight to use new scaling*/
2194 mdss_fb_set_backlight(mfd, curr_bl);
2195 mutex_unlock(&mfd->bl_lock);
2196 return ret;
2197}
2198
2199static int mdp3_csc_config(struct mdp3_session_data *session,
2200 struct mdp_csc_cfg_data *data)
2201{
2202 struct mdp3_dma_color_correct_config config;
2203 struct mdp3_dma_ccs ccs;
2204 int ret = -EINVAL;
2205
Shiraz Hashimd740ab42020-02-04 13:41:20 +05302206 if (!data) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302207 pr_err("%s : Invalid csc vectors", __func__);
2208 return -EINVAL;
2209 }
2210
2211 mutex_lock(&session->lock);
2212 mutex_lock(&session->dma->pp_lock);
2213 session->dma->cc_vect_sel = (session->dma->cc_vect_sel + 1) % 2;
2214
2215 config.ccs_enable = 1;
2216 config.ccs_sel = session->dma->cc_vect_sel;
2217 config.pre_limit_sel = session->dma->cc_vect_sel;
2218 config.post_limit_sel = session->dma->cc_vect_sel;
2219 config.pre_bias_sel = session->dma->cc_vect_sel;
2220 config.post_bias_sel = session->dma->cc_vect_sel;
2221 config.ccs_dirty = true;
2222
2223 ccs.mv = data->csc_data.csc_mv;
2224 ccs.pre_bv = data->csc_data.csc_pre_bv;
2225 ccs.post_bv = data->csc_data.csc_post_bv;
2226 ccs.pre_lv = data->csc_data.csc_pre_lv;
2227 ccs.post_lv = data->csc_data.csc_post_lv;
2228
2229 /* cache one copy of setting for suspend/resume reconfiguring */
2230 session->dma->ccs_cache = *data;
2231
2232 mdp3_clk_enable(1, 0);
2233 ret = session->dma->config_ccs(session->dma, &config, &ccs);
2234 mdp3_clk_enable(0, 0);
2235 mutex_unlock(&session->dma->pp_lock);
2236 mutex_unlock(&session->lock);
2237 return ret;
2238}
2239
2240static int mdp3_pp_ioctl(struct msm_fb_data_type *mfd,
2241 void __user *argp)
2242{
2243 int ret = -EINVAL;
2244 struct msmfb_mdp_pp mdp_pp;
2245 struct mdp_lut_cfg_data *lut;
2246 struct mdp3_session_data *mdp3_session;
2247
2248 if (!mfd || !mfd->mdp.private1)
2249 return -EINVAL;
2250
2251 mdp3_session = mfd->mdp.private1;
2252
2253 ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
2254 if (ret)
2255 return ret;
2256
2257 switch (mdp_pp.op) {
2258 case mdp_bl_scale_cfg:
2259 ret = mdp3_validate_scale_config(&mdp_pp.data.bl_scale_data);
2260 if (ret) {
2261 pr_err("%s: invalid scale config\n", __func__);
2262 break;
2263 }
2264 ret = mdp3_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
2265 &mdp_pp.data.bl_scale_data);
2266 break;
2267 case mdp_op_csc_cfg:
2268 /* Checking state of dyn_pu before programming CSC block */
2269 if (mdp3_session->dyn_pu_state) {
2270 pr_debug("Partial update feature is enabled.\n");
2271 return -EPERM;
2272 }
2273 ret = mdp3_validate_csc_data(&(mdp_pp.data.csc_cfg_data));
2274 if (ret) {
2275 pr_err("%s: invalid csc data\n", __func__);
2276 break;
2277 }
2278 ret = mdp3_csc_config(mdp3_session,
2279 &(mdp_pp.data.csc_cfg_data));
2280 break;
2281 case mdp_op_lut_cfg:
2282 lut = &mdp_pp.data.lut_cfg_data;
2283 if (lut->lut_type != mdp_lut_rgb) {
2284 pr_err("Lut type %d is not supported", lut->lut_type);
2285 return -EINVAL;
2286 }
2287 if (lut->data.rgb_lut_data.flags & MDP_PP_OPS_READ)
2288 ret = mdp3_ctrl_lut_read(mfd,
2289 &(lut->data.rgb_lut_data));
2290 else
2291 ret = mdp3_ctrl_lut_config(mfd,
2292 &(lut->data.rgb_lut_data));
2293 if (ret)
2294 pr_err("RGB LUT ioctl failed\n");
2295 else
2296 ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp));
2297 break;
2298
2299 default:
2300 pr_err("Unsupported request to MDP_PP IOCTL.\n");
2301 ret = -EINVAL;
2302 break;
2303 }
2304 if (!ret)
2305 ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp));
2306 return ret;
2307}
2308
2309static int mdp3_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
2310 void __user *argp)
2311{
Arun kumar47145e02018-03-23 22:07:51 +05302312 int ret = -ENOTSUPP;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302313 struct mdp_histogram_data hist;
2314 struct mdp_histogram_start_req hist_req;
2315 u32 block;
2316 struct mdp3_session_data *mdp3_session;
2317
2318 if (!mfd || !mfd->mdp.private1)
2319 return -EINVAL;
2320
2321 mdp3_session = mfd->mdp.private1;
2322
2323 switch (cmd) {
2324 case MSMFB_HISTOGRAM_START:
2325 ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
2326 if (ret)
2327 return ret;
2328
2329 ret = mdp3_histogram_start(mdp3_session, &hist_req);
2330 break;
2331
2332 case MSMFB_HISTOGRAM_STOP:
2333 ret = copy_from_user(&block, argp, sizeof(int));
2334 if (ret)
2335 return ret;
2336
2337 ret = mdp3_histogram_stop(mdp3_session, block);
2338 break;
2339
2340 case MSMFB_HISTOGRAM:
2341 ret = copy_from_user(&hist, argp, sizeof(hist));
2342 if (ret)
2343 return ret;
2344
2345 ret = mdp3_histogram_collect(mdp3_session, &hist);
2346 if (!ret)
2347 ret = copy_to_user(argp, &hist, sizeof(hist));
2348 break;
2349 default:
2350 break;
2351 }
2352 return ret;
2353}
2354
2355static int mdp3_validate_lut_data(struct fb_cmap *cmap)
2356{
2357 u32 i = 0;
2358
2359 if (!cmap || !cmap->red || !cmap->green || !cmap->blue) {
2360 pr_err("Invalid arguments!\n");
2361 return -EINVAL;
2362 }
2363
2364 for (i = 0; i < MDP_LUT_SIZE; i++) {
2365 if (cmap->red[i] > 0xFF || cmap->green[i] > 0xFF ||
2366 cmap->blue[i] > 0xFF) {
2367 pr_err("LUT value over 255 (limit) at %d index\n", i);
2368 return -EINVAL;
2369 }
2370 }
2371
2372 return 0;
2373}
2374
2375static inline int mdp3_copy_lut_buffer(struct fb_cmap *dst, struct fb_cmap *src)
2376{
2377 if (!dst || !src || !dst->red || !dst->blue || !dst->green ||
2378 !src->red || !src->green || !src->blue) {
2379 pr_err("Invalid params\n");
2380 return -EINVAL;
2381 }
2382
2383 dst->start = src->start;
2384 dst->len = src->len;
2385
2386 memcpy(dst->red, src->red, MDP_LUT_SIZE * sizeof(u16));
2387 memcpy(dst->green, src->green, MDP_LUT_SIZE * sizeof(u16));
2388 memcpy(dst->blue, src->blue, MDP_LUT_SIZE * sizeof(u16));
2389 return 0;
2390}
2391
2392static int mdp3_alloc_lut_buffer(struct platform_device *pdev, void **cmap)
2393{
2394 struct fb_cmap *map;
2395
2396 map = devm_kzalloc(&pdev->dev, sizeof(struct fb_cmap), GFP_KERNEL);
2397 if (map == NULL)
2398 return -ENOMEM;
2399
2400 memset(map, 0, sizeof(struct fb_cmap));
2401
2402 map->red = devm_kzalloc(&pdev->dev, MDP_LUT_SIZE * sizeof(u16),
2403 GFP_KERNEL);
2404 if (map->red == NULL)
2405 goto exit_red;
2406
2407 memset(map->red, 0, sizeof(u16) * MDP_LUT_SIZE);
2408
2409 map->green = devm_kzalloc(&pdev->dev, MDP_LUT_SIZE * sizeof(u16),
2410 GFP_KERNEL);
2411 if (map->green == NULL)
2412 goto exit_green;
2413
2414 memset(map->green, 0, sizeof(u16) * MDP_LUT_SIZE);
2415
2416 map->blue = devm_kzalloc(&pdev->dev, MDP_LUT_SIZE * sizeof(u16),
2417 GFP_KERNEL);
2418 if (map->blue == NULL)
2419 goto exit_blue;
2420
2421 memset(map->blue, 0, sizeof(u16) * MDP_LUT_SIZE);
2422
2423 *cmap = map;
2424 return 0;
2425exit_blue:
2426 devm_kfree(&pdev->dev, map->green);
2427exit_green:
2428 devm_kfree(&pdev->dev, map->red);
2429exit_red:
2430 devm_kfree(&pdev->dev, map);
2431 return -ENOMEM;
2432}
2433
2434static void mdp3_free_lut_buffer(struct platform_device *pdev, void **cmap)
2435{
2436 struct fb_cmap *map = (struct fb_cmap *)(*cmap);
2437
2438 if (map == NULL)
2439 return;
2440
2441 devm_kfree(&pdev->dev, map->blue);
2442 map->blue = NULL;
2443 devm_kfree(&pdev->dev, map->green);
2444 map->green = NULL;
2445 devm_kfree(&pdev->dev, map->red);
2446 map->red = NULL;
2447 devm_kfree(&pdev->dev, map);
2448 map = NULL;
2449}
2450
2451static int mdp3_lut_combine_gain(struct fb_cmap *cmap, struct mdp3_dma *dma)
2452{
2453 int i = 0;
2454 u32 r = 0, g = 0, b = 0;
2455
2456 if (!cmap || !dma || !dma->gc_cmap || !dma->hist_cmap ||
2457 !dma->gc_cmap->red || !dma->gc_cmap->green ||
2458 !dma->gc_cmap->blue || !dma->hist_cmap->red ||
2459 !dma->hist_cmap->green || !dma->hist_cmap->blue) {
2460 pr_err("Invalid params\n");
2461 return -EINVAL;
2462 }
2463
2464 for (i = 1; i < MDP_LUT_SIZE; i++) {
2465 r = MIN(dma->gc_cmap->red[i] * dma->hist_cmap->red[i] *
2466 mdp_lut_inverse16[i], 0xFF0000);
2467 g = MIN(dma->gc_cmap->green[i] * dma->hist_cmap->green[i] *
2468 mdp_lut_inverse16[i], 0xFF0000);
2469 b = MIN(dma->gc_cmap->blue[i] * dma->hist_cmap->blue[i] *
2470 mdp_lut_inverse16[i], 0xFF0000);
2471
2472 cmap->red[i] = (r >> 16) & 0xFF;
2473 cmap->green[i] = (g >> 16) & 0xFF;
2474 cmap->blue[i] = (b >> 16) & 0xFF;
2475 }
2476 return 0;
2477}
2478
2479/* Called from within pp_lock and session lock locked context */
2480static int mdp3_ctrl_lut_update(struct msm_fb_data_type *mfd,
2481 struct fb_cmap *cmap)
2482{
2483 int rc = 0;
2484 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
2485 struct mdp3_dma *dma;
2486 struct mdp3_dma_lut_config lut_config;
2487
2488 dma = mdp3_session->dma;
2489
2490 if (!dma->config_lut) {
2491 pr_err("Config LUT not defined!\n");
2492 return -EINVAL;
2493 }
2494
2495 lut_config.lut_enable = 7;
2496 lut_config.lut_sel = mdp3_session->lut_sel;
2497 lut_config.lut_position = 1;
2498 lut_config.lut_dirty = true;
2499
2500 if (!mdp3_session->status) {
2501 pr_err("display off!\n");
2502 return -EPERM;
2503 }
2504
2505 mdp3_clk_enable(1, 0);
2506 rc = dma->config_lut(dma, &lut_config, cmap);
2507 mdp3_clk_enable(0, 0);
2508 if (rc)
2509 pr_err("mdp3_ctrl_lut_update failed\n");
2510
2511 mdp3_session->lut_sel = (mdp3_session->lut_sel + 1) % 2;
2512 return rc;
2513}
2514
2515static int mdp3_ctrl_lut_config(struct msm_fb_data_type *mfd,
2516 struct mdp_rgb_lut_data *cfg)
2517{
2518 int rc = 0;
2519 bool data_validated = false;
2520 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
2521 struct mdp3_dma *dma;
2522 struct fb_cmap *cmap;
2523
2524 dma = mdp3_session->dma;
2525
2526 if ((cfg->cmap.start > MDP_LUT_SIZE) ||
2527 (cfg->cmap.len > MDP_LUT_SIZE) ||
2528 (cfg->cmap.start + cfg->cmap.len > MDP_LUT_SIZE)) {
2529 pr_err("Invalid arguments.\n");
2530 return -EINVAL;
2531 }
2532
2533 rc = mdp3_alloc_lut_buffer(mfd->pdev, (void **) &cmap);
2534 if (rc) {
2535 pr_err("No memory\n");
2536 return -ENOMEM;
2537 }
2538
2539 mutex_lock(&mdp3_session->lock);
2540 mutex_lock(&dma->pp_lock);
2541 rc = copy_from_user(cmap->red + cfg->cmap.start,
2542 cfg->cmap.red, sizeof(u16) * cfg->cmap.len);
2543 rc |= copy_from_user(cmap->green + cfg->cmap.start,
2544 cfg->cmap.green, sizeof(u16) * cfg->cmap.len);
2545 rc |= copy_from_user(cmap->blue + cfg->cmap.start,
2546 cfg->cmap.blue, sizeof(u16) * cfg->cmap.len);
2547 if (rc) {
2548 pr_err("Copying user data failed!\n");
2549 goto exit_err;
2550 }
2551
2552 switch (cfg->lut_type) {
2553 case mdp_rgb_lut_gc:
2554 if (cfg->flags & MDP_PP_OPS_DISABLE) {
2555 if (dma->lut_sts & MDP3_LUT_GC_EN)
2556 /* Free GC cmap cache since disabled */
2557 mdp3_free_lut_buffer(mfd->pdev,
2558 (void **)&dma->gc_cmap);
2559 dma->lut_sts &= ~MDP3_LUT_GC_EN;
2560 } else if (!(dma->lut_sts & MDP3_LUT_GC_EN)) {
2561 /* Check if values sent are valid */
2562 rc = mdp3_validate_lut_data(cmap);
2563 if (rc) {
2564 pr_err("Invalid GC LUT data\n");
2565 goto exit_err;
2566 }
2567 data_validated = true;
2568
2569 /* Allocate GC cmap cache to store values */
2570 rc = mdp3_alloc_lut_buffer(mfd->pdev,
2571 (void **)&dma->gc_cmap);
2572 if (rc) {
2573 pr_err("GC LUT config failed\n");
2574 goto exit_err;
2575 }
2576 dma->lut_sts |= MDP3_LUT_GC_EN;
2577 }
2578 /*
2579 * Copy the GC values from userspace to maintain the
2580 * correct values user intended to program in cache.
2581 * The values programmed in HW might factor in presence
2582 * of other LUT modifying features hence can be
2583 * different from these user given values.
2584 */
2585 if (dma->lut_sts & MDP3_LUT_GC_EN) {
2586 /* Validate LUT data if not yet validated */
2587 if (!data_validated) {
2588 rc = mdp3_validate_lut_data(cmap);
2589 if (rc) {
2590 pr_err("Invalid GC LUT data\n");
2591 goto exit_err;
2592 }
2593 }
2594 rc = mdp3_copy_lut_buffer(dma->gc_cmap, cmap);
2595 if (rc) {
2596 pr_err("Could not store GC to cache\n");
2597 goto exit_err;
2598 }
2599 }
2600 break;
2601 case mdp_rgb_lut_hist:
2602 if (cfg->flags & MDP_PP_OPS_DISABLE) {
2603 if (dma->lut_sts & MDP3_LUT_HIST_EN)
2604 /* Free HIST cmap cache since disabled */
2605 mdp3_free_lut_buffer(mfd->pdev,
2606 (void **)&dma->hist_cmap);
2607 dma->lut_sts &= ~MDP3_LUT_HIST_EN;
2608 } else if (!(dma->lut_sts & MDP3_LUT_HIST_EN)) {
2609 /* Check if values sent are valid */
2610 rc = mdp3_validate_lut_data(cmap);
2611 if (rc) {
2612 pr_err("Invalid HIST LUT data\n");
2613 goto exit_err;
2614 }
2615 data_validated = true;
2616
2617 /* Allocate HIST cmap cache to store values */
2618 rc = mdp3_alloc_lut_buffer(mfd->pdev,
2619 (void **)&dma->hist_cmap);
2620 if (rc) {
2621 pr_err("HIST LUT config failed\n");
2622 goto exit_err;
2623 }
2624 dma->lut_sts |= MDP3_LUT_HIST_EN;
2625 }
2626 /*
2627 * Copy the HIST LUT values from userspace to maintain
2628 * correct values user intended to program in cache.
2629 * The values programmed in HW might factor in presence
2630 * of other LUT modifying features hence can be
2631 * different from these user given values.
2632 */
2633 if (dma->lut_sts & MDP3_LUT_HIST_EN) {
2634 /* Validate LUT data if not yet validated */
2635 if (!data_validated) {
2636 rc = mdp3_validate_lut_data(cmap);
2637 if (rc) {
2638 pr_err("Invalid H LUT data\n");
2639 goto exit_err;
2640 }
2641 }
2642 rc = mdp3_copy_lut_buffer(dma->hist_cmap, cmap);
2643 if (rc) {
2644 pr_err("Could not cache Hist LUT\n");
2645 goto exit_err;
2646 }
2647 }
2648 break;
2649 default:
2650 pr_err("Invalid lut type: %u\n", cfg->lut_type);
2651 rc = -EINVAL;
2652 goto exit_err;
2653 }
2654
2655 /*
2656 * In case both GC LUT and HIST LUT need to be programmed the gains
2657 * of each the individual LUTs need to be applied onto a single LUT
2658 * and applied in HW
2659 */
2660 if ((dma->lut_sts & MDP3_LUT_HIST_EN) &&
2661 (dma->lut_sts & MDP3_LUT_GC_EN)) {
2662 rc = mdp3_lut_combine_gain(cmap, dma);
2663 if (rc) {
2664 pr_err("Combining gains failed rc = %d\n", rc);
2665 goto exit_err;
2666 }
2667 }
2668
2669 rc = mdp3_ctrl_lut_update(mfd, cmap);
2670 if (rc)
2671 pr_err("Updating LUT failed! rc = %d\n", rc);
2672exit_err:
2673 mutex_unlock(&dma->pp_lock);
2674 mutex_unlock(&mdp3_session->lock);
2675 mdp3_free_lut_buffer(mfd->pdev, (void **) &cmap);
2676 return rc;
2677}
2678
2679static int mdp3_ctrl_lut_read(struct msm_fb_data_type *mfd,
2680 struct mdp_rgb_lut_data *cfg)
2681{
2682 int rc = 0;
2683 struct fb_cmap *cmap;
2684 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
2685 struct mdp3_dma *dma = mdp3_session->dma;
2686
2687 switch (cfg->lut_type) {
2688 case mdp_rgb_lut_gc:
2689 if (!dma->gc_cmap) {
2690 pr_err("GC not programmed\n");
2691 return -EPERM;
2692 }
2693 cmap = dma->gc_cmap;
2694 break;
2695 case mdp_rgb_lut_hist:
2696 if (!dma->hist_cmap) {
2697 pr_err("Hist LUT not programmed\n");
2698 return -EPERM;
2699 }
2700 cmap = dma->hist_cmap;
2701 break;
2702 default:
2703 pr_err("Invalid lut type %u\n", cfg->lut_type);
2704 return -EINVAL;
2705 }
2706
2707 cfg->cmap.start = cmap->start;
2708 cfg->cmap.len = cmap->len;
2709
2710 mutex_lock(&dma->pp_lock);
2711 rc = copy_to_user(cfg->cmap.red, cmap->red, sizeof(u16) *
2712 MDP_LUT_SIZE);
2713 rc |= copy_to_user(cfg->cmap.green, cmap->green, sizeof(u16) *
2714 MDP_LUT_SIZE);
2715 rc |= copy_to_user(cfg->cmap.blue, cmap->blue, sizeof(u16) *
2716 MDP_LUT_SIZE);
2717 mutex_unlock(&dma->pp_lock);
2718 return rc;
2719}
2720
2721/* Invoked from ctrl_on with session lock locked context */
2722static void mdp3_ctrl_pp_resume(struct msm_fb_data_type *mfd)
2723{
2724 struct mdp3_session_data *mdp3_session;
2725 struct mdp3_dma *dma;
2726 struct fb_cmap *cmap;
2727 int rc = 0;
2728
2729 mdp3_session = mfd->mdp.private1;
2730 dma = mdp3_session->dma;
2731
2732 mutex_lock(&dma->pp_lock);
2733 /*
2734 * if dma->ccs_config.ccs_enable is set then DMA PP block was enabled
2735 * via user space IOCTL.
2736 * Then set dma->ccs_config.ccs_dirty flag
2737 * Then PP block will be reconfigured when next kickoff comes.
2738 */
2739 if (dma->ccs_config.ccs_enable)
2740 dma->ccs_config.ccs_dirty = true;
2741
2742 /*
2743 * If gamma correction was enabled then we program the LUT registers
2744 * with the last configuration data before suspend. If gamma correction
2745 * is not enabled then we do not program anything. The LUT from
2746 * histogram processing algorithms will program hardware based on new
2747 * frame data if they are enabled.
2748 */
2749 if (dma->lut_sts & MDP3_LUT_GC_EN) {
2750
2751 rc = mdp3_alloc_lut_buffer(mfd->pdev, (void **)&cmap);
2752 if (rc) {
2753 pr_err("No memory for GC LUT, rc = %d\n", rc);
2754 goto exit_err;
2755 }
2756
2757 if (dma->lut_sts & MDP3_LUT_HIST_EN) {
2758 rc = mdp3_lut_combine_gain(cmap, dma);
2759 if (rc) {
2760 pr_err("Combining the gain failed rc=%d\n", rc);
2761 goto exit_err;
2762 }
2763 } else {
2764 rc = mdp3_copy_lut_buffer(cmap, dma->gc_cmap);
2765 if (rc) {
2766 pr_err("Updating GC failed rc = %d\n", rc);
2767 goto exit_err;
2768 }
2769 }
2770
2771 rc = mdp3_ctrl_lut_update(mfd, cmap);
2772 if (rc)
2773 pr_err("GC Lut update failed rc=%d\n", rc);
2774exit_err:
2775 mdp3_free_lut_buffer(mfd->pdev, (void **)&cmap);
2776 }
2777
2778 mutex_unlock(&dma->pp_lock);
2779}
2780
2781static int mdp3_overlay_prepare(struct msm_fb_data_type *mfd,
2782 struct mdp_overlay_list __user *user_ovlist)
2783{
2784 struct mdp_overlay_list ovlist;
2785 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
2786 struct mdp_overlay *req_list;
2787 struct mdp_overlay *req;
2788 int rc;
2789
2790 if (!mdp3_session)
2791 return -ENODEV;
2792
2793 req = &mdp3_session->req_overlay;
2794
2795 if (copy_from_user(&ovlist, user_ovlist, sizeof(ovlist)))
2796 return -EFAULT;
2797
2798 if (ovlist.num_overlays != 1) {
2799 pr_err("OV_PREPARE failed: only 1 overlay allowed\n");
2800 return -EINVAL;
2801 }
2802
2803 if (copy_from_user(&req_list, ovlist.overlay_list,
2804 sizeof(struct mdp_overlay *)))
2805 return -EFAULT;
2806
2807 if (copy_from_user(req, req_list, sizeof(*req)))
2808 return -EFAULT;
2809
2810 rc = mdp3_overlay_set(mfd, req);
2811 if (!IS_ERR_VALUE(rc)) {
2812 if (copy_to_user(req_list, req, sizeof(*req)))
2813 return -EFAULT;
2814 }
2815
2816 if (put_user(IS_ERR_VALUE(rc) ? 0 : 1,
2817 &user_ovlist->processed_overlays))
2818 return -EFAULT;
2819
2820 return rc;
2821}
2822
2823static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd,
2824 u32 cmd, void __user *argp)
2825{
2826 int rc = -EINVAL;
2827 struct mdp3_session_data *mdp3_session;
2828 struct msmfb_metadata metadata;
2829 struct mdp_overlay *req = NULL;
2830 struct msmfb_overlay_data ov_data;
2831 int val;
2832
2833 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
2834 if (!mdp3_session)
2835 return -ENODEV;
2836
2837 req = &mdp3_session->req_overlay;
2838
2839 if (!mdp3_session->status && cmd != MSMFB_METADATA_GET &&
Krishna Manikandan695632e2020-03-04 20:50:28 +05302840 cmd != MSMFB_METADATA_SET && cmd != MSMFB_HISTOGRAM_STOP &&
2841 cmd != MSMFB_HISTOGRAM) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302842 pr_err("mdp3_ctrl_ioctl_handler, display off!\n");
2843 return -EPERM;
2844 }
2845
2846 switch (cmd) {
2847 case MSMFB_MDP_PP:
2848 rc = mdp3_pp_ioctl(mfd, argp);
2849 break;
2850 case MSMFB_HISTOGRAM_START:
2851 case MSMFB_HISTOGRAM_STOP:
2852 case MSMFB_HISTOGRAM:
2853 rc = mdp3_histo_ioctl(mfd, cmd, argp);
2854 break;
2855
2856 case MSMFB_VSYNC_CTRL:
2857 case MSMFB_OVERLAY_VSYNC_CTRL:
2858 if (!copy_from_user(&val, argp, sizeof(val))) {
2859 mutex_lock(&mdp3_session->lock);
2860 mdp3_session->vsync_enabled = val;
2861 rc = mdp3_ctrl_vsync_enable(mfd, val);
2862 mutex_unlock(&mdp3_session->lock);
2863 } else {
2864 pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n");
2865 rc = -EFAULT;
2866 }
2867 break;
2868 case MSMFB_ASYNC_BLIT:
2869 mutex_lock(&mdp3_res->fs_idle_pc_lock);
2870 if (mdp3_session->in_splash_screen || mdp3_res->idle_pc) {
2871 pr_debug("%s: reset- in_splash = %d, idle_pc = %d",
2872 __func__, mdp3_session->in_splash_screen,
2873 mdp3_res->idle_pc);
2874 mdp3_ctrl_reset(mfd);
2875 }
2876 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
2877 rc = mdp3_ctrl_async_blit_req(mfd, argp);
Arun kumar04d4a922018-05-23 16:22:45 +05302878 if (!rc)
2879 cancel_work_sync(&mdp3_session->clk_off_work);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302880 break;
2881 case MSMFB_BLIT:
2882 mutex_lock(&mdp3_res->fs_idle_pc_lock);
2883 if (mdp3_session->in_splash_screen)
2884 mdp3_ctrl_reset(mfd);
2885 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
2886 rc = mdp3_ctrl_blit_req(mfd, argp);
Arun kumar04d4a922018-05-23 16:22:45 +05302887 if (!rc)
2888 cancel_work_sync(&mdp3_session->clk_off_work);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302889 break;
2890 case MSMFB_METADATA_GET:
2891 rc = copy_from_user(&metadata, argp, sizeof(metadata));
2892 if (!rc)
2893 rc = mdp3_get_metadata(mfd, &metadata);
2894 if (!rc)
2895 rc = copy_to_user(argp, &metadata, sizeof(metadata));
2896 if (rc)
2897 pr_err("mdp3_get_metadata failed (%d)\n", rc);
2898 break;
2899 case MSMFB_METADATA_SET:
2900 rc = copy_from_user(&metadata, argp, sizeof(metadata));
2901 if (!rc)
2902 rc = mdp3_set_metadata(mfd, &metadata);
2903 if (rc)
2904 pr_err("mdp3_set_metadata failed (%d)\n", rc);
2905 break;
2906 case MSMFB_OVERLAY_GET:
2907 rc = copy_from_user(req, argp, sizeof(*req));
2908 if (!rc) {
2909 rc = mdp3_overlay_get(mfd, req);
2910
2911 if (!IS_ERR_VALUE(rc))
2912 rc = copy_to_user(argp, req, sizeof(*req));
2913 }
2914 if (rc)
2915 pr_err("OVERLAY_GET failed (%d)\n", rc);
2916 break;
2917 case MSMFB_OVERLAY_SET:
2918 rc = copy_from_user(req, argp, sizeof(*req));
2919 if (!rc) {
2920 rc = mdp3_overlay_set(mfd, req);
2921
2922 if (!IS_ERR_VALUE(rc))
2923 rc = copy_to_user(argp, req, sizeof(*req));
2924 }
2925 if (rc)
2926 pr_err("OVERLAY_SET failed (%d)\n", rc);
2927 break;
2928 case MSMFB_OVERLAY_UNSET:
2929 if (!IS_ERR_VALUE(copy_from_user(&val, argp, sizeof(val))))
2930 rc = mdp3_overlay_unset(mfd, val);
2931 break;
2932 case MSMFB_OVERLAY_PLAY:
2933 rc = copy_from_user(&ov_data, argp, sizeof(ov_data));
2934 mutex_lock(&mdp3_res->fs_idle_pc_lock);
2935 if (mdp3_session->in_splash_screen)
2936 mdp3_ctrl_reset(mfd);
2937 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
2938 if (!rc)
2939 rc = mdp3_overlay_play(mfd, &ov_data);
2940 if (rc)
2941 pr_err("OVERLAY_PLAY failed (%d)\n", rc);
2942 break;
2943 case MSMFB_OVERLAY_PREPARE:
2944 rc = mdp3_overlay_prepare(mfd, argp);
2945 break;
2946 default:
2947 break;
2948 }
2949 return rc;
2950}
2951
2952int mdp3_wait_for_dma_done(struct mdp3_session_data *session)
2953{
2954 int rc = 0;
2955
2956 if (session->dma_active) {
2957 rc = wait_for_completion_timeout(&session->dma_completion,
Abhijith Desaib502b282018-09-12 14:48:22 +05302958 dma_timeout_value(session->dma));
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302959 if (rc > 0) {
2960 session->dma_active = 0;
2961 rc = 0;
2962 } else if (rc == 0) {
2963 rc = -ETIME;
2964 }
2965 }
2966 return rc;
2967}
2968
2969static int mdp3_update_panel_info(struct msm_fb_data_type *mfd, int mode,
2970 int dest_ctrl)
2971{
2972 int ret = 0;
2973 struct mdp3_session_data *mdp3_session;
2974 struct mdss_panel_data *panel;
2975 u32 intf_type = 0;
2976
2977 if (!mfd || !mfd->mdp.private1)
2978 return -EINVAL;
2979
2980 mdp3_session = mfd->mdp.private1;
2981 panel = mdp3_session->panel;
2982
2983 if (!panel->event_handler)
2984 return 0;
2985 ret = panel->event_handler(panel, MDSS_EVENT_DSI_UPDATE_PANEL_DATA,
2986 (void *)(unsigned long)mode);
2987 if (ret)
2988 pr_err("Dynamic switch to %s mode failed!\n",
2989 mode ? "command" : "video");
2990 if (mode == 1)
2991 mfd->panel.type = MIPI_CMD_PANEL;
2992 else
2993 mfd->panel.type = MIPI_VIDEO_PANEL;
2994
2995 if (mfd->panel.type != MIPI_VIDEO_PANEL)
2996 mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
2997
2998 intf_type = mdp3_ctrl_get_intf_type(mfd);
2999 mdp3_session->intf->cfg.type = intf_type;
3000 mdp3_session->intf->available = 1;
3001 mdp3_session->intf->in_use = 1;
3002 mdp3_res->intf[intf_type].in_use = 1;
3003
3004 mdp3_intf_init(mdp3_session->intf);
3005
3006 mdp3_session->dma->output_config.out_sel = intf_type;
3007 mdp3_session->status = mdp3_session->intf->active;
3008
3009 return 0;
3010}
3011
3012static int mdp3_vsync_retire_setup(struct msm_fb_data_type *mfd)
3013{
3014 struct mdp3_session_data *mdp3_session;
3015 struct mdp3_notification retire_client;
3016 char name[24];
3017
3018 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
3019
3020 snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index);
Arun kumar47145e02018-03-23 22:07:51 +05303021 mfd->mdp_sync_pt_data.timeline_retire = mdss_create_timeline(name);
3022 if (mfd->mdp_sync_pt_data.timeline_retire == NULL) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303023 pr_err("cannot vsync create time line");
3024 return -ENOMEM;
3025 }
3026
Vijay Navnath Kamble7f082222018-09-10 12:40:01 +05303027 if (mfd->panel_info->type == MIPI_CMD_PANEL) {
3028 /* Add retire vsync handler */
3029 retire_client.handler = mdp3_vsync_retire_handle_vsync;
3030 retire_client.arg = mdp3_session;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303031
Vijay Navnath Kamble7f082222018-09-10 12:40:01 +05303032 if (mdp3_session->dma)
3033 mdp3_session->dma->retire_client = retire_client;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303034
Vijay Navnath Kamble7f082222018-09-10 12:40:01 +05303035 INIT_WORK(&mdp3_session->retire_work,
3036 mdp3_vsync_retire_work_handler);
3037 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303038
3039 return 0;
3040}
3041
3042int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
3043{
3044 struct device *dev = mfd->fbi->dev;
3045 struct msm_mdp_interface *mdp3_interface = &mfd->mdp;
3046 struct mdp3_session_data *mdp3_session = NULL;
3047 u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
Arun kumardb962812018-05-30 16:31:52 +05303048 int frame_rate = DEFAULT_FRAME_RATE;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303049 int rc;
3050 int splash_mismatch = 0;
3051 struct sched_param sched = { .sched_priority = 16 };
3052
3053 pr_info("mdp3_ctrl_init\n");
3054 rc = mdp3_parse_dt_splash(mfd);
3055 if (rc)
3056 splash_mismatch = 1;
3057
Arun kumardb962812018-05-30 16:31:52 +05303058 frame_rate = mdss_panel_get_framerate(mfd->panel_info,
3059 FPS_RESOLUTION_HZ);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303060 mdp3_interface->on_fnc = mdp3_ctrl_on;
3061 mdp3_interface->off_fnc = mdp3_ctrl_off;
3062 mdp3_interface->do_histogram = NULL;
3063 mdp3_interface->cursor_update = NULL;
3064 mdp3_interface->dma_fnc = mdp3_ctrl_pan_display;
3065 mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
3066 mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
3067 mdp3_interface->pre_commit = mdp3_layer_pre_commit;
3068 mdp3_interface->atomic_validate = mdp3_layer_atomic_validate;
3069 mdp3_interface->lut_update = NULL;
3070 mdp3_interface->configure_panel = mdp3_update_panel_info;
3071 mdp3_interface->input_event_handler = NULL;
Animesh Kishore8b42bd92018-12-04 18:57:13 +05303072 mdp3_interface->signal_retire_fence = mdp3_vsync_retire_signal;
Arun kumar162db222018-05-09 17:28:40 +05303073 mdp3_interface->is_twm_en = mdp3_is_twm_en;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303074
3075 mdp3_session = kzalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
3076 if (!mdp3_session)
3077 return -ENOMEM;
3078
3079 mutex_init(&mdp3_session->lock);
3080 INIT_WORK(&mdp3_session->clk_off_work, mdp3_dispatch_clk_off);
3081
Arun kumar47145e02018-03-23 22:07:51 +05303082 kthread_init_worker(&mdp3_session->worker);
3083 kthread_init_work(&mdp3_session->dma_done_work, mdp3_dispatch_dma_done);
3084
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303085
3086 mdp3_session->thread = kthread_run(kthread_worker_fn,
3087 &mdp3_session->worker,
3088 "mdp3_dispatch_dma_done");
3089
3090 if (IS_ERR(mdp3_session->thread)) {
3091 pr_err("Can't initialize mdp3_dispatch_dma_done thread\n");
3092 rc = -ENODEV;
3093 goto init_done;
3094 }
3095
3096 sched_setscheduler(mdp3_session->thread, SCHED_FIFO, &sched);
3097
3098 atomic_set(&mdp3_session->vsync_countdown, 0);
3099 mutex_init(&mdp3_session->histo_lock);
3100 mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
3101 if (!mdp3_session->dma) {
3102 rc = -ENODEV;
3103 goto init_done;
3104 }
3105
3106 rc = mdp3_dma_init(mdp3_session->dma);
3107 if (rc) {
3108 pr_err("fail to init dma\n");
3109 goto init_done;
3110 }
Animesh Kishore3650a562018-11-16 00:26:26 +05303111 mdp3_session->dma->session = mdp3_session;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303112
3113 intf_type = mdp3_ctrl_get_intf_type(mfd);
3114 mdp3_session->intf = mdp3_get_display_intf(intf_type);
3115 if (!mdp3_session->intf) {
3116 rc = -ENODEV;
3117 goto init_done;
3118 }
3119 rc = mdp3_intf_init(mdp3_session->intf);
3120 if (rc) {
3121 pr_err("fail to init interface\n");
3122 goto init_done;
3123 }
3124
3125 mdp3_session->dma->output_config.out_sel = intf_type;
3126 mdp3_session->mfd = mfd;
3127 mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
3128 mdp3_session->status = mdp3_session->intf->active;
3129 mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
3130 mdp3_bufq_init(&mdp3_session->bufq_in);
3131 mdp3_bufq_init(&mdp3_session->bufq_out);
3132 mdp3_session->histo_status = 0;
3133 mdp3_session->lut_sel = 0;
3134 BLOCKING_INIT_NOTIFIER_HEAD(&mdp3_session->notifier_head);
3135
3136 init_timer(&mdp3_session->vsync_timer);
3137 mdp3_session->vsync_timer.function = mdp3_vsync_timer_func;
3138 mdp3_session->vsync_timer.data = (u32)mdp3_session;
Abhijith Desaib502b282018-09-12 14:48:22 +05303139
3140 if (frame_rate != 0)
3141 mdp3_session->dma->vsync_period =
3142 DIV_ROUND_UP(1000, frame_rate);
3143
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303144 mfd->mdp.private1 = mdp3_session;
3145 init_completion(&mdp3_session->dma_completion);
Arun kumardb962812018-05-30 16:31:52 +05303146 if (intf_type != MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
3147 intf_type != MDP3_DMA_OUTPUT_SEL_SPI_CMD)
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303148 mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
3149
3150 rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
3151 if (rc) {
3152 pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
3153 goto init_done;
3154 }
3155 rc = sysfs_create_group(&dev->kobj, &generic_attr_group);
3156 if (rc) {
3157 pr_err("generic sysfs group creation failed, ret=%d\n", rc);
3158 goto init_done;
3159 }
3160
3161 mdp3_session->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd,
3162 "vsync_event");
3163 if (!mdp3_session->vsync_event_sd) {
3164 pr_err("vsync_event sysfs lookup failed\n");
3165 rc = -ENODEV;
3166 goto init_done;
3167 }
3168
3169 mdp3_session->dma->hist_event_sd = sysfs_get_dirent(dev->kobj.sd,
3170 "hist_event");
3171 if (!mdp3_session->dma->hist_event_sd) {
3172 pr_err("hist_event sysfs lookup failed\n");
3173 rc = -ENODEV;
3174 goto init_done;
3175 }
3176
3177 mdp3_session->bl_event_sd = sysfs_get_dirent(dev->kobj.sd,
3178 "bl_event");
3179 if (!mdp3_session->bl_event_sd) {
3180 pr_err("bl_event sysfs lookup failed\n");
3181 rc = -ENODEV;
3182 goto init_done;
3183 }
3184
3185 rc = mdp3_create_sysfs_link(dev);
3186 if (rc)
3187 pr_warn("problem creating link to mdp sysfs\n");
3188
3189 /* Enable PM runtime */
3190 pm_runtime_set_suspended(&mdp3_res->pdev->dev);
3191 pm_runtime_enable(&mdp3_res->pdev->dev);
3192
3193 kobject_uevent(&dev->kobj, KOBJ_ADD);
3194 pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
3195
3196 if (mdp3_get_cont_spash_en()) {
3197 mdp3_session->clk_on = 1;
3198 mdp3_session->in_splash_screen = 1;
3199 mdp3_ctrl_notifier_register(mdp3_session,
3200 &mdp3_session->mfd->mdp_sync_pt_data.notifier);
3201 }
3202
3203 /*
3204 * Increment the overlay active count.
3205 * This is needed to ensure that if idle power collapse kicks in
3206 * right away, it would be handled correctly.
3207 */
3208 atomic_inc(&mdp3_res->active_intf_cnt);
3209 if (splash_mismatch) {
3210 pr_err("splash memory mismatch, stop splash\n");
3211 mdp3_ctrl_off(mfd);
3212 }
3213
3214 mdp3_session->vsync_before_commit = true;
3215 mdp3_session->dyn_pu_state = mfd->panel_info->partial_update_enabled;
3216
Vijay Navnath Kamble7f082222018-09-10 12:40:01 +05303217 rc = mdp3_vsync_retire_setup(mfd);
3218 if (IS_ERR_VALUE(rc)) {
3219 pr_err("unable to create vsync timeline\n");
3220 goto init_done;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303221 }
3222init_done:
3223 if (IS_ERR_VALUE(rc))
3224 kfree(mdp3_session);
3225
3226 return rc;
3227}