blob: 2238e2dab8d2254ffc0d3aa9b3e53c95d770b430 [file] [log] [blame]
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(fmt) "%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);
951 panel = mdp3_session->panel;
952 /* make sure DSI host is initialized properly */
953 if (panel) {
954 pr_debug("%s : dsi host init, power state = %d Splash %d\n",
955 __func__, mfd->panel_power_state,
956 mdp3_session->in_splash_screen);
957 if (mdss_fb_is_power_on_lp(mfd) ||
958 mdp3_session->in_splash_screen) {
959 /* Turn on panel so that it can exit low power mode */
960 mdp3_clk_enable(1, 0);
961 rc = panel->event_handler(panel,
962 MDSS_EVENT_LINK_READY, NULL);
963 rc |= panel->event_handler(panel,
964 MDSS_EVENT_UNBLANK, NULL);
965 rc |= panel->event_handler(panel,
966 MDSS_EVENT_PANEL_ON, NULL);
Animesh Kishore96d4f7e2018-11-26 17:53:53 +0530967 if (mdss_fb_is_power_on_lp(mfd))
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530968 rc |= mdp3_enable_panic_ctrl();
969 mdp3_clk_enable(0, 0);
970 }
971 }
972
973 if (mdp3_session->status) {
974 pr_debug("fb%d is on already\n", mfd->index);
975 MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__, mfd->panel_power_state);
976 goto end;
977 }
978
979 if (mdp3_session->intf->active) {
980 pr_debug("continuous splash screen, initialized already\n");
981 mdp3_session->status = 1;
982 goto end;
983 }
984
985 /*
986 * Get a reference to the runtime pm device.
987 * If idle pc feature is enabled, it will be released
988 * at end of this routine else, when device is turned off.
989 */
990 pm_runtime_get_sync(&mdp3_res->pdev->dev);
991
992 /* Increment the overlay active count */
993 atomic_inc(&mdp3_res->active_intf_cnt);
994 mdp3_ctrl_notifier_register(mdp3_session,
995 &mdp3_session->mfd->mdp_sync_pt_data.notifier);
996
997 /* request bus bandwidth before DSI DMA traffic */
998 rc = mdp3_ctrl_res_req_bus(mfd, 1);
999 if (rc) {
1000 pr_err("fail to request bus resource\n");
1001 goto on_error;
1002 }
1003
1004 rc = mdp3_dynamic_clock_gating_ctrl(0);
1005 if (rc) {
1006 pr_err("fail to disable dynamic clock gating\n");
1007 goto on_error;
1008 }
1009 mdp3_qos_remapper_setup(panel);
1010
1011 rc = mdp3_ctrl_res_req_clk(mfd, 1);
1012 if (rc) {
1013 pr_err("fail to request mdp clk resource\n");
1014 goto on_error;
1015 }
1016
1017 if (panel->event_handler) {
1018 rc = panel->event_handler(panel, MDSS_EVENT_LINK_READY, NULL);
1019 rc |= panel->event_handler(panel, MDSS_EVENT_UNBLANK, NULL);
1020 rc |= panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
1021 if (panel->panel_info.type == MIPI_CMD_PANEL) {
1022 struct dsi_panel_clk_ctrl clk_ctrl;
1023
1024 clk_ctrl.state = MDSS_DSI_CLK_ON;
1025 clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT;
1026 rc |= panel->event_handler(panel,
1027 MDSS_EVENT_PANEL_CLK_CTRL,
1028 (void *)&clk_ctrl);
1029 }
1030 }
1031 if (rc) {
1032 pr_err("fail to turn on the panel\n");
1033 goto on_error;
1034 }
1035
1036 rc = mdp3_ctrl_dma_init(mfd, mdp3_session->dma);
1037 if (rc) {
1038 pr_err("dma init failed\n");
1039 goto on_error;
1040 }
1041
1042 rc = mdp3_ppp_init();
1043 if (rc) {
1044 pr_err("ppp init failed\n");
1045 goto on_error;
1046 }
1047
1048 rc = mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
1049 if (rc) {
1050 pr_err("display interface init failed\n");
1051 goto on_error;
1052 }
1053 mdp3_session->clk_on = 1;
1054
1055 mdp3_session->first_commit = true;
1056 if (mfd->panel_info->panel_dead)
1057 mdp3_session->esd_recovery = true;
1058
1059 mdp3_session->status = 1;
1060
1061 mdp3_ctrl_pp_resume(mfd);
Abhijith Desaib502b282018-09-12 14:48:22 +05301062
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301063on_error:
1064 if (rc || (mdp3_res->idle_pc_enabled &&
1065 (mfd->panel_info->type == MIPI_CMD_PANEL))) {
1066 if (rc) {
1067 pr_err("Failed to turn on fb%d\n", mfd->index);
1068 atomic_dec(&mdp3_res->active_intf_cnt);
1069 }
1070 pm_runtime_put(&mdp3_res->pdev->dev);
1071 }
1072end:
Abhijith Desaib502b282018-09-12 14:48:22 +05301073 framerate = mdss_panel_get_framerate(mfd->panel_info,
1074 FPS_RESOLUTION_HZ);
1075 if (framerate != 0)
1076 mdp3_session->dma->vsync_period = DIV_ROUND_UP(1000, framerate);
1077
1078 MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__, mfd->panel_power_state, framerate);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301079 mutex_unlock(&mdp3_session->lock);
1080 return rc;
1081}
1082
Arun kumar162db222018-05-09 17:28:40 +05301083static bool mdp3_is_twm_en(void)
1084{
1085 return mdp3_res->twm_en;
1086}
1087
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301088static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
1089{
1090 int rc = 0;
Arun kumardb962812018-05-30 16:31:52 +05301091 int client = 0;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301092 bool intf_stopped = true;
1093 struct mdp3_session_data *mdp3_session;
1094 struct mdss_panel_data *panel;
Abhijith Desaib502b282018-09-12 14:48:22 +05301095 u32 framerate = 0;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301096
1097 pr_debug("mdp3_ctrl_off\n");
1098 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
1099 if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
1100 !mdp3_session->intf) {
1101 pr_err("mdp3_ctrl_on no device");
1102 return -ENODEV;
1103 }
1104
1105 /*
1106 * Keep a reference to the runtime pm until the overlay is turned
1107 * off, and then release this last reference at the end. This will
1108 * help in distinguishing between idle power collapse versus suspend
1109 * power collapse
1110 */
1111 pm_runtime_get_sync(&mdp3_res->pdev->dev);
1112
Animesh Kishore96d4f7e2018-11-26 17:53:53 +05301113 MDSS_XLOG(XLOG_FUNC_ENTRY, __LINE__, mdss_fb_is_power_on_lp(mfd),
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301114 mfd->panel_power_state);
1115 panel = mdp3_session->panel;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301116
Arun kumar04d4a922018-05-23 16:22:45 +05301117 cancel_work_sync(&mdp3_session->clk_off_work);
Arun kumarcefb7d12018-05-23 18:12:25 +05301118 mutex_lock(&mdp3_session->lock);
1119 MDSS_XLOG(0x111);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301120 pr_debug("Requested power state = %d\n", mfd->panel_power_state);
1121 if (mdss_fb_is_power_on_lp(mfd)) {
1122 /*
1123 * Transition to low power
1124 * As display updates are expected in low power mode,
1125 * keep the interface and clocks on.
1126 */
1127 intf_stopped = false;
1128 } else {
1129 /* Transition to display off */
1130 if (!mdp3_session->status) {
1131 pr_debug("fb%d is off already", mfd->index);
1132 goto off_error;
1133 }
Arun kumar162db222018-05-09 17:28:40 +05301134 if (panel && panel->set_backlight) {
1135 if (!mdp3_is_twm_en())
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301136 panel->set_backlight(panel, 0);
Arun kumar162db222018-05-09 17:28:40 +05301137 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301138 }
1139
1140 /*
1141 * While transitioning from interactive to low power,
1142 * events need to be sent to the interface so that the
1143 * panel can be configured in low power mode
1144 */
Arun kumaraa11bb22018-05-09 16:05:42 +05301145 if (!mdp3_is_twm_en()) {
1146 if (panel->event_handler)
1147 rc = panel->event_handler(panel, MDSS_EVENT_BLANK,
1148 (void *) (long int)mfd->panel_power_state);
1149 if (rc)
1150 pr_err("EVENT_BLANK error (%d)\n", rc);
1151 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301152 if (intf_stopped) {
1153 if (!mdp3_session->clk_on)
1154 mdp3_ctrl_clk_enable(mfd, 1);
1155 /* PP related programming for ctrl off */
1156 mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
1157 mutex_lock(&mdp3_session->dma->pp_lock);
1158 mdp3_session->dma->ccs_config.ccs_dirty = false;
1159 mdp3_session->dma->lut_config.lut_dirty = false;
1160 mutex_unlock(&mdp3_session->dma->pp_lock);
1161
1162 rc = mdp3_session->dma->stop(mdp3_session->dma,
1163 mdp3_session->intf);
1164 if (rc)
1165 pr_debug("fail to stop the MDP3 dma\n");
1166 /* Wait to ensure TG to turn off */
1167 msleep(20);
1168 mfd->panel_info->cont_splash_enabled = 0;
1169
1170 /* Disable Auto refresh once continuous splash disabled */
1171 mdp3_autorefresh_disable(mfd->panel_info);
1172 mdp3_splash_done(mfd->panel_info);
1173
1174 mdp3_irq_deregister();
1175 }
1176
Arun kumar162db222018-05-09 17:28:40 +05301177 if (panel->event_handler) {
Arun kumarec570b72018-05-09 20:23:38 +05301178 if (mdp3_is_twm_en()) {
1179 pr_info("TWM active skip panel off, disable disp_en\n");
1180 if (gpio_is_valid(panel->panel_en_gpio)) {
1181 rc = gpio_direction_output(
1182 panel->panel_en_gpio, 1);
1183 if (rc) {
1184 pr_err("%s:set dir for gpio(%d) FAIL\n",
1185 __func__, panel->panel_en_gpio);
1186 } else {
1187 gpio_set_value((panel->panel_en_gpio), 0);
1188 usleep_range(100, 110);
1189 pr_debug("%s:set disp_en_gpio_%d Low\n",
1190 __func__, panel->panel_en_gpio);
1191 }
1192 }
1193 } else {
Arun kumar162db222018-05-09 17:28:40 +05301194 rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF,
1195 (void *) (long int)mfd->panel_power_state);
Arun kumarec570b72018-05-09 20:23:38 +05301196 }
Arun kumar162db222018-05-09 17:28:40 +05301197 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301198 if (rc)
1199 pr_err("EVENT_PANEL_OFF error (%d)\n", rc);
1200
1201 if (intf_stopped) {
1202 if (mdp3_session->clk_on) {
1203 pr_debug("mdp3_ctrl_off stop clock\n");
1204 if (panel->event_handler &&
1205 (panel->panel_info.type == MIPI_CMD_PANEL)) {
1206 struct dsi_panel_clk_ctrl clk_ctrl;
1207
1208 clk_ctrl.state = MDSS_DSI_CLK_OFF;
1209 clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT;
1210 rc |= panel->event_handler(panel,
1211 MDSS_EVENT_PANEL_CLK_CTRL,
1212 (void *)&clk_ctrl);
1213 }
1214
1215 rc = mdp3_dynamic_clock_gating_ctrl(1);
1216 rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);
1217 if (rc)
1218 pr_err("mdp clock resource release failed\n");
1219 }
1220
1221 mdp3_ctrl_notifier_unregister(mdp3_session,
1222 &mdp3_session->mfd->mdp_sync_pt_data.notifier);
1223
1224 mdp3_session->vsync_enabled = 0;
1225 atomic_set(&mdp3_session->vsync_countdown, 0);
1226 atomic_set(&mdp3_session->dma_done_cnt, 0);
1227 mdp3_session->clk_on = 0;
1228 mdp3_session->in_splash_screen = 0;
1229 mdp3_res->solid_fill_vote_en = false;
1230 mdp3_session->status = 0;
1231 if (atomic_dec_return(&mdp3_res->active_intf_cnt) != 0) {
1232 pr_warn("active_intf_cnt unbalanced\n");
1233 atomic_set(&mdp3_res->active_intf_cnt, 0);
1234 }
1235 /*
1236 * Release the pm runtime reference held when
1237 * idle pc feature is not enabled
1238 */
1239 if (!mdp3_res->idle_pc_enabled ||
1240 (mfd->panel_info->type != MIPI_CMD_PANEL)) {
1241 rc = pm_runtime_put(&mdp3_res->pdev->dev);
1242 if (rc)
1243 pr_err("%s: pm_runtime_put failed (rc %d)\n",
1244 __func__, rc);
1245 }
Arun kumardb962812018-05-30 16:31:52 +05301246 client = mdp3_get_ion_client(mfd);
1247 mdp3_bufq_deinit(&mdp3_session->bufq_out, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301248 if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
1249 mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
Arun kumardb962812018-05-30 16:31:52 +05301250 mdp3_bufq_deinit(&mdp3_session->bufq_in, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301251 }
1252 }
1253
Animesh Kishore96d4f7e2018-11-26 17:53:53 +05301254 if (mdss_fb_is_power_on_lp(mfd) &&
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301255 (mfd->panel.type == MIPI_CMD_PANEL)) {
Animesh Kishore96d4f7e2018-11-26 17:53:53 +05301256 pr_debug("%s: Disable MDP3 clocks in LP\n", __func__);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301257 if (!mdp3_session->clk_on)
1258 mdp3_ctrl_clk_enable(mfd, 1);
1259 /*
1260 * STOP DMA transfer first and signal vsync notification
1261 * Before releasing the resource in ULP state.
1262 */
1263 rc = mdp3_session->dma->stop(mdp3_session->dma,
1264 mdp3_session->intf);
1265 if (rc)
Animesh Kishore96d4f7e2018-11-26 17:53:53 +05301266 pr_warn("fail to stop the MDP3 dma in LP\n");
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301267 /* Wait to ensure TG to turn off */
1268 msleep(20);
1269 /*
1270 * Handle ULP request initiated from fb_pm_suspend.
1271 * For ULP panel power state disabling vsync and set
1272 * vsync_count to zero and Turn off MDP3 clocks
1273 */
1274 atomic_set(&mdp3_session->vsync_countdown, 0);
1275 mdp3_session->vsync_enabled = 0;
1276 mdp3_ctrl_vsync_enable(mdp3_session->mfd, 0);
1277 mdp3_ctrl_clk_enable(mdp3_session->mfd, 0);
1278 }
1279off_error:
Arun kumardb962812018-05-30 16:31:52 +05301280 if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
1281 mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
1282 mdp3_bufq_deinit(&mdp3_session->bufq_in, client);
1283 }
Abhijith Desaib502b282018-09-12 14:48:22 +05301284
1285 framerate = mdss_panel_get_framerate(mfd->panel_info,
1286 FPS_RESOLUTION_HZ);
1287 if (framerate != 0)
1288 mdp3_session->dma->vsync_period = DIV_ROUND_UP(1000, framerate);
1289
1290 MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__, framerate);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301291 mutex_unlock(&mdp3_session->lock);
1292 /* Release the last reference to the runtime device */
1293 pm_runtime_put(&mdp3_res->pdev->dev);
1294
1295 return 0;
1296}
1297
1298int mdp3_ctrl_reset(struct msm_fb_data_type *mfd)
1299{
1300 int rc = 0;
1301 struct mdp3_session_data *mdp3_session;
1302 struct mdp3_dma *mdp3_dma;
1303 struct mdss_panel_data *panel;
1304 struct mdp3_notification vsync_client;
1305
1306 pr_debug("mdp3_ctrl_reset\n");
1307 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
1308 if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
1309 !mdp3_session->intf) {
1310 pr_err("mdp3_ctrl_reset no device");
1311 return -ENODEV;
1312 }
1313
1314 panel = mdp3_session->panel;
1315 mdp3_dma = mdp3_session->dma;
1316 mutex_lock(&mdp3_session->lock);
1317 pr_debug("mdp3_ctrl_reset idle_pc %s FS_EN %s\n",
1318 mdp3_res->idle_pc ? "True":"False",
1319 mdp3_res->fs_ena ? "True":"False");
1320 if (mdp3_res->idle_pc) {
1321 mdp3_clk_enable(1, 0);
1322 mdp3_dynamic_clock_gating_ctrl(0);
1323 mdp3_qos_remapper_setup(panel);
1324 }
1325
1326 /*Map the splash addr for VIDEO mode panel before smmu attach*/
1327 if ((mfd->panel.type == MIPI_VIDEO_PANEL) &&
1328 (mdp3_session->in_splash_screen)) {
1329 rc = mdss_smmu_map(MDSS_IOMMU_DOMAIN_UNSECURE,
1330 mdp3_res->splash_mem_addr,
1331 mdp3_res->splash_mem_addr,
1332 mdp3_res->splash_mem_size,
1333 IOMMU_READ | IOMMU_NOEXEC);
1334 }
1335
1336 rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
1337 if (rc) {
1338 pr_err("fail to attach dma iommu\n");
1339 if (mdp3_res->idle_pc)
1340 mdp3_clk_enable(0, 0);
1341 goto reset_error;
1342 }
1343
1344 vsync_client = mdp3_dma->vsync_client;
1345
1346 mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
1347 mdp3_ctrl_dma_init(mfd, mdp3_dma);
1348 mdp3_ppp_init();
1349 mdp3_ctrl_pp_resume(mfd);
1350 if (vsync_client.handler)
1351 mdp3_dma->vsync_enable(mdp3_dma, &vsync_client);
1352
1353 if (!mdp3_res->idle_pc) {
1354 mdp3_session->first_commit = true;
1355 mfd->panel_info->cont_splash_enabled = 0;
1356 mdp3_session->in_splash_screen = 0;
1357 mdp3_splash_done(mfd->panel_info);
1358 /* Disable Auto refresh */
1359 mdp3_autorefresh_disable(mfd->panel_info);
1360 } else {
1361 mdp3_res->idle_pc = false;
1362 mdp3_clk_enable(0, 0);
1363 mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
1364 }
1365
1366reset_error:
1367 mutex_unlock(&mdp3_session->lock);
1368 return rc;
1369}
1370
1371static int mdp3_overlay_get(struct msm_fb_data_type *mfd,
1372 struct mdp_overlay *req)
1373{
1374 int rc = 0;
1375 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1376
1377 mutex_lock(&mdp3_session->lock);
1378
1379 if (mdp3_session->overlay.id == req->id)
1380 *req = mdp3_session->overlay;
1381 else
1382 rc = -EINVAL;
1383
1384 mutex_unlock(&mdp3_session->lock);
1385
1386 return rc;
1387}
1388
1389static int mdp3_overlay_set(struct msm_fb_data_type *mfd,
1390 struct mdp_overlay *req)
1391{
1392 int rc = 0;
1393 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1394 struct mdp3_dma *dma = mdp3_session->dma;
1395 struct fb_fix_screeninfo *fix;
1396 struct fb_info *fbi = mfd->fbi;
1397 int stride;
1398 int format;
1399
1400 fix = &fbi->fix;
1401 stride = req->src.width * ppp_bpp(req->src.format);
1402 format = mdp3_ctrl_get_source_format(req->src.format);
1403
1404
1405 if (mdp3_session->overlay.id != req->id)
1406 pr_err("overlay was not released, continue to recover\n");
1407 /*
1408 * A change in overlay structure will always come with
1409 * MSMFB_NEW_REQUEST for MDP3
1410 */
1411 if (req->id == MSMFB_NEW_REQUEST) {
1412 mutex_lock(&mdp3_session->lock);
1413 if (dma->source_config.stride != stride ||
1414 dma->source_config.format != format) {
1415 dma->source_config.format = format;
1416 dma->source_config.stride = stride;
1417 dma->output_config.pack_pattern =
1418 mdp3_ctrl_get_pack_pattern(req->src.format);
1419 dma->update_src_cfg = true;
1420 }
1421 mdp3_session->overlay = *req;
1422 mdp3_session->overlay.id = 1;
1423 req->id = 1;
1424 mutex_unlock(&mdp3_session->lock);
1425 }
1426
1427 return rc;
1428}
1429
1430static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
1431{
1432 int rc = 0;
1433 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1434 struct fb_info *fbi = mfd->fbi;
1435 struct fb_fix_screeninfo *fix;
1436 int format;
Arun kumardb962812018-05-30 16:31:52 +05301437 int client;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301438
1439 fix = &fbi->fix;
1440 format = mdp3_ctrl_get_source_format(mfd->fb_imgType);
1441 mutex_lock(&mdp3_session->lock);
1442
Arun kumardb962812018-05-30 16:31:52 +05301443 client = mdp3_get_ion_client(mfd);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301444 if (mdp3_session->overlay.id == ndx && ndx == 1) {
1445 mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
Arun kumardb962812018-05-30 16:31:52 +05301446 mdp3_bufq_deinit(&mdp3_session->bufq_in, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301447 } else {
1448 rc = -EINVAL;
1449 }
1450
1451 mutex_unlock(&mdp3_session->lock);
1452
1453 return rc;
1454}
1455
1456static int mdp3_overlay_queue_buffer(struct msm_fb_data_type *mfd,
1457 struct msmfb_overlay_data *req)
1458{
1459 int rc;
1460 bool is_panel_type_cmd = false;
1461 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1462 struct msmfb_data *img = &req->data;
1463 struct mdp3_img_data data;
1464 struct mdp3_dma *dma = mdp3_session->dma;
Arun kumardb962812018-05-30 16:31:52 +05301465 int client;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301466
Arun kumardb962812018-05-30 16:31:52 +05301467 client = mdp3_get_ion_client(mfd);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301468 memset(&data, 0, sizeof(struct mdp3_img_data));
Arun kumardb962812018-05-30 16:31:52 +05301469 if (mfd->panel.type == MIPI_CMD_PANEL || client == MDP3_CLIENT_SPI)
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301470 is_panel_type_cmd = true;
1471 if (is_panel_type_cmd) {
Arun kumardb962812018-05-30 16:31:52 +05301472 rc = mdp3_iommu_enable(client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301473 if (rc) {
1474 pr_err("fail to enable iommu\n");
1475 return rc;
1476 }
1477 }
Arun kumardb962812018-05-30 16:31:52 +05301478 rc = mdp3_get_img(img, &data, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301479 if (rc) {
1480 pr_err("fail to get overlay buffer\n");
1481 goto err;
1482 }
1483
1484 if (data.len < dma->source_config.stride * dma->source_config.height) {
1485 pr_err("buf size(0x%lx) is smaller than dma config(0x%x)\n",
1486 data.len, (dma->source_config.stride *
1487 dma->source_config.height));
Arun kumardb962812018-05-30 16:31:52 +05301488 mdp3_put_img(&data, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301489 rc = -EINVAL;
1490 goto err;
1491 }
1492 rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data);
1493 if (rc) {
1494 pr_err("fail to queue the overlay buffer, buffer drop\n");
Arun kumardb962812018-05-30 16:31:52 +05301495 mdp3_put_img(&data, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301496 goto err;
1497 }
1498 rc = 0;
1499err:
1500 if (is_panel_type_cmd)
1501 mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
1502 return rc;
1503}
1504
1505static int mdp3_overlay_play(struct msm_fb_data_type *mfd,
1506 struct msmfb_overlay_data *req)
1507{
1508 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
1509 int rc = 0;
1510
1511 pr_debug("mdp3_overlay_play req id=%x mem_id=%d\n",
1512 req->id, req->data.memory_id);
1513
1514 mutex_lock(&mdp3_session->lock);
1515
1516 if (mdp3_session->overlay.id == MSMFB_NEW_REQUEST) {
1517 pr_err("overlay play without overlay set first\n");
1518 mutex_unlock(&mdp3_session->lock);
1519 return -EINVAL;
1520 }
1521
1522 if (mdss_fb_is_power_on(mfd))
1523 rc = mdp3_overlay_queue_buffer(mfd, req);
1524 else
1525 rc = -EPERM;
1526
1527 mutex_unlock(&mdp3_session->lock);
1528
1529 return rc;
1530}
1531
1532bool update_roi(struct mdp3_rect oldROI, struct mdp_rect newROI)
1533{
1534 return ((newROI.x != oldROI.x) || (newROI.y != oldROI.y) ||
1535 (newROI.w != oldROI.w) || (newROI.h != oldROI.h));
1536}
1537
1538bool is_roi_valid(struct mdp3_dma_source source_config, struct mdp_rect roi)
1539{
1540 return (roi.w > 0) && (roi.h > 0) &&
1541 (roi.x >= source_config.x) &&
1542 ((roi.x + roi.w) <= source_config.width) &&
1543 (roi.y >= source_config.y) &&
1544 ((roi.y + roi.h) <= source_config.height);
1545}
1546
1547static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd,
1548 struct mdp_display_commit *cmt_data)
1549{
1550 struct mdp3_session_data *mdp3_session;
1551 struct mdp3_img_data *data;
1552 struct mdss_panel_info *panel_info;
1553 int rc = 0;
Arun kumardb962812018-05-30 16:31:52 +05301554 int client;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301555 static bool splash_done;
1556 struct mdss_panel_data *panel;
Arun kumardb962812018-05-30 16:31:52 +05301557 int frame_rate = DEFAULT_FRAME_RATE;
1558 int stride;
Abhijith Desai49898e72018-09-11 16:03:34 +05301559 int prev_bl;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301560
1561 if (!mfd || !mfd->mdp.private1)
1562 return -EINVAL;
1563
1564 panel_info = mfd->panel_info;
1565 mdp3_session = mfd->mdp.private1;
1566 if (!mdp3_session || !mdp3_session->dma)
1567 return -EINVAL;
1568
Arun kumardb962812018-05-30 16:31:52 +05301569 frame_rate = mdss_panel_get_framerate(panel_info, FPS_RESOLUTION_HZ);
1570 client = mdp3_get_ion_client(mfd);
1571
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301572 if (mdp3_bufq_count(&mdp3_session->bufq_in) == 0) {
1573 pr_debug("no buffer in queue yet\n");
1574 return -EPERM;
1575 }
1576
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301577 panel = mdp3_session->panel;
1578 mutex_lock(&mdp3_res->fs_idle_pc_lock);
1579 if (mdp3_session->in_splash_screen ||
1580 mdp3_res->idle_pc) {
1581 pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__,
1582 mdp3_session->in_splash_screen, mdp3_res->idle_pc);
1583 rc = mdp3_ctrl_reset(mfd);
1584 if (rc) {
1585 pr_err("fail to reset display\n");
1586 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
1587 return -EINVAL;
1588 }
Abhijith Desaib7dabd92018-09-11 17:07:19 +05301589 if ((mdp3_session->dma->roi.x || mdp3_session->dma->roi.y) &&
1590 panel_info->partial_update_enabled)
1591 mdp3_session->dma->update_src_cfg = true;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301592 }
1593 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
1594
Arun kumarcefb7d12018-05-23 18:12:25 +05301595 cancel_work_sync(&mdp3_session->clk_off_work);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301596 mutex_lock(&mdp3_session->lock);
1597
1598 if (!mdp3_session->status) {
1599 pr_err("%s, display off!\n", __func__);
1600 mutex_unlock(&mdp3_session->lock);
1601 return -EPERM;
1602 }
Abhijith Desaib502b282018-09-12 14:48:22 +05301603 MDSS_XLOG(0x111, mdp3_session->dma->vsync_period);
1604
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301605 mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
1606 data = mdp3_bufq_pop(&mdp3_session->bufq_in);
1607 if (data) {
1608 mdp3_ctrl_reset_countdown(mdp3_session, mfd);
1609 mdp3_ctrl_clk_enable(mfd, 1);
Arun kumardb962812018-05-30 16:31:52 +05301610 stride = mdp3_session->dma->source_config.stride;
1611 if (mdp3_ctrl_get_intf_type(mfd) ==
1612 MDP3_DMA_OUTPUT_SEL_SPI_CMD){
1613 mdp3_session->intf->active = false;
1614 msm_ion_do_cache_op(mdp3_res->ion_client,
1615 data->srcp_ihdl, (void *)(int)data->addr,
1616 data->len, ION_IOC_INV_CACHES);
1617 rc = mdss_spi_panel_kickoff(mdp3_session->panel,
1618 (void *)(int)data->addr, (int)data->len,
1619 stride);
1620 } else if (mdp3_session->dma->update_src_cfg &&
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301621 panel_info->partial_update_enabled) {
1622 panel->panel_info.roi.x = mdp3_session->dma->roi.x;
1623 panel->panel_info.roi.y = mdp3_session->dma->roi.y;
1624 panel->panel_info.roi.w = mdp3_session->dma->roi.w;
1625 panel->panel_info.roi.h = mdp3_session->dma->roi.h;
1626 rc = mdp3_session->dma->update(mdp3_session->dma,
1627 (void *)(int)data->addr,
1628 mdp3_session->intf, (void *)panel);
1629 } else {
1630 rc = mdp3_session->dma->update(mdp3_session->dma,
1631 (void *)(int)data->addr,
1632 mdp3_session->intf, NULL);
1633 }
1634 /* This is for the previous frame */
1635 if (rc < 0) {
1636 mdp3_ctrl_notify(mdp3_session,
1637 MDP_NOTIFY_FRAME_TIMEOUT);
1638 } else {
1639 if (mdp3_ctrl_get_intf_type(mfd) ==
Arun kumardb962812018-05-30 16:31:52 +05301640 MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
1641 mdp3_ctrl_get_intf_type(mfd) ==
1642 MDP3_DMA_OUTPUT_SEL_SPI_CMD) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301643 mdp3_ctrl_notify(mdp3_session,
1644 MDP_NOTIFY_FRAME_DONE);
1645 }
1646 }
1647 mdp3_session->dma_active = 1;
Arun kumar52b7f182018-05-23 15:12:27 +05301648 reinit_completion(&mdp3_session->dma_completion);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301649 mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
1650 mdp3_bufq_push(&mdp3_session->bufq_out, data);
1651 }
1652
1653 if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
1654 mdp3_release_splash_memory(mfd);
1655 data = mdp3_bufq_pop(&mdp3_session->bufq_out);
1656 if (data)
Arun kumardb962812018-05-30 16:31:52 +05301657 mdp3_put_img(data, client);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301658 }
1659
1660 if (mdp3_session->first_commit) {
1661 /*wait to ensure frame is sent to panel*/
1662 if (panel_info->mipi.post_init_delay)
Arun kumardb962812018-05-30 16:31:52 +05301663 msleep(((1000 / frame_rate) + 1) *
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301664 panel_info->mipi.post_init_delay);
1665 else
Arun kumardb962812018-05-30 16:31:52 +05301666 msleep((1000 / frame_rate) + 1);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301667 mdp3_session->first_commit = false;
1668 if (panel)
1669 rc |= panel->event_handler(panel,
1670 MDSS_EVENT_POST_PANEL_ON, NULL);
1671 }
1672
1673 mdp3_session->vsync_before_commit = 0;
Abhijith Desai49898e72018-09-11 16:03:34 +05301674 prev_bl = mfd->bl_level;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301675 if (!splash_done || mdp3_session->esd_recovery == true) {
Abhijith Desai49898e72018-09-11 16:03:34 +05301676 if (panel && panel->set_backlight) {
1677 if (mdp3_session->esd_recovery == true && prev_bl > 0)
1678 panel->set_backlight(panel, prev_bl);
1679 else
1680 panel->set_backlight(panel,
1681 panel->panel_info.bl_max);
1682 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301683 splash_done = true;
1684 mdp3_session->esd_recovery = false;
1685 }
1686
Arun kumardb962812018-05-30 16:31:52 +05301687 /*Update backlight only if its changed*/
1688 if (mdp3_res->bklt_level && mdp3_res->bklt_update) {
1689 mdss_spi_panel_bl_ctrl_update(panel, mdp3_res->bklt_level);
1690 mdp3_res->bklt_update = false;
1691 }
1692
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301693 /* start vsync tick countdown for cmd mode if vsync isn't enabled */
1694 if (mfd->panel.type == MIPI_CMD_PANEL && !mdp3_session->vsync_enabled)
1695 mdp3_ctrl_vsync_enable(mdp3_session->mfd, 0);
1696
1697 mutex_unlock(&mdp3_session->lock);
1698
1699 mdss_fb_update_notify_update(mfd);
1700
1701 return 0;
1702}
1703
1704static int mdp3_map_pan_buff_immediate(struct msm_fb_data_type *mfd)
1705{
1706 int rc = 0;
1707 unsigned long length;
1708 dma_addr_t addr;
1709 int domain = mfd->mdp.fb_mem_get_iommu_domain();
1710
1711 rc = mdss_smmu_map_dma_buf(mfd->fbmem_buf, mfd->fb_table, domain,
1712 &addr, &length, DMA_BIDIRECTIONAL);
1713 if (IS_ERR_VALUE(rc))
1714 goto err_unmap;
1715 else
1716 mfd->iova = addr;
1717
1718 pr_debug("%s : smmu map dma buf VA: (%llx) MFD->iova %llx\n",
1719 __func__, (u64) addr, (u64) mfd->iova);
1720 return rc;
1721
1722err_unmap:
1723 pr_err("smmu map dma buf failed: (%d)\n", rc);
1724 dma_buf_unmap_attachment(mfd->fb_attachment, mfd->fb_table,
1725 mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL));
1726 dma_buf_detach(mfd->fbmem_buf, mfd->fb_attachment);
1727 dma_buf_put(mfd->fbmem_buf);
1728 return rc;
1729}
1730
1731static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
1732{
1733 struct fb_info *fbi;
1734 struct mdp3_session_data *mdp3_session;
1735 u32 offset;
1736 int bpp;
1737 struct mdss_panel_info *panel_info;
1738 static bool splash_done;
1739 struct mdss_panel_data *panel;
1740
1741 int rc;
1742
1743 pr_debug("mdp3_ctrl_pan_display\n");
1744 if (!mfd || !mfd->mdp.private1)
1745 return;
1746
1747 panel_info = mfd->panel_info;
1748 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
1749 if (!mdp3_session || !mdp3_session->dma)
1750 return;
1751
1752 mutex_lock(&mdp3_res->fs_idle_pc_lock);
1753 if (mdp3_session->in_splash_screen ||
1754 mdp3_res->idle_pc) {
1755 pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__,
1756 mdp3_session->in_splash_screen, mdp3_res->idle_pc);
1757 rc = mdp3_ctrl_reset(mfd);
1758 if (rc) {
1759 pr_err("fail to reset display\n");
1760 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
1761 return;
1762 }
1763 }
1764 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
1765
1766 mutex_lock(&mdp3_session->lock);
1767
1768 if (!mdp3_session->status) {
1769 pr_err("mdp3_ctrl_pan_display, display off!\n");
1770 goto pan_error;
1771 }
1772
1773 fbi = mfd->fbi;
1774
1775 bpp = fbi->var.bits_per_pixel / 8;
1776 offset = fbi->var.xoffset * bpp +
1777 fbi->var.yoffset * fbi->fix.line_length;
1778
1779 if (offset > fbi->fix.smem_len) {
1780 pr_err("invalid fb offset=%u total length=%u\n",
1781 offset, fbi->fix.smem_len);
1782 goto pan_error;
1783 }
1784
1785 if (mfd->fbi->screen_base) {
1786 mdp3_ctrl_reset_countdown(mdp3_session, mfd);
1787 mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
1788 mdp3_ctrl_clk_enable(mfd, 1);
1789 if (mdp3_session->first_commit) {
1790 rc = mdp3_map_pan_buff_immediate(mfd);
1791 if (IS_ERR_VALUE(rc))
1792 goto pan_error;
1793 }
1794 rc = mdp3_session->dma->update(mdp3_session->dma,
1795 (void *)(int)(mfd->iova + offset),
1796 mdp3_session->intf, NULL);
1797 /* This is for the previous frame */
1798 if (rc < 0) {
1799 mdp3_ctrl_notify(mdp3_session,
1800 MDP_NOTIFY_FRAME_TIMEOUT);
1801 } else {
1802 if (mdp3_ctrl_get_intf_type(mfd) ==
1803 MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
1804 mdp3_ctrl_notify(mdp3_session,
1805 MDP_NOTIFY_FRAME_DONE);
1806 }
1807 }
1808 mdp3_session->dma_active = 1;
Arun kumar52b7f182018-05-23 15:12:27 +05301809 reinit_completion(&mdp3_session->dma_completion);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301810 mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
1811 } else {
1812 pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
1813 mdp3_clk_enable(1, 0);
1814 mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
1815 mdp3_clk_enable(0, 0);
1816 }
1817
1818 panel = mdp3_session->panel;
Arun kumardb962812018-05-30 16:31:52 +05301819 if (mdp3_ctrl_get_intf_type(mfd) != MDP3_DMA_OUTPUT_SEL_SPI_CMD) {
1820 if (mdp3_session->first_commit) {
1821 if (panel_info->mipi.init_delay)
1822 msleep(((1000 / panel_info->mipi.frame_rate)
1823 + 1) * panel_info->mipi.post_init_delay);
1824 else
1825 msleep(1000 / panel_info->mipi.frame_rate);
1826 mdp3_session->first_commit = false;
1827 if (panel)
1828 panel->event_handler(panel,
1829 MDSS_EVENT_POST_PANEL_ON, NULL);
1830 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301831 }
1832
1833 mdp3_session->vsync_before_commit = 0;
1834 if (!splash_done || mdp3_session->esd_recovery == true) {
1835 if (panel && panel->set_backlight)
1836 panel->set_backlight(panel, panel->panel_info.bl_max);
1837 splash_done = true;
1838 mdp3_session->esd_recovery = false;
1839 }
1840
Arun kumardb962812018-05-30 16:31:52 +05301841 /*Update backlight only if its changed*/
1842 if (mdp3_res->bklt_level && mdp3_res->bklt_update) {
1843 mdss_spi_panel_bl_ctrl_update(panel, mdp3_res->bklt_level);
1844 mdp3_res->bklt_update = false;
1845 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301846
1847pan_error:
1848 mutex_unlock(&mdp3_session->lock);
1849}
1850
1851static int mdp3_set_metadata(struct msm_fb_data_type *mfd,
1852 struct msmfb_metadata *metadata_ptr)
1853{
1854 int ret = 0;
1855
1856 switch (metadata_ptr->op) {
1857 case metadata_op_crc:
1858 ret = mdp3_ctrl_res_req_clk(mfd, 1);
1859 if (ret) {
1860 pr_err("failed to turn on mdp clks\n");
1861 return ret;
1862 }
1863 ret = mdp3_misr_set(&metadata_ptr->data.misr_request);
1864 ret = mdp3_ctrl_res_req_clk(mfd, 0);
1865 if (ret) {
1866 pr_err("failed to release mdp clks\n");
1867 return ret;
1868 }
1869 break;
1870 default:
1871 pr_warn("Unsupported request to MDP SET META IOCTL.\n");
1872 ret = -EINVAL;
1873 break;
1874 }
1875 return ret;
1876}
1877
1878static int mdp3_get_metadata(struct msm_fb_data_type *mfd,
1879 struct msmfb_metadata *metadata)
1880{
1881 int ret = 0;
1882
1883 switch (metadata->op) {
1884 case metadata_op_frame_rate:
1885 metadata->data.panel_frame_rate =
Arun kumardb962812018-05-30 16:31:52 +05301886 mdss_panel_get_framerate(mfd->panel_info,
1887 FPS_RESOLUTION_HZ);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301888 break;
1889 case metadata_op_get_caps:
1890 metadata->data.caps.mdp_rev = 305;
1891 metadata->data.caps.rgb_pipes = 0;
1892 metadata->data.caps.vig_pipes = 0;
1893 metadata->data.caps.dma_pipes = 1;
1894 break;
1895 case metadata_op_crc:
1896 ret = mdp3_ctrl_res_req_clk(mfd, 1);
1897 if (ret) {
1898 pr_err("failed to turn on mdp clks\n");
1899 return ret;
1900 }
1901 ret = mdp3_misr_get(&metadata->data.misr_request);
1902 ret = mdp3_ctrl_res_req_clk(mfd, 0);
1903 if (ret) {
1904 pr_err("failed to release mdp clks\n");
1905 return ret;
1906 }
1907 break;
1908 case metadata_op_get_ion_fd:
Sachin Bhayaref4932612018-04-03 20:09:12 +05301909 if (mfd->fb_ion_handle && mfd->fb_ion_client) {
Sachin Bhayare5fb6b9b2018-04-12 18:57:52 +05301910 get_dma_buf(mfd->fbmem_buf);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301911 metadata->data.fbmem_ionfd =
Sachin Bhayaref4932612018-04-03 20:09:12 +05301912 ion_share_dma_buf_fd(mfd->fb_ion_client,
1913 mfd->fb_ion_handle);
Sachin Bhayare5fb6b9b2018-04-12 18:57:52 +05301914 if (metadata->data.fbmem_ionfd < 0) {
1915 dma_buf_put(mfd->fbmem_buf);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301916 pr_err("fd allocation failed. fd = %d\n",
Sachin Bhayare5fb6b9b2018-04-12 18:57:52 +05301917 metadata->data.fbmem_ionfd);
1918 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301919 }
1920 break;
1921 default:
1922 pr_warn("Unsupported request to MDP GET META IOCTL.\n");
1923 ret = -EINVAL;
1924 break;
1925 }
1926 return ret;
1927}
1928
1929int mdp3_validate_start_req(struct mdp_histogram_start_req *req)
1930{
1931 if (req->frame_cnt >= MDP_HISTOGRAM_FRAME_COUNT_MAX) {
1932 pr_err("%s invalid req frame_cnt\n", __func__);
1933 return -EINVAL;
1934 }
1935 if (req->bit_mask >= MDP_HISTOGRAM_BIT_MASK_MAX) {
1936 pr_err("%s invalid req bit mask\n", __func__);
1937 return -EINVAL;
1938 }
1939 if (req->block != MDP_BLOCK_DMA_P ||
1940 req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
1941 pr_err("mdp3_histogram_start invalid request\n");
1942 return -EINVAL;
1943 }
1944 return 0;
1945}
1946
1947int mdp3_validate_scale_config(struct mdp_bl_scale_data *data)
1948{
1949 if (data->scale > MDP_HISTOGRAM_BL_SCALE_MAX) {
1950 pr_err("%s invalid bl_scale\n", __func__);
1951 return -EINVAL;
1952 }
1953 if (data->min_lvl > MDP_HISTOGRAM_BL_LEVEL_MAX) {
1954 pr_err("%s invalid bl_min_lvl\n", __func__);
1955 return -EINVAL;
1956 }
1957 return 0;
1958}
1959
1960int mdp3_validate_csc_data(struct mdp_csc_cfg_data *data)
1961{
1962 int i;
1963 bool mv_valid = false;
1964
1965 for (i = 0; i < 9; i++) {
1966 if (data->csc_data.csc_mv[i] >=
1967 MDP_HISTOGRAM_CSC_MATRIX_MAX)
1968 return -EINVAL;
1969 if ((!mv_valid) && (data->csc_data.csc_mv[i] != 0))
1970 mv_valid = true;
1971 }
1972 if (!mv_valid) {
1973 pr_err("%s: black screen data! csc_mv is all 0s\n", __func__);
1974 return -EINVAL;
1975 }
1976 for (i = 0; i < 3; i++) {
1977 if (data->csc_data.csc_pre_bv[i] >=
1978 MDP_HISTOGRAM_CSC_VECTOR_MAX)
1979 return -EINVAL;
1980 if (data->csc_data.csc_post_bv[i] >=
1981 MDP_HISTOGRAM_CSC_VECTOR_MAX)
1982 return -EINVAL;
1983 }
1984 for (i = 0; i < 6; i++) {
1985 if (data->csc_data.csc_pre_lv[i] >=
1986 MDP_HISTOGRAM_CSC_VECTOR_MAX)
1987 return -EINVAL;
1988 if (data->csc_data.csc_post_lv[i] >=
1989 MDP_HISTOGRAM_CSC_VECTOR_MAX)
1990 return -EINVAL;
1991 }
1992 return 0;
1993}
1994
1995static int mdp3_histogram_start(struct mdp3_session_data *session,
1996 struct mdp_histogram_start_req *req)
1997{
1998 int ret;
1999 struct mdp3_dma_histogram_config histo_config;
2000
2001 mutex_lock(&session->lock);
2002 if (!session->status) {
2003 mutex_unlock(&session->lock);
2004 return -EPERM;
2005 }
2006
2007 pr_debug("mdp3_histogram_start\n");
2008
2009 ret = mdp3_validate_start_req(req);
2010 if (ret) {
2011 mutex_unlock(&session->lock);
2012 return ret;
2013 }
2014
2015 if (!session->dma->histo_op ||
2016 !session->dma->config_histo) {
2017 pr_err("mdp3_histogram_start not supported\n");
2018 mutex_unlock(&session->lock);
2019 return -EINVAL;
2020 }
2021
2022 mutex_lock(&session->histo_lock);
2023
2024 if (session->histo_status) {
2025 pr_info("mdp3_histogram_start already started\n");
2026 mutex_unlock(&session->histo_lock);
2027 mutex_unlock(&session->lock);
2028 return 0;
2029 }
2030
2031 mdp3_res_update(1, 0, MDP3_CLIENT_DMA_P);
2032 ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_RESET);
2033 if (ret) {
2034 pr_err("mdp3_histogram_start reset error\n");
2035 goto histogram_start_err;
2036 }
2037
2038 histo_config.frame_count = req->frame_cnt;
2039 histo_config.bit_mask = req->bit_mask;
2040 histo_config.auto_clear_en = 1;
2041 histo_config.bit_mask_polarity = 0;
2042 ret = session->dma->config_histo(session->dma, &histo_config);
2043 if (ret) {
2044 pr_err("mdp3_histogram_start config error\n");
2045 goto histogram_start_err;
2046 }
2047
2048 ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_START);
2049 if (ret) {
2050 pr_err("mdp3_histogram_start config error\n");
2051 goto histogram_start_err;
2052 }
2053
2054 session->histo_status = 1;
2055
2056histogram_start_err:
2057 mdp3_res_update(0, 0, MDP3_CLIENT_DMA_P);
2058 mutex_unlock(&session->histo_lock);
2059 mutex_unlock(&session->lock);
2060 return ret;
2061}
2062
2063static int mdp3_histogram_stop(struct mdp3_session_data *session,
2064 u32 block)
2065{
2066 int ret;
2067
2068 pr_debug("mdp3_histogram_stop\n");
2069
2070 if (!session->dma->histo_op || block != MDP_BLOCK_DMA_P) {
2071 pr_err("mdp3_histogram_stop not supported\n");
2072 return -EINVAL;
2073 }
2074
2075 mutex_lock(&session->histo_lock);
2076
2077 if (!session->histo_status) {
2078 pr_debug("mdp3_histogram_stop already stopped!");
2079 ret = 0;
2080 goto histogram_stop_err;
2081 }
2082
2083 mdp3_clk_enable(1, 0);
2084 ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_CANCEL);
2085 mdp3_clk_enable(0, 0);
2086 if (ret)
2087 pr_err("mdp3_histogram_stop error\n");
2088
2089 session->histo_status = 0;
2090
2091histogram_stop_err:
2092 mutex_unlock(&session->histo_lock);
2093 return ret;
2094}
2095
2096static int mdp3_histogram_collect(struct mdp3_session_data *session,
2097 struct mdp_histogram_data *hist)
2098{
2099 int ret;
2100 struct mdp3_dma_histogram_data *mdp3_histo;
2101
2102 pr_debug("%s\n", __func__);
2103 if (!session->dma->get_histo) {
2104 pr_err("mdp3_histogram_collect not supported\n");
2105 return -EINVAL;
2106 }
2107
2108 mutex_lock(&session->histo_lock);
2109
2110 if (!session->histo_status) {
2111 pr_debug("mdp3_histogram_collect not started\n");
2112 mutex_unlock(&session->histo_lock);
2113 return -EPROTO;
2114 }
2115
2116 mutex_unlock(&session->histo_lock);
2117
2118 if (!session->clk_on) {
2119 pr_debug("mdp/dsi clock off currently\n");
2120 return -EPERM;
2121 }
2122
2123 mdp3_clk_enable(1, 0);
2124 ret = session->dma->get_histo(session->dma);
2125 mdp3_clk_enable(0, 0);
2126 if (ret) {
2127 pr_debug("mdp3_histogram_collect error = %d\n", ret);
2128 return ret;
2129 }
2130
2131 mdp3_histo = &session->dma->histo_data;
2132
2133 ret = copy_to_user(hist->c0, mdp3_histo->r_data,
2134 sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM);
2135 if (ret)
2136 return ret;
2137
2138 ret = copy_to_user(hist->c1, mdp3_histo->g_data,
2139 sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM);
2140 if (ret)
2141 return ret;
2142
2143 ret = copy_to_user(hist->c2, mdp3_histo->b_data,
2144 sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM);
2145 if (ret)
2146 return ret;
2147
2148 ret = copy_to_user(hist->extra_info, mdp3_histo->extra,
2149 sizeof(uint32_t) * 2);
2150 if (ret)
2151 return ret;
2152
2153 hist->bin_cnt = MDP_HISTOGRAM_BIN_NUM;
2154 hist->block = MDP_BLOCK_DMA_P;
2155 return ret;
2156}
2157
2158static int mdp3_bl_scale_config(struct msm_fb_data_type *mfd,
2159 struct mdp_bl_scale_data *data)
2160{
2161 int ret = 0;
2162 int curr_bl;
2163
2164 mutex_lock(&mfd->bl_lock);
2165 curr_bl = mfd->bl_level;
2166 mfd->bl_scale = data->scale;
2167 mfd->bl_min_lvl = data->min_lvl;
2168 pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
2169 mfd->bl_min_lvl);
2170
2171 /* update current backlight to use new scaling*/
2172 mdss_fb_set_backlight(mfd, curr_bl);
2173 mutex_unlock(&mfd->bl_lock);
2174 return ret;
2175}
2176
2177static int mdp3_csc_config(struct mdp3_session_data *session,
2178 struct mdp_csc_cfg_data *data)
2179{
2180 struct mdp3_dma_color_correct_config config;
2181 struct mdp3_dma_ccs ccs;
2182 int ret = -EINVAL;
2183
2184 if (!data->csc_data.csc_mv || !data->csc_data.csc_pre_bv ||
2185 !data->csc_data.csc_post_bv || !data->csc_data.csc_pre_lv ||
2186 !data->csc_data.csc_post_lv) {
2187 pr_err("%s : Invalid csc vectors", __func__);
2188 return -EINVAL;
2189 }
2190
2191 mutex_lock(&session->lock);
2192 mutex_lock(&session->dma->pp_lock);
2193 session->dma->cc_vect_sel = (session->dma->cc_vect_sel + 1) % 2;
2194
2195 config.ccs_enable = 1;
2196 config.ccs_sel = session->dma->cc_vect_sel;
2197 config.pre_limit_sel = session->dma->cc_vect_sel;
2198 config.post_limit_sel = session->dma->cc_vect_sel;
2199 config.pre_bias_sel = session->dma->cc_vect_sel;
2200 config.post_bias_sel = session->dma->cc_vect_sel;
2201 config.ccs_dirty = true;
2202
2203 ccs.mv = data->csc_data.csc_mv;
2204 ccs.pre_bv = data->csc_data.csc_pre_bv;
2205 ccs.post_bv = data->csc_data.csc_post_bv;
2206 ccs.pre_lv = data->csc_data.csc_pre_lv;
2207 ccs.post_lv = data->csc_data.csc_post_lv;
2208
2209 /* cache one copy of setting for suspend/resume reconfiguring */
2210 session->dma->ccs_cache = *data;
2211
2212 mdp3_clk_enable(1, 0);
2213 ret = session->dma->config_ccs(session->dma, &config, &ccs);
2214 mdp3_clk_enable(0, 0);
2215 mutex_unlock(&session->dma->pp_lock);
2216 mutex_unlock(&session->lock);
2217 return ret;
2218}
2219
2220static int mdp3_pp_ioctl(struct msm_fb_data_type *mfd,
2221 void __user *argp)
2222{
2223 int ret = -EINVAL;
2224 struct msmfb_mdp_pp mdp_pp;
2225 struct mdp_lut_cfg_data *lut;
2226 struct mdp3_session_data *mdp3_session;
2227
2228 if (!mfd || !mfd->mdp.private1)
2229 return -EINVAL;
2230
2231 mdp3_session = mfd->mdp.private1;
2232
2233 ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
2234 if (ret)
2235 return ret;
2236
2237 switch (mdp_pp.op) {
2238 case mdp_bl_scale_cfg:
2239 ret = mdp3_validate_scale_config(&mdp_pp.data.bl_scale_data);
2240 if (ret) {
2241 pr_err("%s: invalid scale config\n", __func__);
2242 break;
2243 }
2244 ret = mdp3_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
2245 &mdp_pp.data.bl_scale_data);
2246 break;
2247 case mdp_op_csc_cfg:
2248 /* Checking state of dyn_pu before programming CSC block */
2249 if (mdp3_session->dyn_pu_state) {
2250 pr_debug("Partial update feature is enabled.\n");
2251 return -EPERM;
2252 }
2253 ret = mdp3_validate_csc_data(&(mdp_pp.data.csc_cfg_data));
2254 if (ret) {
2255 pr_err("%s: invalid csc data\n", __func__);
2256 break;
2257 }
2258 ret = mdp3_csc_config(mdp3_session,
2259 &(mdp_pp.data.csc_cfg_data));
2260 break;
2261 case mdp_op_lut_cfg:
2262 lut = &mdp_pp.data.lut_cfg_data;
2263 if (lut->lut_type != mdp_lut_rgb) {
2264 pr_err("Lut type %d is not supported", lut->lut_type);
2265 return -EINVAL;
2266 }
2267 if (lut->data.rgb_lut_data.flags & MDP_PP_OPS_READ)
2268 ret = mdp3_ctrl_lut_read(mfd,
2269 &(lut->data.rgb_lut_data));
2270 else
2271 ret = mdp3_ctrl_lut_config(mfd,
2272 &(lut->data.rgb_lut_data));
2273 if (ret)
2274 pr_err("RGB LUT ioctl failed\n");
2275 else
2276 ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp));
2277 break;
2278
2279 default:
2280 pr_err("Unsupported request to MDP_PP IOCTL.\n");
2281 ret = -EINVAL;
2282 break;
2283 }
2284 if (!ret)
2285 ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp));
2286 return ret;
2287}
2288
2289static int mdp3_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
2290 void __user *argp)
2291{
Arun kumar47145e02018-03-23 22:07:51 +05302292 int ret = -ENOTSUPP;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302293 struct mdp_histogram_data hist;
2294 struct mdp_histogram_start_req hist_req;
2295 u32 block;
2296 struct mdp3_session_data *mdp3_session;
2297
2298 if (!mfd || !mfd->mdp.private1)
2299 return -EINVAL;
2300
2301 mdp3_session = mfd->mdp.private1;
2302
2303 switch (cmd) {
2304 case MSMFB_HISTOGRAM_START:
2305 ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
2306 if (ret)
2307 return ret;
2308
2309 ret = mdp3_histogram_start(mdp3_session, &hist_req);
2310 break;
2311
2312 case MSMFB_HISTOGRAM_STOP:
2313 ret = copy_from_user(&block, argp, sizeof(int));
2314 if (ret)
2315 return ret;
2316
2317 ret = mdp3_histogram_stop(mdp3_session, block);
2318 break;
2319
2320 case MSMFB_HISTOGRAM:
2321 ret = copy_from_user(&hist, argp, sizeof(hist));
2322 if (ret)
2323 return ret;
2324
2325 ret = mdp3_histogram_collect(mdp3_session, &hist);
2326 if (!ret)
2327 ret = copy_to_user(argp, &hist, sizeof(hist));
2328 break;
2329 default:
2330 break;
2331 }
2332 return ret;
2333}
2334
2335static int mdp3_validate_lut_data(struct fb_cmap *cmap)
2336{
2337 u32 i = 0;
2338
2339 if (!cmap || !cmap->red || !cmap->green || !cmap->blue) {
2340 pr_err("Invalid arguments!\n");
2341 return -EINVAL;
2342 }
2343
2344 for (i = 0; i < MDP_LUT_SIZE; i++) {
2345 if (cmap->red[i] > 0xFF || cmap->green[i] > 0xFF ||
2346 cmap->blue[i] > 0xFF) {
2347 pr_err("LUT value over 255 (limit) at %d index\n", i);
2348 return -EINVAL;
2349 }
2350 }
2351
2352 return 0;
2353}
2354
2355static inline int mdp3_copy_lut_buffer(struct fb_cmap *dst, struct fb_cmap *src)
2356{
2357 if (!dst || !src || !dst->red || !dst->blue || !dst->green ||
2358 !src->red || !src->green || !src->blue) {
2359 pr_err("Invalid params\n");
2360 return -EINVAL;
2361 }
2362
2363 dst->start = src->start;
2364 dst->len = src->len;
2365
2366 memcpy(dst->red, src->red, MDP_LUT_SIZE * sizeof(u16));
2367 memcpy(dst->green, src->green, MDP_LUT_SIZE * sizeof(u16));
2368 memcpy(dst->blue, src->blue, MDP_LUT_SIZE * sizeof(u16));
2369 return 0;
2370}
2371
2372static int mdp3_alloc_lut_buffer(struct platform_device *pdev, void **cmap)
2373{
2374 struct fb_cmap *map;
2375
2376 map = devm_kzalloc(&pdev->dev, sizeof(struct fb_cmap), GFP_KERNEL);
2377 if (map == NULL)
2378 return -ENOMEM;
2379
2380 memset(map, 0, sizeof(struct fb_cmap));
2381
2382 map->red = devm_kzalloc(&pdev->dev, MDP_LUT_SIZE * sizeof(u16),
2383 GFP_KERNEL);
2384 if (map->red == NULL)
2385 goto exit_red;
2386
2387 memset(map->red, 0, sizeof(u16) * MDP_LUT_SIZE);
2388
2389 map->green = devm_kzalloc(&pdev->dev, MDP_LUT_SIZE * sizeof(u16),
2390 GFP_KERNEL);
2391 if (map->green == NULL)
2392 goto exit_green;
2393
2394 memset(map->green, 0, sizeof(u16) * MDP_LUT_SIZE);
2395
2396 map->blue = devm_kzalloc(&pdev->dev, MDP_LUT_SIZE * sizeof(u16),
2397 GFP_KERNEL);
2398 if (map->blue == NULL)
2399 goto exit_blue;
2400
2401 memset(map->blue, 0, sizeof(u16) * MDP_LUT_SIZE);
2402
2403 *cmap = map;
2404 return 0;
2405exit_blue:
2406 devm_kfree(&pdev->dev, map->green);
2407exit_green:
2408 devm_kfree(&pdev->dev, map->red);
2409exit_red:
2410 devm_kfree(&pdev->dev, map);
2411 return -ENOMEM;
2412}
2413
2414static void mdp3_free_lut_buffer(struct platform_device *pdev, void **cmap)
2415{
2416 struct fb_cmap *map = (struct fb_cmap *)(*cmap);
2417
2418 if (map == NULL)
2419 return;
2420
2421 devm_kfree(&pdev->dev, map->blue);
2422 map->blue = NULL;
2423 devm_kfree(&pdev->dev, map->green);
2424 map->green = NULL;
2425 devm_kfree(&pdev->dev, map->red);
2426 map->red = NULL;
2427 devm_kfree(&pdev->dev, map);
2428 map = NULL;
2429}
2430
2431static int mdp3_lut_combine_gain(struct fb_cmap *cmap, struct mdp3_dma *dma)
2432{
2433 int i = 0;
2434 u32 r = 0, g = 0, b = 0;
2435
2436 if (!cmap || !dma || !dma->gc_cmap || !dma->hist_cmap ||
2437 !dma->gc_cmap->red || !dma->gc_cmap->green ||
2438 !dma->gc_cmap->blue || !dma->hist_cmap->red ||
2439 !dma->hist_cmap->green || !dma->hist_cmap->blue) {
2440 pr_err("Invalid params\n");
2441 return -EINVAL;
2442 }
2443
2444 for (i = 1; i < MDP_LUT_SIZE; i++) {
2445 r = MIN(dma->gc_cmap->red[i] * dma->hist_cmap->red[i] *
2446 mdp_lut_inverse16[i], 0xFF0000);
2447 g = MIN(dma->gc_cmap->green[i] * dma->hist_cmap->green[i] *
2448 mdp_lut_inverse16[i], 0xFF0000);
2449 b = MIN(dma->gc_cmap->blue[i] * dma->hist_cmap->blue[i] *
2450 mdp_lut_inverse16[i], 0xFF0000);
2451
2452 cmap->red[i] = (r >> 16) & 0xFF;
2453 cmap->green[i] = (g >> 16) & 0xFF;
2454 cmap->blue[i] = (b >> 16) & 0xFF;
2455 }
2456 return 0;
2457}
2458
2459/* Called from within pp_lock and session lock locked context */
2460static int mdp3_ctrl_lut_update(struct msm_fb_data_type *mfd,
2461 struct fb_cmap *cmap)
2462{
2463 int rc = 0;
2464 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
2465 struct mdp3_dma *dma;
2466 struct mdp3_dma_lut_config lut_config;
2467
2468 dma = mdp3_session->dma;
2469
2470 if (!dma->config_lut) {
2471 pr_err("Config LUT not defined!\n");
2472 return -EINVAL;
2473 }
2474
2475 lut_config.lut_enable = 7;
2476 lut_config.lut_sel = mdp3_session->lut_sel;
2477 lut_config.lut_position = 1;
2478 lut_config.lut_dirty = true;
2479
2480 if (!mdp3_session->status) {
2481 pr_err("display off!\n");
2482 return -EPERM;
2483 }
2484
2485 mdp3_clk_enable(1, 0);
2486 rc = dma->config_lut(dma, &lut_config, cmap);
2487 mdp3_clk_enable(0, 0);
2488 if (rc)
2489 pr_err("mdp3_ctrl_lut_update failed\n");
2490
2491 mdp3_session->lut_sel = (mdp3_session->lut_sel + 1) % 2;
2492 return rc;
2493}
2494
2495static int mdp3_ctrl_lut_config(struct msm_fb_data_type *mfd,
2496 struct mdp_rgb_lut_data *cfg)
2497{
2498 int rc = 0;
2499 bool data_validated = false;
2500 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
2501 struct mdp3_dma *dma;
2502 struct fb_cmap *cmap;
2503
2504 dma = mdp3_session->dma;
2505
2506 if ((cfg->cmap.start > MDP_LUT_SIZE) ||
2507 (cfg->cmap.len > MDP_LUT_SIZE) ||
2508 (cfg->cmap.start + cfg->cmap.len > MDP_LUT_SIZE)) {
2509 pr_err("Invalid arguments.\n");
2510 return -EINVAL;
2511 }
2512
2513 rc = mdp3_alloc_lut_buffer(mfd->pdev, (void **) &cmap);
2514 if (rc) {
2515 pr_err("No memory\n");
2516 return -ENOMEM;
2517 }
2518
2519 mutex_lock(&mdp3_session->lock);
2520 mutex_lock(&dma->pp_lock);
2521 rc = copy_from_user(cmap->red + cfg->cmap.start,
2522 cfg->cmap.red, sizeof(u16) * cfg->cmap.len);
2523 rc |= copy_from_user(cmap->green + cfg->cmap.start,
2524 cfg->cmap.green, sizeof(u16) * cfg->cmap.len);
2525 rc |= copy_from_user(cmap->blue + cfg->cmap.start,
2526 cfg->cmap.blue, sizeof(u16) * cfg->cmap.len);
2527 if (rc) {
2528 pr_err("Copying user data failed!\n");
2529 goto exit_err;
2530 }
2531
2532 switch (cfg->lut_type) {
2533 case mdp_rgb_lut_gc:
2534 if (cfg->flags & MDP_PP_OPS_DISABLE) {
2535 if (dma->lut_sts & MDP3_LUT_GC_EN)
2536 /* Free GC cmap cache since disabled */
2537 mdp3_free_lut_buffer(mfd->pdev,
2538 (void **)&dma->gc_cmap);
2539 dma->lut_sts &= ~MDP3_LUT_GC_EN;
2540 } else if (!(dma->lut_sts & MDP3_LUT_GC_EN)) {
2541 /* Check if values sent are valid */
2542 rc = mdp3_validate_lut_data(cmap);
2543 if (rc) {
2544 pr_err("Invalid GC LUT data\n");
2545 goto exit_err;
2546 }
2547 data_validated = true;
2548
2549 /* Allocate GC cmap cache to store values */
2550 rc = mdp3_alloc_lut_buffer(mfd->pdev,
2551 (void **)&dma->gc_cmap);
2552 if (rc) {
2553 pr_err("GC LUT config failed\n");
2554 goto exit_err;
2555 }
2556 dma->lut_sts |= MDP3_LUT_GC_EN;
2557 }
2558 /*
2559 * Copy the GC values from userspace to maintain the
2560 * correct values user intended to program in cache.
2561 * The values programmed in HW might factor in presence
2562 * of other LUT modifying features hence can be
2563 * different from these user given values.
2564 */
2565 if (dma->lut_sts & MDP3_LUT_GC_EN) {
2566 /* Validate LUT data if not yet validated */
2567 if (!data_validated) {
2568 rc = mdp3_validate_lut_data(cmap);
2569 if (rc) {
2570 pr_err("Invalid GC LUT data\n");
2571 goto exit_err;
2572 }
2573 }
2574 rc = mdp3_copy_lut_buffer(dma->gc_cmap, cmap);
2575 if (rc) {
2576 pr_err("Could not store GC to cache\n");
2577 goto exit_err;
2578 }
2579 }
2580 break;
2581 case mdp_rgb_lut_hist:
2582 if (cfg->flags & MDP_PP_OPS_DISABLE) {
2583 if (dma->lut_sts & MDP3_LUT_HIST_EN)
2584 /* Free HIST cmap cache since disabled */
2585 mdp3_free_lut_buffer(mfd->pdev,
2586 (void **)&dma->hist_cmap);
2587 dma->lut_sts &= ~MDP3_LUT_HIST_EN;
2588 } else if (!(dma->lut_sts & MDP3_LUT_HIST_EN)) {
2589 /* Check if values sent are valid */
2590 rc = mdp3_validate_lut_data(cmap);
2591 if (rc) {
2592 pr_err("Invalid HIST LUT data\n");
2593 goto exit_err;
2594 }
2595 data_validated = true;
2596
2597 /* Allocate HIST cmap cache to store values */
2598 rc = mdp3_alloc_lut_buffer(mfd->pdev,
2599 (void **)&dma->hist_cmap);
2600 if (rc) {
2601 pr_err("HIST LUT config failed\n");
2602 goto exit_err;
2603 }
2604 dma->lut_sts |= MDP3_LUT_HIST_EN;
2605 }
2606 /*
2607 * Copy the HIST LUT values from userspace to maintain
2608 * correct values user intended to program in cache.
2609 * The values programmed in HW might factor in presence
2610 * of other LUT modifying features hence can be
2611 * different from these user given values.
2612 */
2613 if (dma->lut_sts & MDP3_LUT_HIST_EN) {
2614 /* Validate LUT data if not yet validated */
2615 if (!data_validated) {
2616 rc = mdp3_validate_lut_data(cmap);
2617 if (rc) {
2618 pr_err("Invalid H LUT data\n");
2619 goto exit_err;
2620 }
2621 }
2622 rc = mdp3_copy_lut_buffer(dma->hist_cmap, cmap);
2623 if (rc) {
2624 pr_err("Could not cache Hist LUT\n");
2625 goto exit_err;
2626 }
2627 }
2628 break;
2629 default:
2630 pr_err("Invalid lut type: %u\n", cfg->lut_type);
2631 rc = -EINVAL;
2632 goto exit_err;
2633 }
2634
2635 /*
2636 * In case both GC LUT and HIST LUT need to be programmed the gains
2637 * of each the individual LUTs need to be applied onto a single LUT
2638 * and applied in HW
2639 */
2640 if ((dma->lut_sts & MDP3_LUT_HIST_EN) &&
2641 (dma->lut_sts & MDP3_LUT_GC_EN)) {
2642 rc = mdp3_lut_combine_gain(cmap, dma);
2643 if (rc) {
2644 pr_err("Combining gains failed rc = %d\n", rc);
2645 goto exit_err;
2646 }
2647 }
2648
2649 rc = mdp3_ctrl_lut_update(mfd, cmap);
2650 if (rc)
2651 pr_err("Updating LUT failed! rc = %d\n", rc);
2652exit_err:
2653 mutex_unlock(&dma->pp_lock);
2654 mutex_unlock(&mdp3_session->lock);
2655 mdp3_free_lut_buffer(mfd->pdev, (void **) &cmap);
2656 return rc;
2657}
2658
2659static int mdp3_ctrl_lut_read(struct msm_fb_data_type *mfd,
2660 struct mdp_rgb_lut_data *cfg)
2661{
2662 int rc = 0;
2663 struct fb_cmap *cmap;
2664 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
2665 struct mdp3_dma *dma = mdp3_session->dma;
2666
2667 switch (cfg->lut_type) {
2668 case mdp_rgb_lut_gc:
2669 if (!dma->gc_cmap) {
2670 pr_err("GC not programmed\n");
2671 return -EPERM;
2672 }
2673 cmap = dma->gc_cmap;
2674 break;
2675 case mdp_rgb_lut_hist:
2676 if (!dma->hist_cmap) {
2677 pr_err("Hist LUT not programmed\n");
2678 return -EPERM;
2679 }
2680 cmap = dma->hist_cmap;
2681 break;
2682 default:
2683 pr_err("Invalid lut type %u\n", cfg->lut_type);
2684 return -EINVAL;
2685 }
2686
2687 cfg->cmap.start = cmap->start;
2688 cfg->cmap.len = cmap->len;
2689
2690 mutex_lock(&dma->pp_lock);
2691 rc = copy_to_user(cfg->cmap.red, cmap->red, sizeof(u16) *
2692 MDP_LUT_SIZE);
2693 rc |= copy_to_user(cfg->cmap.green, cmap->green, sizeof(u16) *
2694 MDP_LUT_SIZE);
2695 rc |= copy_to_user(cfg->cmap.blue, cmap->blue, sizeof(u16) *
2696 MDP_LUT_SIZE);
2697 mutex_unlock(&dma->pp_lock);
2698 return rc;
2699}
2700
2701/* Invoked from ctrl_on with session lock locked context */
2702static void mdp3_ctrl_pp_resume(struct msm_fb_data_type *mfd)
2703{
2704 struct mdp3_session_data *mdp3_session;
2705 struct mdp3_dma *dma;
2706 struct fb_cmap *cmap;
2707 int rc = 0;
2708
2709 mdp3_session = mfd->mdp.private1;
2710 dma = mdp3_session->dma;
2711
2712 mutex_lock(&dma->pp_lock);
2713 /*
2714 * if dma->ccs_config.ccs_enable is set then DMA PP block was enabled
2715 * via user space IOCTL.
2716 * Then set dma->ccs_config.ccs_dirty flag
2717 * Then PP block will be reconfigured when next kickoff comes.
2718 */
2719 if (dma->ccs_config.ccs_enable)
2720 dma->ccs_config.ccs_dirty = true;
2721
2722 /*
2723 * If gamma correction was enabled then we program the LUT registers
2724 * with the last configuration data before suspend. If gamma correction
2725 * is not enabled then we do not program anything. The LUT from
2726 * histogram processing algorithms will program hardware based on new
2727 * frame data if they are enabled.
2728 */
2729 if (dma->lut_sts & MDP3_LUT_GC_EN) {
2730
2731 rc = mdp3_alloc_lut_buffer(mfd->pdev, (void **)&cmap);
2732 if (rc) {
2733 pr_err("No memory for GC LUT, rc = %d\n", rc);
2734 goto exit_err;
2735 }
2736
2737 if (dma->lut_sts & MDP3_LUT_HIST_EN) {
2738 rc = mdp3_lut_combine_gain(cmap, dma);
2739 if (rc) {
2740 pr_err("Combining the gain failed rc=%d\n", rc);
2741 goto exit_err;
2742 }
2743 } else {
2744 rc = mdp3_copy_lut_buffer(cmap, dma->gc_cmap);
2745 if (rc) {
2746 pr_err("Updating GC failed rc = %d\n", rc);
2747 goto exit_err;
2748 }
2749 }
2750
2751 rc = mdp3_ctrl_lut_update(mfd, cmap);
2752 if (rc)
2753 pr_err("GC Lut update failed rc=%d\n", rc);
2754exit_err:
2755 mdp3_free_lut_buffer(mfd->pdev, (void **)&cmap);
2756 }
2757
2758 mutex_unlock(&dma->pp_lock);
2759}
2760
2761static int mdp3_overlay_prepare(struct msm_fb_data_type *mfd,
2762 struct mdp_overlay_list __user *user_ovlist)
2763{
2764 struct mdp_overlay_list ovlist;
2765 struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
2766 struct mdp_overlay *req_list;
2767 struct mdp_overlay *req;
2768 int rc;
2769
2770 if (!mdp3_session)
2771 return -ENODEV;
2772
2773 req = &mdp3_session->req_overlay;
2774
2775 if (copy_from_user(&ovlist, user_ovlist, sizeof(ovlist)))
2776 return -EFAULT;
2777
2778 if (ovlist.num_overlays != 1) {
2779 pr_err("OV_PREPARE failed: only 1 overlay allowed\n");
2780 return -EINVAL;
2781 }
2782
2783 if (copy_from_user(&req_list, ovlist.overlay_list,
2784 sizeof(struct mdp_overlay *)))
2785 return -EFAULT;
2786
2787 if (copy_from_user(req, req_list, sizeof(*req)))
2788 return -EFAULT;
2789
2790 rc = mdp3_overlay_set(mfd, req);
2791 if (!IS_ERR_VALUE(rc)) {
2792 if (copy_to_user(req_list, req, sizeof(*req)))
2793 return -EFAULT;
2794 }
2795
2796 if (put_user(IS_ERR_VALUE(rc) ? 0 : 1,
2797 &user_ovlist->processed_overlays))
2798 return -EFAULT;
2799
2800 return rc;
2801}
2802
2803static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd,
2804 u32 cmd, void __user *argp)
2805{
2806 int rc = -EINVAL;
2807 struct mdp3_session_data *mdp3_session;
2808 struct msmfb_metadata metadata;
2809 struct mdp_overlay *req = NULL;
2810 struct msmfb_overlay_data ov_data;
2811 int val;
2812
2813 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
2814 if (!mdp3_session)
2815 return -ENODEV;
2816
2817 req = &mdp3_session->req_overlay;
2818
2819 if (!mdp3_session->status && cmd != MSMFB_METADATA_GET &&
2820 cmd != MSMFB_HISTOGRAM_STOP && cmd != MSMFB_HISTOGRAM) {
2821 pr_err("mdp3_ctrl_ioctl_handler, display off!\n");
2822 return -EPERM;
2823 }
2824
2825 switch (cmd) {
2826 case MSMFB_MDP_PP:
2827 rc = mdp3_pp_ioctl(mfd, argp);
2828 break;
2829 case MSMFB_HISTOGRAM_START:
2830 case MSMFB_HISTOGRAM_STOP:
2831 case MSMFB_HISTOGRAM:
2832 rc = mdp3_histo_ioctl(mfd, cmd, argp);
2833 break;
2834
2835 case MSMFB_VSYNC_CTRL:
2836 case MSMFB_OVERLAY_VSYNC_CTRL:
2837 if (!copy_from_user(&val, argp, sizeof(val))) {
2838 mutex_lock(&mdp3_session->lock);
2839 mdp3_session->vsync_enabled = val;
2840 rc = mdp3_ctrl_vsync_enable(mfd, val);
2841 mutex_unlock(&mdp3_session->lock);
2842 } else {
2843 pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n");
2844 rc = -EFAULT;
2845 }
2846 break;
2847 case MSMFB_ASYNC_BLIT:
2848 mutex_lock(&mdp3_res->fs_idle_pc_lock);
2849 if (mdp3_session->in_splash_screen || mdp3_res->idle_pc) {
2850 pr_debug("%s: reset- in_splash = %d, idle_pc = %d",
2851 __func__, mdp3_session->in_splash_screen,
2852 mdp3_res->idle_pc);
2853 mdp3_ctrl_reset(mfd);
2854 }
2855 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
2856 rc = mdp3_ctrl_async_blit_req(mfd, argp);
Arun kumar04d4a922018-05-23 16:22:45 +05302857 if (!rc)
2858 cancel_work_sync(&mdp3_session->clk_off_work);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302859 break;
2860 case MSMFB_BLIT:
2861 mutex_lock(&mdp3_res->fs_idle_pc_lock);
2862 if (mdp3_session->in_splash_screen)
2863 mdp3_ctrl_reset(mfd);
2864 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
2865 rc = mdp3_ctrl_blit_req(mfd, argp);
Arun kumar04d4a922018-05-23 16:22:45 +05302866 if (!rc)
2867 cancel_work_sync(&mdp3_session->clk_off_work);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302868 break;
2869 case MSMFB_METADATA_GET:
2870 rc = copy_from_user(&metadata, argp, sizeof(metadata));
2871 if (!rc)
2872 rc = mdp3_get_metadata(mfd, &metadata);
2873 if (!rc)
2874 rc = copy_to_user(argp, &metadata, sizeof(metadata));
2875 if (rc)
2876 pr_err("mdp3_get_metadata failed (%d)\n", rc);
2877 break;
2878 case MSMFB_METADATA_SET:
2879 rc = copy_from_user(&metadata, argp, sizeof(metadata));
2880 if (!rc)
2881 rc = mdp3_set_metadata(mfd, &metadata);
2882 if (rc)
2883 pr_err("mdp3_set_metadata failed (%d)\n", rc);
2884 break;
2885 case MSMFB_OVERLAY_GET:
2886 rc = copy_from_user(req, argp, sizeof(*req));
2887 if (!rc) {
2888 rc = mdp3_overlay_get(mfd, req);
2889
2890 if (!IS_ERR_VALUE(rc))
2891 rc = copy_to_user(argp, req, sizeof(*req));
2892 }
2893 if (rc)
2894 pr_err("OVERLAY_GET failed (%d)\n", rc);
2895 break;
2896 case MSMFB_OVERLAY_SET:
2897 rc = copy_from_user(req, argp, sizeof(*req));
2898 if (!rc) {
2899 rc = mdp3_overlay_set(mfd, req);
2900
2901 if (!IS_ERR_VALUE(rc))
2902 rc = copy_to_user(argp, req, sizeof(*req));
2903 }
2904 if (rc)
2905 pr_err("OVERLAY_SET failed (%d)\n", rc);
2906 break;
2907 case MSMFB_OVERLAY_UNSET:
2908 if (!IS_ERR_VALUE(copy_from_user(&val, argp, sizeof(val))))
2909 rc = mdp3_overlay_unset(mfd, val);
2910 break;
2911 case MSMFB_OVERLAY_PLAY:
2912 rc = copy_from_user(&ov_data, argp, sizeof(ov_data));
2913 mutex_lock(&mdp3_res->fs_idle_pc_lock);
2914 if (mdp3_session->in_splash_screen)
2915 mdp3_ctrl_reset(mfd);
2916 mutex_unlock(&mdp3_res->fs_idle_pc_lock);
2917 if (!rc)
2918 rc = mdp3_overlay_play(mfd, &ov_data);
2919 if (rc)
2920 pr_err("OVERLAY_PLAY failed (%d)\n", rc);
2921 break;
2922 case MSMFB_OVERLAY_PREPARE:
2923 rc = mdp3_overlay_prepare(mfd, argp);
2924 break;
2925 default:
2926 break;
2927 }
2928 return rc;
2929}
2930
2931int mdp3_wait_for_dma_done(struct mdp3_session_data *session)
2932{
2933 int rc = 0;
2934
2935 if (session->dma_active) {
2936 rc = wait_for_completion_timeout(&session->dma_completion,
Abhijith Desaib502b282018-09-12 14:48:22 +05302937 dma_timeout_value(session->dma));
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302938 if (rc > 0) {
2939 session->dma_active = 0;
2940 rc = 0;
2941 } else if (rc == 0) {
2942 rc = -ETIME;
2943 }
2944 }
2945 return rc;
2946}
2947
2948static int mdp3_update_panel_info(struct msm_fb_data_type *mfd, int mode,
2949 int dest_ctrl)
2950{
2951 int ret = 0;
2952 struct mdp3_session_data *mdp3_session;
2953 struct mdss_panel_data *panel;
2954 u32 intf_type = 0;
2955
2956 if (!mfd || !mfd->mdp.private1)
2957 return -EINVAL;
2958
2959 mdp3_session = mfd->mdp.private1;
2960 panel = mdp3_session->panel;
2961
2962 if (!panel->event_handler)
2963 return 0;
2964 ret = panel->event_handler(panel, MDSS_EVENT_DSI_UPDATE_PANEL_DATA,
2965 (void *)(unsigned long)mode);
2966 if (ret)
2967 pr_err("Dynamic switch to %s mode failed!\n",
2968 mode ? "command" : "video");
2969 if (mode == 1)
2970 mfd->panel.type = MIPI_CMD_PANEL;
2971 else
2972 mfd->panel.type = MIPI_VIDEO_PANEL;
2973
2974 if (mfd->panel.type != MIPI_VIDEO_PANEL)
2975 mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
2976
2977 intf_type = mdp3_ctrl_get_intf_type(mfd);
2978 mdp3_session->intf->cfg.type = intf_type;
2979 mdp3_session->intf->available = 1;
2980 mdp3_session->intf->in_use = 1;
2981 mdp3_res->intf[intf_type].in_use = 1;
2982
2983 mdp3_intf_init(mdp3_session->intf);
2984
2985 mdp3_session->dma->output_config.out_sel = intf_type;
2986 mdp3_session->status = mdp3_session->intf->active;
2987
2988 return 0;
2989}
2990
2991static int mdp3_vsync_retire_setup(struct msm_fb_data_type *mfd)
2992{
2993 struct mdp3_session_data *mdp3_session;
2994 struct mdp3_notification retire_client;
2995 char name[24];
2996
2997 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
2998
2999 snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index);
Arun kumar47145e02018-03-23 22:07:51 +05303000 mfd->mdp_sync_pt_data.timeline_retire = mdss_create_timeline(name);
3001 if (mfd->mdp_sync_pt_data.timeline_retire == NULL) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303002 pr_err("cannot vsync create time line");
3003 return -ENOMEM;
3004 }
3005
Vijay Navnath Kamble7f082222018-09-10 12:40:01 +05303006 if (mfd->panel_info->type == MIPI_CMD_PANEL) {
3007 /* Add retire vsync handler */
3008 retire_client.handler = mdp3_vsync_retire_handle_vsync;
3009 retire_client.arg = mdp3_session;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303010
Vijay Navnath Kamble7f082222018-09-10 12:40:01 +05303011 if (mdp3_session->dma)
3012 mdp3_session->dma->retire_client = retire_client;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303013
Vijay Navnath Kamble7f082222018-09-10 12:40:01 +05303014 INIT_WORK(&mdp3_session->retire_work,
3015 mdp3_vsync_retire_work_handler);
3016 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303017
3018 return 0;
3019}
3020
3021int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
3022{
3023 struct device *dev = mfd->fbi->dev;
3024 struct msm_mdp_interface *mdp3_interface = &mfd->mdp;
3025 struct mdp3_session_data *mdp3_session = NULL;
3026 u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
Arun kumardb962812018-05-30 16:31:52 +05303027 int frame_rate = DEFAULT_FRAME_RATE;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303028 int rc;
3029 int splash_mismatch = 0;
3030 struct sched_param sched = { .sched_priority = 16 };
3031
3032 pr_info("mdp3_ctrl_init\n");
3033 rc = mdp3_parse_dt_splash(mfd);
3034 if (rc)
3035 splash_mismatch = 1;
3036
Arun kumardb962812018-05-30 16:31:52 +05303037 frame_rate = mdss_panel_get_framerate(mfd->panel_info,
3038 FPS_RESOLUTION_HZ);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303039 mdp3_interface->on_fnc = mdp3_ctrl_on;
3040 mdp3_interface->off_fnc = mdp3_ctrl_off;
3041 mdp3_interface->do_histogram = NULL;
3042 mdp3_interface->cursor_update = NULL;
3043 mdp3_interface->dma_fnc = mdp3_ctrl_pan_display;
3044 mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
3045 mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
3046 mdp3_interface->pre_commit = mdp3_layer_pre_commit;
3047 mdp3_interface->atomic_validate = mdp3_layer_atomic_validate;
3048 mdp3_interface->lut_update = NULL;
3049 mdp3_interface->configure_panel = mdp3_update_panel_info;
3050 mdp3_interface->input_event_handler = NULL;
Animesh Kishore8b42bd92018-12-04 18:57:13 +05303051 mdp3_interface->signal_retire_fence = mdp3_vsync_retire_signal;
Arun kumar162db222018-05-09 17:28:40 +05303052 mdp3_interface->is_twm_en = mdp3_is_twm_en;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303053
3054 mdp3_session = kzalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
3055 if (!mdp3_session)
3056 return -ENOMEM;
3057
3058 mutex_init(&mdp3_session->lock);
3059 INIT_WORK(&mdp3_session->clk_off_work, mdp3_dispatch_clk_off);
3060
Arun kumar47145e02018-03-23 22:07:51 +05303061 kthread_init_worker(&mdp3_session->worker);
3062 kthread_init_work(&mdp3_session->dma_done_work, mdp3_dispatch_dma_done);
3063
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303064
3065 mdp3_session->thread = kthread_run(kthread_worker_fn,
3066 &mdp3_session->worker,
3067 "mdp3_dispatch_dma_done");
3068
3069 if (IS_ERR(mdp3_session->thread)) {
3070 pr_err("Can't initialize mdp3_dispatch_dma_done thread\n");
3071 rc = -ENODEV;
3072 goto init_done;
3073 }
3074
3075 sched_setscheduler(mdp3_session->thread, SCHED_FIFO, &sched);
3076
3077 atomic_set(&mdp3_session->vsync_countdown, 0);
3078 mutex_init(&mdp3_session->histo_lock);
3079 mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
3080 if (!mdp3_session->dma) {
3081 rc = -ENODEV;
3082 goto init_done;
3083 }
3084
3085 rc = mdp3_dma_init(mdp3_session->dma);
3086 if (rc) {
3087 pr_err("fail to init dma\n");
3088 goto init_done;
3089 }
Animesh Kishore3650a562018-11-16 00:26:26 +05303090 mdp3_session->dma->session = mdp3_session;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303091
3092 intf_type = mdp3_ctrl_get_intf_type(mfd);
3093 mdp3_session->intf = mdp3_get_display_intf(intf_type);
3094 if (!mdp3_session->intf) {
3095 rc = -ENODEV;
3096 goto init_done;
3097 }
3098 rc = mdp3_intf_init(mdp3_session->intf);
3099 if (rc) {
3100 pr_err("fail to init interface\n");
3101 goto init_done;
3102 }
3103
3104 mdp3_session->dma->output_config.out_sel = intf_type;
3105 mdp3_session->mfd = mfd;
3106 mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
3107 mdp3_session->status = mdp3_session->intf->active;
3108 mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
3109 mdp3_bufq_init(&mdp3_session->bufq_in);
3110 mdp3_bufq_init(&mdp3_session->bufq_out);
3111 mdp3_session->histo_status = 0;
3112 mdp3_session->lut_sel = 0;
3113 BLOCKING_INIT_NOTIFIER_HEAD(&mdp3_session->notifier_head);
3114
3115 init_timer(&mdp3_session->vsync_timer);
3116 mdp3_session->vsync_timer.function = mdp3_vsync_timer_func;
3117 mdp3_session->vsync_timer.data = (u32)mdp3_session;
Abhijith Desaib502b282018-09-12 14:48:22 +05303118
3119 if (frame_rate != 0)
3120 mdp3_session->dma->vsync_period =
3121 DIV_ROUND_UP(1000, frame_rate);
3122
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303123 mfd->mdp.private1 = mdp3_session;
3124 init_completion(&mdp3_session->dma_completion);
Arun kumardb962812018-05-30 16:31:52 +05303125 if (intf_type != MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
3126 intf_type != MDP3_DMA_OUTPUT_SEL_SPI_CMD)
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303127 mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
3128
3129 rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
3130 if (rc) {
3131 pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
3132 goto init_done;
3133 }
3134 rc = sysfs_create_group(&dev->kobj, &generic_attr_group);
3135 if (rc) {
3136 pr_err("generic sysfs group creation failed, ret=%d\n", rc);
3137 goto init_done;
3138 }
3139
3140 mdp3_session->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd,
3141 "vsync_event");
3142 if (!mdp3_session->vsync_event_sd) {
3143 pr_err("vsync_event sysfs lookup failed\n");
3144 rc = -ENODEV;
3145 goto init_done;
3146 }
3147
3148 mdp3_session->dma->hist_event_sd = sysfs_get_dirent(dev->kobj.sd,
3149 "hist_event");
3150 if (!mdp3_session->dma->hist_event_sd) {
3151 pr_err("hist_event sysfs lookup failed\n");
3152 rc = -ENODEV;
3153 goto init_done;
3154 }
3155
3156 mdp3_session->bl_event_sd = sysfs_get_dirent(dev->kobj.sd,
3157 "bl_event");
3158 if (!mdp3_session->bl_event_sd) {
3159 pr_err("bl_event sysfs lookup failed\n");
3160 rc = -ENODEV;
3161 goto init_done;
3162 }
3163
3164 rc = mdp3_create_sysfs_link(dev);
3165 if (rc)
3166 pr_warn("problem creating link to mdp sysfs\n");
3167
3168 /* Enable PM runtime */
3169 pm_runtime_set_suspended(&mdp3_res->pdev->dev);
3170 pm_runtime_enable(&mdp3_res->pdev->dev);
3171
3172 kobject_uevent(&dev->kobj, KOBJ_ADD);
3173 pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
3174
3175 if (mdp3_get_cont_spash_en()) {
3176 mdp3_session->clk_on = 1;
3177 mdp3_session->in_splash_screen = 1;
3178 mdp3_ctrl_notifier_register(mdp3_session,
3179 &mdp3_session->mfd->mdp_sync_pt_data.notifier);
3180 }
3181
3182 /*
3183 * Increment the overlay active count.
3184 * This is needed to ensure that if idle power collapse kicks in
3185 * right away, it would be handled correctly.
3186 */
3187 atomic_inc(&mdp3_res->active_intf_cnt);
3188 if (splash_mismatch) {
3189 pr_err("splash memory mismatch, stop splash\n");
3190 mdp3_ctrl_off(mfd);
3191 }
3192
3193 mdp3_session->vsync_before_commit = true;
3194 mdp3_session->dyn_pu_state = mfd->panel_info->partial_update_enabled;
3195
Vijay Navnath Kamble7f082222018-09-10 12:40:01 +05303196 rc = mdp3_vsync_retire_setup(mfd);
3197 if (IS_ERR_VALUE(rc)) {
3198 pr_err("unable to create vsync timeline\n");
3199 goto init_done;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303200 }
3201init_done:
3202 if (IS_ERR_VALUE(rc))
3203 kfree(mdp3_session);
3204
3205 return rc;
3206}