blob: b827eca91f8938e610f0ae0478de1fd8463c7d64 [file] [log] [blame]
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301/*
2 * Core MDSS framebuffer driver.
3 *
4 * Copyright (C) 2007 Google Incorporated
Krishna Manikandan695632e2020-03-04 20:50:28 +05305 * Copyright (c) 2008-2020, The Linux Foundation. All rights reserved.
Sachin Bhayareeeb88892018-01-02 16:36:01 +05306 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#define pr_fmt(fmt) "%s: " fmt, __func__
18
19#include <linux/videodev2.h>
20#include <linux/bootmem.h>
21#include <linux/console.h>
22#include <linux/debugfs.h>
23#include <linux/delay.h>
24#include <linux/device.h>
25#include <linux/dma-mapping.h>
26#include <linux/dma-buf.h>
27#include <linux/fb.h>
28#include <linux/init.h>
29#include <linux/ioport.h>
30#include <linux/kernel.h>
31#include <linux/memory.h>
32#include <linux/mm.h>
33#include <linux/module.h>
34#include <linux/moduleparam.h>
35#include <linux/msm_mdp.h>
36#include <linux/of.h>
37#include <linux/of_address.h>
38#include <linux/of_platform.h>
39#include <linux/proc_fs.h>
40#include <linux/pm_runtime.h>
41#include <linux/slab.h>
42#include <linux/string.h>
43#include <linux/uaccess.h>
44#include <linux/version.h>
45#include <linux/vmalloc.h>
Sachin Bhayareeeb88892018-01-02 16:36:01 +053046#include <linux/file.h>
47#include <linux/kthread.h>
48#include <linux/dma-buf.h>
49#include "mdss_fb.h"
50#include "mdss_mdp_splash_logo.h"
51#define CREATE_TRACE_POINTS
52#include "mdss_debug.h"
53#include "mdss_smmu.h"
54#include "mdss_mdp.h"
55#include "mdp3_ctrl.h"
Sachin Bhayare2b6d0042018-01-13 19:38:21 +053056#include "mdss_sync.h"
Sachin Bhayareeeb88892018-01-02 16:36:01 +053057
58#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
59#define MDSS_FB_NUM 3
60#else
61#define MDSS_FB_NUM 2
62#endif
63
64#ifndef EXPORT_COMPAT
65#define EXPORT_COMPAT(x)
66#endif
67
68#define MAX_FBI_LIST 32
69
70#ifndef TARGET_HW_MDSS_MDP3
71#define BLANK_FLAG_LP FB_BLANK_NORMAL
72#define BLANK_FLAG_ULP FB_BLANK_VSYNC_SUSPEND
73#else
74#define BLANK_FLAG_LP FB_BLANK_VSYNC_SUSPEND
75#define BLANK_FLAG_ULP FB_BLANK_NORMAL
76#endif
77
78/*
79 * Time period for fps calulation in micro seconds.
80 * Default value is set to 1 sec.
81 */
82#define MDP_TIME_PERIOD_CALC_FPS_US 1000000
83
84static struct fb_info *fbi_list[MAX_FBI_LIST];
85static int fbi_list_index;
86
87static u32 mdss_fb_pseudo_palette[16] = {
88 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
89 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
90 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
91 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
92};
93
94static struct msm_mdp_interface *mdp_instance;
95
96static int mdss_fb_register(struct msm_fb_data_type *mfd);
97static int mdss_fb_open(struct fb_info *info, int user);
98static int mdss_fb_release(struct fb_info *info, int user);
99static int mdss_fb_release_all(struct fb_info *info, bool release_all);
100static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
101 struct fb_info *info);
102static int mdss_fb_check_var(struct fb_var_screeninfo *var,
103 struct fb_info *info);
104static int mdss_fb_set_par(struct fb_info *info);
105static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
106 int op_enable);
107static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd);
108static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
109 unsigned long arg, struct file *file);
110static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
111 struct vm_area_struct *vma);
112static int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd,
113 size_t size);
114static void mdss_fb_release_fences(struct msm_fb_data_type *mfd);
115static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
116 unsigned long val, void *data);
117
118static int __mdss_fb_display_thread(void *data);
119static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
120static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
121 int event, void *arg);
122static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd,
123 int type);
124void mdss_fb_no_update_notify_timer_cb(unsigned long data)
125{
126 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
127
128 if (!mfd) {
129 pr_err("%s mfd NULL\n", __func__);
130 return;
131 }
132 mfd->no_update.value = NOTIFY_TYPE_NO_UPDATE;
133 complete(&mfd->no_update.comp);
134}
135
136void mdss_fb_bl_update_notify(struct msm_fb_data_type *mfd,
137 uint32_t notification_type)
138{
139#ifndef TARGET_HW_MDSS_MDP3
140 struct mdss_overlay_private *mdp5_data = NULL;
141#endif
142#ifdef TARGET_HW_MDSS_MDP3
143 struct mdp3_session_data *mdp3_session = NULL;
144#endif
145 if (!mfd) {
146 pr_err("%s mfd NULL\n", __func__);
147 return;
148 }
149 mutex_lock(&mfd->update.lock);
150 if (mfd->update.is_suspend) {
151 mutex_unlock(&mfd->update.lock);
152 return;
153 }
154 if (mfd->update.ref_count > 0) {
155 mutex_unlock(&mfd->update.lock);
156 mfd->update.value = notification_type;
157 complete(&mfd->update.comp);
158 mutex_lock(&mfd->update.lock);
159 }
160 mutex_unlock(&mfd->update.lock);
161
162 mutex_lock(&mfd->no_update.lock);
163 if (mfd->no_update.ref_count > 0) {
164 mutex_unlock(&mfd->no_update.lock);
165 mfd->no_update.value = notification_type;
166 complete(&mfd->no_update.comp);
167 mutex_lock(&mfd->no_update.lock);
168 }
169 mutex_unlock(&mfd->no_update.lock);
170#ifndef TARGET_HW_MDSS_MDP3
171 mdp5_data = mfd_to_mdp5_data(mfd);
172 if (mdp5_data) {
173 if (notification_type == NOTIFY_TYPE_BL_AD_ATTEN_UPDATE) {
174 mdp5_data->ad_bl_events++;
175 sysfs_notify_dirent(mdp5_data->ad_bl_event_sd);
176 } else if (notification_type == NOTIFY_TYPE_BL_UPDATE) {
177 mdp5_data->bl_events++;
178 sysfs_notify_dirent(mdp5_data->bl_event_sd);
179 }
180 }
181#endif
182#ifdef TARGET_HW_MDSS_MDP3
183 mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
184 if (mdp3_session) {
185 mdp3_session->bl_events++;
186 sysfs_notify_dirent(mdp3_session->bl_event_sd);
187 pr_debug("bl_event = %u\n", mdp3_session->bl_events);
188 }
189#endif
190}
191
192static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
193 unsigned long *argp)
194{
195 int ret;
196 unsigned int notify = 0x0, to_user = 0x0;
197
198 ret = copy_from_user(&notify, argp, sizeof(unsigned int));
199 if (ret) {
200 pr_err("%s:ioctl failed\n", __func__);
201 return ret;
202 }
203
204 if (notify > NOTIFY_UPDATE_POWER_OFF)
205 return -EINVAL;
206
207 if (notify == NOTIFY_UPDATE_INIT) {
208 mutex_lock(&mfd->update.lock);
209 mfd->update.init_done = true;
210 mutex_unlock(&mfd->update.lock);
211 ret = 1;
212 } else if (notify == NOTIFY_UPDATE_DEINIT) {
213 mutex_lock(&mfd->update.lock);
214 mfd->update.init_done = false;
215 mutex_unlock(&mfd->update.lock);
216 complete(&mfd->update.comp);
217 complete(&mfd->no_update.comp);
218 ret = 1;
219 } else if (mfd->update.is_suspend) {
220 to_user = NOTIFY_TYPE_SUSPEND;
221 mfd->update.is_suspend = 0;
222 ret = 1;
223 } else if (notify == NOTIFY_UPDATE_START) {
224 mutex_lock(&mfd->update.lock);
225 if (mfd->update.init_done)
226 reinit_completion(&mfd->update.comp);
227 else {
228 mutex_unlock(&mfd->update.lock);
229 pr_err("notify update start called without init\n");
230 return -EINVAL;
231 }
232 mfd->update.ref_count++;
233 mutex_unlock(&mfd->update.lock);
234 ret = wait_for_completion_interruptible_timeout(
235 &mfd->update.comp, 4 * HZ);
236 mutex_lock(&mfd->update.lock);
237 mfd->update.ref_count--;
238 mutex_unlock(&mfd->update.lock);
239 to_user = (unsigned int)mfd->update.value;
240 if (mfd->update.type == NOTIFY_TYPE_SUSPEND) {
241 to_user = (unsigned int)mfd->update.type;
242 ret = 1;
243 }
244 } else if (notify == NOTIFY_UPDATE_STOP) {
245 mutex_lock(&mfd->update.lock);
Naseer Ahmed8f6e4432016-11-09 12:14:31 -0500246 if (mfd->update.init_done) {
247 mutex_unlock(&mfd->update.lock);
248 mutex_lock(&mfd->no_update.lock);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530249 reinit_completion(&mfd->no_update.comp);
Naseer Ahmed8f6e4432016-11-09 12:14:31 -0500250 } else {
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530251 mutex_unlock(&mfd->update.lock);
252 pr_err("notify update stop called without init\n");
253 return -EINVAL;
254 }
255 mfd->no_update.ref_count++;
256 mutex_unlock(&mfd->no_update.lock);
257 ret = wait_for_completion_interruptible_timeout(
258 &mfd->no_update.comp, 4 * HZ);
259 mutex_lock(&mfd->no_update.lock);
260 mfd->no_update.ref_count--;
261 mutex_unlock(&mfd->no_update.lock);
262 to_user = (unsigned int)mfd->no_update.value;
263 } else {
264 if (mdss_fb_is_power_on(mfd)) {
265 reinit_completion(&mfd->power_off_comp);
266 ret = wait_for_completion_interruptible_timeout(
267 &mfd->power_off_comp, 1 * HZ);
268 }
269 }
270
271 if (ret == 0)
272 ret = -ETIMEDOUT;
273 else if (ret > 0)
274 ret = copy_to_user(argp, &to_user, sizeof(unsigned int));
275 return ret;
276}
277
278static int lcd_backlight_registered;
279
280static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev,
281 enum led_brightness value)
282{
283 struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
Sachin Bhayareb6b5a0f2018-03-02 19:50:39 +0530284 u64 bl_lvl;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530285
286 if (mfd->boot_notification_led) {
287 led_trigger_event(mfd->boot_notification_led, 0);
288 mfd->boot_notification_led = NULL;
289 }
290
291 if (value > mfd->panel_info->brightness_max)
292 value = mfd->panel_info->brightness_max;
293
294 /* This maps android backlight level 0 to 255 into
295 * driver backlight level 0 to bl_max with rounding
296 */
297 MDSS_BRIGHT_TO_BL(bl_lvl, value, mfd->panel_info->bl_max,
298 mfd->panel_info->brightness_max);
299
300 if (!bl_lvl && value)
301 bl_lvl = 1;
302
303 if (!IS_CALIB_MODE_BL(mfd) && (!mfd->ext_bl_ctrl || !value ||
304 !mfd->bl_level)) {
305 mutex_lock(&mfd->bl_lock);
306 mdss_fb_set_backlight(mfd, bl_lvl);
307 mutex_unlock(&mfd->bl_lock);
308 }
309}
310
Xu Yang2057d112017-02-15 09:29:27 +0800311static enum led_brightness mdss_fb_get_bl_brightness(
312 struct led_classdev *led_cdev)
313{
314 struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
315 u64 value;
316
317 MDSS_BL_TO_BRIGHT(value, mfd->bl_level, mfd->panel_info->bl_max,
318 mfd->panel_info->brightness_max);
319
320 return value;
321}
322
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530323static struct led_classdev backlight_led = {
324 .name = "lcd-backlight",
325 .brightness = MDSS_MAX_BL_BRIGHTNESS / 2,
326 .brightness_set = mdss_fb_set_bl_brightness,
Xu Yang2057d112017-02-15 09:29:27 +0800327 .brightness_get = mdss_fb_get_bl_brightness,
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530328 .max_brightness = MDSS_MAX_BL_BRIGHTNESS,
329};
330
331static ssize_t mdss_fb_get_type(struct device *dev,
332 struct device_attribute *attr, char *buf)
333{
334 ssize_t ret = 0;
335 struct fb_info *fbi = dev_get_drvdata(dev);
336 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
337
338 switch (mfd->panel.type) {
339 case NO_PANEL:
340 ret = snprintf(buf, PAGE_SIZE, "no panel\n");
341 break;
342 case HDMI_PANEL:
343 ret = snprintf(buf, PAGE_SIZE, "hdmi panel\n");
344 break;
345 case LVDS_PANEL:
346 ret = snprintf(buf, PAGE_SIZE, "lvds panel\n");
347 break;
348 case DTV_PANEL:
349 ret = snprintf(buf, PAGE_SIZE, "dtv panel\n");
350 break;
351 case MIPI_VIDEO_PANEL:
352 ret = snprintf(buf, PAGE_SIZE, "mipi dsi video panel\n");
353 break;
354 case MIPI_CMD_PANEL:
355 ret = snprintf(buf, PAGE_SIZE, "mipi dsi cmd panel\n");
356 break;
357 case WRITEBACK_PANEL:
358 ret = snprintf(buf, PAGE_SIZE, "writeback panel\n");
359 break;
360 case EDP_PANEL:
361 ret = snprintf(buf, PAGE_SIZE, "edp panel\n");
362 break;
Arun kumardb962812018-05-30 16:31:52 +0530363 case SPI_PANEL:
364 ret = snprintf(buf, PAGE_SIZE, "spi panel\n");
365 break;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530366 default:
367 ret = snprintf(buf, PAGE_SIZE, "unknown panel\n");
368 break;
369 }
370
371 return ret;
372}
373
374static int mdss_fb_get_panel_xres(struct mdss_panel_info *pinfo)
375{
376 struct mdss_panel_data *pdata;
377 int xres;
378
379 pdata = container_of(pinfo, struct mdss_panel_data, panel_info);
380
381 xres = pinfo->xres;
382 if (pdata->next && pdata->next->active)
383 xres += mdss_fb_get_panel_xres(&pdata->next->panel_info);
384
385 return xres;
386}
387
388static inline int mdss_fb_validate_split(int left, int right,
389 struct msm_fb_data_type *mfd)
390{
391 int rc = -EINVAL;
392 u32 panel_xres = mdss_fb_get_panel_xres(mfd->panel_info);
393
394 pr_debug("%pS: split_mode = %d left=%d right=%d panel_xres=%d\n",
395 __builtin_return_address(0), mfd->split_mode,
396 left, right, panel_xres);
397
398 /* more validate condition could be added if needed */
399 if (left && right) {
400 if (panel_xres == left + right) {
401 mfd->split_fb_left = left;
402 mfd->split_fb_right = right;
403 rc = 0;
404 }
405 } else {
406 if (mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
407 mfd->split_fb_left = mfd->panel_info->xres;
408 mfd->split_fb_right = panel_xres - mfd->split_fb_left;
409 rc = 0;
410 } else {
411 mfd->split_fb_left = mfd->split_fb_right = 0;
412 }
413 }
414
415 return rc;
416}
417
418static ssize_t mdss_fb_store_split(struct device *dev,
419 struct device_attribute *attr, const char *buf, size_t len)
420{
421 int data[2] = {0};
422 struct fb_info *fbi = dev_get_drvdata(dev);
423 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
424
425 if (sscanf(buf, "%d %d", &data[0], &data[1]) != 2)
426 pr_debug("Not able to read split values\n");
427 else if (!mdss_fb_validate_split(data[0], data[1], mfd))
428 pr_debug("split left=%d right=%d\n", data[0], data[1]);
429
430 return len;
431}
432
433static ssize_t mdss_fb_show_split(struct device *dev,
434 struct device_attribute *attr, char *buf)
435{
436 ssize_t ret = 0;
437 struct fb_info *fbi = dev_get_drvdata(dev);
438 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
439
440 ret = snprintf(buf, PAGE_SIZE, "%d %d\n",
441 mfd->split_fb_left, mfd->split_fb_right);
442 return ret;
443}
444
445static void mdss_fb_get_split(struct msm_fb_data_type *mfd)
446{
447 if ((mfd->split_mode == MDP_SPLIT_MODE_NONE) &&
448 (mfd->split_fb_left && mfd->split_fb_right))
449 mfd->split_mode = MDP_DUAL_LM_SINGLE_DISPLAY;
450
451 pr_debug("split fb%d left=%d right=%d mode=%d\n", mfd->index,
452 mfd->split_fb_left, mfd->split_fb_right, mfd->split_mode);
453}
454
455static ssize_t mdss_fb_get_src_split_info(struct device *dev,
456 struct device_attribute *attr, char *buf)
457{
458 int ret = 0;
459 struct fb_info *fbi = dev_get_drvdata(dev);
460 struct msm_fb_data_type *mfd = fbi->par;
461
462 if (is_split_lm(mfd) && (fbi->var.yres > fbi->var.xres)) {
463 pr_debug("always split mode enabled\n");
464 ret = scnprintf(buf, PAGE_SIZE,
465 "src_split_always\n");
466 }
467
468 return ret;
469}
470
471static ssize_t mdss_fb_get_thermal_level(struct device *dev,
472 struct device_attribute *attr, char *buf)
473{
474 struct fb_info *fbi = dev_get_drvdata(dev);
475 struct msm_fb_data_type *mfd = fbi->par;
476 int ret;
477
478 ret = scnprintf(buf, PAGE_SIZE, "thermal_level=%d\n",
479 mfd->thermal_level);
480
481 return ret;
482}
483
484static ssize_t mdss_fb_set_thermal_level(struct device *dev,
485 struct device_attribute *attr, const char *buf, size_t count)
486{
487 struct fb_info *fbi = dev_get_drvdata(dev);
488 struct msm_fb_data_type *mfd = fbi->par;
489 int rc = 0;
490 int thermal_level = 0;
491
492 rc = kstrtoint(buf, 10, &thermal_level);
493 if (rc) {
494 pr_err("kstrtoint failed. rc=%d\n", rc);
495 return rc;
496 }
497
498 pr_debug("Thermal level set to %d\n", thermal_level);
499 mfd->thermal_level = thermal_level;
500 sysfs_notify(&mfd->fbi->dev->kobj, NULL, "msm_fb_thermal_level");
501
502 return count;
503}
504
505static ssize_t mdss_mdp_show_blank_event(struct device *dev,
506 struct device_attribute *attr, char *buf)
507{
508 struct fb_info *fbi = dev_get_drvdata(dev);
509 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
510 int ret;
511
512 pr_debug("fb%d panel_power_state = %d\n", mfd->index,
513 mfd->panel_power_state);
514 ret = scnprintf(buf, PAGE_SIZE, "panel_power_on = %d\n",
515 mfd->panel_power_state);
516
517 return ret;
518}
519
520static void __mdss_fb_idle_notify_work(struct work_struct *work)
521{
522 struct delayed_work *dw = to_delayed_work(work);
523 struct msm_fb_data_type *mfd = container_of(dw, struct msm_fb_data_type,
524 idle_notify_work);
525
526 /* Notify idle-ness here */
527 pr_debug("Idle timeout %dms expired!\n", mfd->idle_time);
528 if (mfd->idle_time)
529 sysfs_notify(&mfd->fbi->dev->kobj, NULL, "idle_notify");
530 mfd->idle_state = MDSS_FB_IDLE;
531}
532
533
534static ssize_t mdss_fb_get_fps_info(struct device *dev,
535 struct device_attribute *attr, char *buf)
536{
537 struct fb_info *fbi = dev_get_drvdata(dev);
538 struct msm_fb_data_type *mfd = fbi->par;
Sachin Bhayareb6b5a0f2018-03-02 19:50:39 +0530539 u64 fps_int, fps_float;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530540
541 if (mfd->panel_power_state != MDSS_PANEL_POWER_ON)
542 mfd->fps_info.measured_fps = 0;
Sachin Bhayareb6b5a0f2018-03-02 19:50:39 +0530543 fps_int = (u64) mfd->fps_info.measured_fps;
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530544 fps_float = do_div(fps_int, 10);
Sachin Bhayareb6b5a0f2018-03-02 19:50:39 +0530545 return scnprintf(buf, PAGE_SIZE, "%llu.%llu\n", fps_int, fps_float);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530546
547}
548
549static ssize_t mdss_fb_get_idle_time(struct device *dev,
550 struct device_attribute *attr, char *buf)
551{
552 struct fb_info *fbi = dev_get_drvdata(dev);
553 struct msm_fb_data_type *mfd = fbi->par;
554 int ret;
555
556 ret = scnprintf(buf, PAGE_SIZE, "%d", mfd->idle_time);
557
558 return ret;
559}
560
561static ssize_t mdss_fb_set_idle_time(struct device *dev,
562 struct device_attribute *attr, const char *buf, size_t count)
563{
564 struct fb_info *fbi = dev_get_drvdata(dev);
565 struct msm_fb_data_type *mfd = fbi->par;
566 int rc = 0;
567 int idle_time = 0;
568
569 rc = kstrtoint(buf, 10, &idle_time);
570 if (rc) {
571 pr_err("kstrtoint failed. rc=%d\n", rc);
572 return rc;
573 }
574
575 pr_debug("Idle time = %d\n", idle_time);
576 mfd->idle_time = idle_time;
577
578 return count;
579}
580
581static ssize_t mdss_fb_get_idle_notify(struct device *dev,
582 struct device_attribute *attr, char *buf)
583{
584 struct fb_info *fbi = dev_get_drvdata(dev);
585 struct msm_fb_data_type *mfd = fbi->par;
586 int ret;
587
588 ret = scnprintf(buf, PAGE_SIZE, "%s",
589 work_busy(&mfd->idle_notify_work.work) ? "no" : "yes");
590
591 return ret;
592}
593
594static ssize_t mdss_fb_get_panel_info(struct device *dev,
595 struct device_attribute *attr, char *buf)
596{
597 struct fb_info *fbi = dev_get_drvdata(dev);
598 struct msm_fb_data_type *mfd = fbi->par;
599 struct mdss_panel_info *pinfo = mfd->panel_info;
600 int ret;
601
602 ret = scnprintf(buf, PAGE_SIZE,
603 "pu_en=%d\nxstart=%d\nwalign=%d\nystart=%d\nhalign=%d\n"
604 "min_w=%d\nmin_h=%d\nroi_merge=%d\ndyn_fps_en=%d\n"
605 "min_fps=%d\nmax_fps=%d\npanel_name=%s\n"
606 "primary_panel=%d\nis_pluggable=%d\ndisplay_id=%s\n"
607 "is_cec_supported=%d\nis_pingpong_split=%d\n"
608 "is_hdr_enabled=%d\n"
609 "peak_brightness=%d\nblackness_level=%d\n"
610 "white_chromaticity_x=%d\nwhite_chromaticity_y=%d\n"
611 "red_chromaticity_x=%d\nred_chromaticity_y=%d\n"
612 "green_chromaticity_x=%d\ngreen_chromaticity_y=%d\n"
Krishna Chaitanya Devarakonda6f6f50a2016-11-21 21:52:35 +0530613 "blue_chromaticity_x=%d\nblue_chromaticity_y=%d\n"
614 "panel_orientation=%d\n",
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530615 pinfo->partial_update_enabled,
616 pinfo->roi_alignment.xstart_pix_align,
617 pinfo->roi_alignment.width_pix_align,
618 pinfo->roi_alignment.ystart_pix_align,
619 pinfo->roi_alignment.height_pix_align,
620 pinfo->roi_alignment.min_width,
621 pinfo->roi_alignment.min_height,
622 pinfo->partial_update_roi_merge,
623 pinfo->dynamic_fps, pinfo->min_fps, pinfo->max_fps,
624 pinfo->panel_name, pinfo->is_prim_panel,
625 pinfo->is_pluggable, pinfo->display_id,
626 pinfo->is_cec_supported, is_pingpong_split(mfd),
627 pinfo->hdr_properties.hdr_enabled,
628 pinfo->hdr_properties.peak_brightness,
629 pinfo->hdr_properties.blackness_level,
630 pinfo->hdr_properties.display_primaries[0],
631 pinfo->hdr_properties.display_primaries[1],
632 pinfo->hdr_properties.display_primaries[2],
633 pinfo->hdr_properties.display_primaries[3],
634 pinfo->hdr_properties.display_primaries[4],
635 pinfo->hdr_properties.display_primaries[5],
636 pinfo->hdr_properties.display_primaries[6],
Krishna Chaitanya Devarakonda6f6f50a2016-11-21 21:52:35 +0530637 pinfo->hdr_properties.display_primaries[7],
638 pinfo->panel_orientation);
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530639
640 return ret;
641}
642
643static ssize_t mdss_fb_get_panel_status(struct device *dev,
644 struct device_attribute *attr, char *buf)
645{
646 struct fb_info *fbi = dev_get_drvdata(dev);
647 struct msm_fb_data_type *mfd = fbi->par;
648 int ret;
649 int panel_status;
650
651 if (mdss_panel_is_power_off(mfd->panel_power_state)) {
652 ret = scnprintf(buf, PAGE_SIZE, "panel_status=%s\n", "suspend");
653 } else {
654 panel_status = mdss_fb_send_panel_event(mfd,
655 MDSS_EVENT_DSI_PANEL_STATUS, NULL);
656 ret = scnprintf(buf, PAGE_SIZE, "panel_status=%s\n",
657 panel_status > 0 ? "alive" : "dead");
658 }
659
660 return ret;
661}
662
663static ssize_t mdss_fb_force_panel_dead(struct device *dev,
664 struct device_attribute *attr, const char *buf, size_t len)
665{
666 struct fb_info *fbi = dev_get_drvdata(dev);
667 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
668 struct mdss_panel_data *pdata;
669
670 pdata = dev_get_platdata(&mfd->pdev->dev);
671 if (!pdata) {
672 pr_err("no panel connected!\n");
673 return len;
674 }
675
676 if (kstrtouint(buf, 0, &pdata->panel_info.panel_force_dead))
677 pr_err("kstrtouint buf error!\n");
678
679 return len;
680}
681
682/*
683 * mdss_fb_blanking_mode_switch() - Function triggers dynamic mode switch
684 * @mfd: Framebuffer data structure for display
685 * @mode: Enabled/Disable LowPowerMode
686 * 1: Enter into LowPowerMode
687 * 0: Exit from LowPowerMode
688 *
689 * This Function dynamically switches to and from video mode. This
690 * swtich involves the panel turning off backlight during trantision.
691 */
692static int mdss_fb_blanking_mode_switch(struct msm_fb_data_type *mfd, int mode)
693{
694 int ret = 0;
695 u32 bl_lvl = 0;
696 struct mdss_panel_info *pinfo = NULL;
697 struct mdss_panel_data *pdata;
698
699 if (!mfd || !mfd->panel_info)
700 return -EINVAL;
701
702 pinfo = mfd->panel_info;
703
704 if (!pinfo->mipi.dms_mode) {
705 pr_warn("Panel does not support dynamic switch!\n");
706 return 0;
707 }
708
709 if (mode == pinfo->mipi.mode) {
710 pr_debug("Already in requested mode!\n");
711 return 0;
712 }
713 pr_debug("Enter mode: %d\n", mode);
714
715 pdata = dev_get_platdata(&mfd->pdev->dev);
716
717 pdata->panel_info.dynamic_switch_pending = true;
718 ret = mdss_fb_pan_idle(mfd);
719 if (ret) {
720 pr_err("mdss_fb_pan_idle for fb%d failed. ret=%d\n",
721 mfd->index, ret);
722 pdata->panel_info.dynamic_switch_pending = false;
723 return ret;
724 }
725
726 mutex_lock(&mfd->bl_lock);
727 bl_lvl = mfd->bl_level;
728 mdss_fb_set_backlight(mfd, 0);
729 mutex_unlock(&mfd->bl_lock);
730
731 lock_fb_info(mfd->fbi);
732 ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
733 mfd->op_enable);
734 if (ret) {
735 pr_err("can't turn off display!\n");
736 unlock_fb_info(mfd->fbi);
737 return ret;
738 }
739
740 mfd->op_enable = false;
741
742 ret = mfd->mdp.configure_panel(mfd, mode, 1);
743 mdss_fb_set_mdp_sync_pt_threshold(mfd, mfd->panel.type);
744
745 mfd->op_enable = true;
746
747 ret = mdss_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
748 mfd->op_enable);
749 if (ret) {
750 pr_err("can't turn on display!\n");
751 unlock_fb_info(mfd->fbi);
752 return ret;
753 }
754 unlock_fb_info(mfd->fbi);
755
756 mutex_lock(&mfd->bl_lock);
757 mfd->allow_bl_update = true;
758 mdss_fb_set_backlight(mfd, bl_lvl);
759 mutex_unlock(&mfd->bl_lock);
760
761 pdata->panel_info.dynamic_switch_pending = false;
762 pdata->panel_info.is_lpm_mode = mode ? 1 : 0;
763
764 if (ret) {
765 pr_err("can't turn on display!\n");
766 return ret;
767 }
768
769 pr_debug("Exit mode: %d\n", mode);
770
771 return 0;
772}
773
774static ssize_t mdss_fb_change_dfps_mode(struct device *dev,
775 struct device_attribute *attr, const char *buf, size_t len)
776{
777 struct fb_info *fbi = dev_get_drvdata(dev);
778 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
779 struct mdss_panel_data *pdata;
780 struct mdss_panel_info *pinfo;
781 u32 dfps_mode;
782
783 pdata = dev_get_platdata(&mfd->pdev->dev);
784 if (!pdata) {
785 pr_err("no panel connected!\n");
786 return len;
787 }
788 pinfo = &pdata->panel_info;
789
790 if (kstrtouint(buf, 0, &dfps_mode)) {
791 pr_err("kstrtouint buf error!\n");
792 return len;
793 }
794
795 if (dfps_mode >= DFPS_MODE_MAX) {
796 pinfo->dynamic_fps = false;
797 return len;
798 }
799
800 if (mfd->idle_time != 0) {
801 pr_err("ERROR: Idle time is not disabled.\n");
802 return len;
803 }
804
805 if (pinfo->current_fps != pinfo->default_fps) {
806 pr_err("ERROR: panel not configured to default fps\n");
807 return len;
808 }
809
810 pinfo->dynamic_fps = true;
811 pinfo->dfps_update = dfps_mode;
812
813 if (pdata->next)
814 pdata->next->panel_info.dfps_update = dfps_mode;
815
816 return len;
817}
818
819static ssize_t mdss_fb_get_dfps_mode(struct device *dev,
820 struct device_attribute *attr, char *buf)
821{
822 struct fb_info *fbi = dev_get_drvdata(dev);
823 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
824 struct mdss_panel_data *pdata;
825 struct mdss_panel_info *pinfo;
826 int ret;
827
828 pdata = dev_get_platdata(&mfd->pdev->dev);
829 if (!pdata) {
830 pr_err("no panel connected!\n");
831 return -EINVAL;
832 }
833 pinfo = &pdata->panel_info;
834
835 ret = scnprintf(buf, PAGE_SIZE, "dfps enabled=%d mode=%d\n",
836 pinfo->dynamic_fps, pinfo->dfps_update);
837
838 return ret;
839}
840
841static ssize_t mdss_fb_change_persist_mode(struct device *dev,
842 struct device_attribute *attr, const char *buf, size_t len)
843{
844 struct fb_info *fbi = dev_get_drvdata(dev);
845 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
846 struct mdss_panel_info *pinfo = NULL;
847 struct mdss_panel_data *pdata;
848 int ret = 0;
849 u32 persist_mode;
850
851 if (!mfd || !mfd->panel_info) {
852 pr_err("%s: Panel info is NULL!\n", __func__);
853 return len;
854 }
855
856 pinfo = mfd->panel_info;
857
858 if (kstrtouint(buf, 0, &persist_mode)) {
859 pr_err("kstrtouint buf error!\n");
860 return len;
861 }
862
863 mutex_lock(&mfd->mdss_sysfs_lock);
864 if (mdss_panel_is_power_off(mfd->panel_power_state)) {
865 pinfo->persist_mode = persist_mode;
866 goto end;
867 }
868
869 mutex_lock(&mfd->bl_lock);
870
871 pdata = dev_get_platdata(&mfd->pdev->dev);
872 if ((pdata) && (pdata->apply_display_setting))
873 ret = pdata->apply_display_setting(pdata, persist_mode);
874
875 mutex_unlock(&mfd->bl_lock);
876
877 if (!ret) {
878 pr_debug("%s: Persist mode %d\n", __func__, persist_mode);
879 pinfo->persist_mode = persist_mode;
880 }
881
882end:
883 mutex_unlock(&mfd->mdss_sysfs_lock);
884 return len;
885}
886
887static ssize_t mdss_fb_get_persist_mode(struct device *dev,
888 struct device_attribute *attr, char *buf)
889{
890 struct fb_info *fbi = dev_get_drvdata(dev);
891 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
892 struct mdss_panel_data *pdata;
893 struct mdss_panel_info *pinfo;
894 int ret;
895
896 pdata = dev_get_platdata(&mfd->pdev->dev);
897 if (!pdata) {
898 pr_err("no panel connected!\n");
899 return -EINVAL;
900 }
901 pinfo = &pdata->panel_info;
902
903 ret = scnprintf(buf, PAGE_SIZE, "%d\n", pinfo->persist_mode);
904
905 return ret;
906}
907
Abhijit Kulkarnic8c7eec2017-02-08 16:41:16 -0800908static ssize_t mdss_fb_idle_pc_notify(struct device *dev,
909 struct device_attribute *attr, char *buf)
910{
911 return scnprintf(buf, PAGE_SIZE, "idle power collapsed\n");
912}
913
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530914static DEVICE_ATTR(msm_fb_type, 0444, mdss_fb_get_type, NULL);
915static DEVICE_ATTR(msm_fb_split, 0644, mdss_fb_show_split,
916 mdss_fb_store_split);
917static DEVICE_ATTR(show_blank_event, 0444, mdss_mdp_show_blank_event, NULL);
918static DEVICE_ATTR(idle_time, 0644,
919 mdss_fb_get_idle_time, mdss_fb_set_idle_time);
920static DEVICE_ATTR(idle_notify, 0444, mdss_fb_get_idle_notify, NULL);
921static DEVICE_ATTR(msm_fb_panel_info, 0444, mdss_fb_get_panel_info, NULL);
922static DEVICE_ATTR(msm_fb_src_split_info, 0444, mdss_fb_get_src_split_info,
923 NULL);
924static DEVICE_ATTR(msm_fb_thermal_level, 0644,
925 mdss_fb_get_thermal_level, mdss_fb_set_thermal_level);
926static DEVICE_ATTR(msm_fb_panel_status, 0644,
927 mdss_fb_get_panel_status, mdss_fb_force_panel_dead);
928static DEVICE_ATTR(msm_fb_dfps_mode, 0644,
929 mdss_fb_get_dfps_mode, mdss_fb_change_dfps_mode);
930static DEVICE_ATTR(measured_fps, 0664,
931 mdss_fb_get_fps_info, NULL);
932static DEVICE_ATTR(msm_fb_persist_mode, 0644,
933 mdss_fb_get_persist_mode, mdss_fb_change_persist_mode);
Abhijit Kulkarnic8c7eec2017-02-08 16:41:16 -0800934static DEVICE_ATTR(idle_power_collapse, 0444, mdss_fb_idle_pc_notify, NULL);
935
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530936static struct attribute *mdss_fb_attrs[] = {
937 &dev_attr_msm_fb_type.attr,
938 &dev_attr_msm_fb_split.attr,
939 &dev_attr_show_blank_event.attr,
940 &dev_attr_idle_time.attr,
941 &dev_attr_idle_notify.attr,
942 &dev_attr_msm_fb_panel_info.attr,
943 &dev_attr_msm_fb_src_split_info.attr,
944 &dev_attr_msm_fb_thermal_level.attr,
945 &dev_attr_msm_fb_panel_status.attr,
946 &dev_attr_msm_fb_dfps_mode.attr,
947 &dev_attr_measured_fps.attr,
948 &dev_attr_msm_fb_persist_mode.attr,
Abhijit Kulkarnic8c7eec2017-02-08 16:41:16 -0800949 &dev_attr_idle_power_collapse.attr,
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530950 NULL,
951};
952
953static struct attribute_group mdss_fb_attr_group = {
954 .attrs = mdss_fb_attrs,
955};
956
957static int mdss_fb_create_sysfs(struct msm_fb_data_type *mfd)
958{
959 int rc;
960
961 rc = sysfs_create_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
962 if (rc)
963 pr_err("sysfs group creation failed, rc=%d\n", rc);
964 return rc;
965}
966
967static void mdss_fb_remove_sysfs(struct msm_fb_data_type *mfd)
968{
969 sysfs_remove_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
970}
971
972static void mdss_fb_shutdown(struct platform_device *pdev)
973{
974 struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
975
Sachin Bhayareeeb88892018-01-02 16:36:01 +0530976 mfd->shutdown_pending = true;
977
978 /* wake up threads waiting on idle or kickoff queues */
979 wake_up_all(&mfd->idle_wait_q);
980 wake_up_all(&mfd->kickoff_wait_q);
981
982 lock_fb_info(mfd->fbi);
983 mdss_fb_release_all(mfd->fbi, true);
984 sysfs_notify(&mfd->fbi->dev->kobj, NULL, "show_blank_event");
985 unlock_fb_info(mfd->fbi);
986}
987
988static void mdss_fb_input_event_handler(struct input_handle *handle,
989 unsigned int type,
990 unsigned int code,
991 int value)
992{
993 struct msm_fb_data_type *mfd = handle->handler->private;
994 int rc;
995
996 if ((type != EV_ABS) || !mdss_fb_is_power_on(mfd))
997 return;
998
999 if (mfd->mdp.input_event_handler) {
1000 rc = mfd->mdp.input_event_handler(mfd);
1001 if (rc)
1002 pr_err("mdp input event handler failed\n");
1003 }
1004}
1005
1006static int mdss_fb_input_connect(struct input_handler *handler,
1007 struct input_dev *dev,
1008 const struct input_device_id *id)
1009{
1010 int rc;
1011 struct input_handle *handle;
1012
1013 handle = kzalloc(sizeof(*handle), GFP_KERNEL);
1014 if (!handle)
1015 return -ENOMEM;
1016
1017 handle->dev = dev;
1018 handle->handler = handler;
1019 handle->name = handler->name;
1020
1021 rc = input_register_handle(handle);
1022 if (rc) {
1023 pr_err("failed to register input handle, rc = %d\n", rc);
1024 goto error;
1025 }
1026
1027 rc = input_open_device(handle);
1028 if (rc) {
1029 pr_err("failed to open input device, rc = %d\n", rc);
1030 goto error_unregister;
1031 }
1032
1033 return 0;
1034
1035error_unregister:
1036 input_unregister_handle(handle);
1037error:
1038 kfree(handle);
1039 return rc;
1040}
1041
1042static void mdss_fb_input_disconnect(struct input_handle *handle)
1043{
1044 input_close_device(handle);
1045 input_unregister_handle(handle);
1046 kfree(handle);
1047}
1048
1049/*
1050 * Structure for specifying event parameters on which to receive callbacks.
1051 * This structure will trigger a callback in case of a touch event (specified by
1052 * EV_ABS) where there is a change in X and Y coordinates,
1053 */
1054static const struct input_device_id mdss_fb_input_ids[] = {
1055 {
1056 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
1057 .evbit = { BIT_MASK(EV_ABS) },
1058 .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
1059 BIT_MASK(ABS_MT_POSITION_X) |
1060 BIT_MASK(ABS_MT_POSITION_Y) },
1061 },
1062 { },
1063};
1064
1065static int mdss_fb_register_input_handler(struct msm_fb_data_type *mfd)
1066{
1067 int rc;
1068 struct input_handler *handler;
1069
1070 if (mfd->input_handler)
1071 return -EINVAL;
1072
1073 handler = kzalloc(sizeof(*handler), GFP_KERNEL);
1074 if (!handler)
1075 return -ENOMEM;
1076
1077 handler->event = mdss_fb_input_event_handler;
1078 handler->connect = mdss_fb_input_connect;
1079 handler->disconnect = mdss_fb_input_disconnect,
1080 handler->name = "mdss_fb",
1081 handler->id_table = mdss_fb_input_ids;
1082 handler->private = mfd;
1083
1084 rc = input_register_handler(handler);
1085 if (rc) {
1086 pr_err("Unable to register the input handler\n");
1087 kfree(handler);
1088 } else {
1089 mfd->input_handler = handler;
1090 }
1091
1092 return rc;
1093}
1094
1095static void mdss_fb_unregister_input_handler(struct msm_fb_data_type *mfd)
1096{
1097 if (!mfd->input_handler)
1098 return;
1099
1100 input_unregister_handler(mfd->input_handler);
1101 kfree(mfd->input_handler);
1102}
1103
1104static void mdss_fb_videomode_from_panel_timing(struct fb_videomode *videomode,
1105 struct mdss_panel_timing *pt)
1106{
1107 videomode->name = pt->name;
1108 videomode->xres = pt->xres;
1109 videomode->yres = pt->yres;
1110 videomode->left_margin = pt->h_back_porch;
1111 videomode->right_margin = pt->h_front_porch;
1112 videomode->hsync_len = pt->h_pulse_width;
1113 videomode->upper_margin = pt->v_back_porch;
1114 videomode->lower_margin = pt->v_front_porch;
1115 videomode->vsync_len = pt->v_pulse_width;
1116 videomode->refresh = pt->frame_rate;
1117 videomode->flag = 0;
1118 videomode->vmode = 0;
1119 videomode->sync = 0;
1120
1121 if (videomode->refresh) {
1122 unsigned long clk_rate, h_total, v_total;
1123
1124 h_total = videomode->xres + videomode->left_margin
1125 + videomode->right_margin + videomode->hsync_len;
1126 v_total = videomode->yres + videomode->lower_margin
1127 + videomode->upper_margin + videomode->vsync_len;
1128 clk_rate = h_total * v_total * videomode->refresh;
1129 videomode->pixclock =
1130 KHZ2PICOS(clk_rate / 1000);
1131 } else {
1132 videomode->pixclock =
1133 KHZ2PICOS((unsigned long)pt->clk_rate / 1000);
1134 }
1135}
1136
1137static void mdss_fb_set_split_mode(struct msm_fb_data_type *mfd,
1138 struct mdss_panel_data *pdata)
1139{
1140 if (pdata->panel_info.is_split_display) {
1141 struct mdss_panel_data *pnext = pdata->next;
1142
1143 mfd->split_fb_left = pdata->panel_info.lm_widths[0];
1144 if (pnext)
1145 mfd->split_fb_right = pnext->panel_info.lm_widths[0];
1146
1147 if (pdata->panel_info.use_pingpong_split)
1148 mfd->split_mode = MDP_PINGPONG_SPLIT;
1149 else
1150 mfd->split_mode = MDP_DUAL_LM_DUAL_DISPLAY;
1151 } else if ((pdata->panel_info.lm_widths[0] != 0)
1152 && (pdata->panel_info.lm_widths[1] != 0)) {
1153 mfd->split_fb_left = pdata->panel_info.lm_widths[0];
1154 mfd->split_fb_right = pdata->panel_info.lm_widths[1];
1155 mfd->split_mode = MDP_DUAL_LM_SINGLE_DISPLAY;
1156 } else {
1157 mfd->split_mode = MDP_SPLIT_MODE_NONE;
1158 }
1159}
1160
1161static int mdss_fb_init_panel_modes(struct msm_fb_data_type *mfd,
1162 struct mdss_panel_data *pdata)
1163{
1164 struct fb_info *fbi = mfd->fbi;
1165 struct fb_videomode *modedb;
1166 struct mdss_panel_timing *pt;
1167 struct list_head *pos;
1168 int num_timings = 0;
1169 int i = 0;
1170
1171 /* check if multiple modes are supported */
1172 if (!pdata->timings_list.prev || !pdata->timings_list.next)
1173 INIT_LIST_HEAD(&pdata->timings_list);
1174
1175 if (!fbi || !pdata->current_timing || list_empty(&pdata->timings_list))
1176 return 0;
1177
1178 list_for_each(pos, &pdata->timings_list)
1179 num_timings++;
1180
1181 modedb = devm_kzalloc(fbi->dev, num_timings * sizeof(*modedb),
1182 GFP_KERNEL);
1183 if (!modedb)
1184 return -ENOMEM;
1185
1186 list_for_each_entry(pt, &pdata->timings_list, list) {
1187 struct mdss_panel_timing *spt = NULL;
1188
1189 mdss_fb_videomode_from_panel_timing(modedb + i, pt);
1190 if (pdata->next) {
1191 spt = mdss_panel_get_timing_by_name(pdata->next,
1192 modedb[i].name);
Sandeep Panda77497c02017-06-28 18:31:35 +05301193 /* for split config, recalculate xres and pixel clock */
1194 if (!IS_ERR_OR_NULL(spt)) {
1195 unsigned long pclk, h_total, v_total;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301196 modedb[i].xres += spt->xres;
Sandeep Panda77497c02017-06-28 18:31:35 +05301197 h_total = modedb[i].xres +
1198 modedb[i].left_margin +
1199 modedb[i].right_margin +
1200 modedb[i].hsync_len;
1201 v_total = modedb[i].yres +
1202 modedb[i].lower_margin +
1203 modedb[i].upper_margin +
1204 modedb[i].vsync_len;
1205 pclk = h_total * v_total * modedb[i].refresh;
1206 modedb[i].pixclock = KHZ2PICOS(pclk / 1000);
1207 } else {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301208 pr_debug("no matching split config for %s\n",
1209 modedb[i].name);
Sandeep Panda77497c02017-06-28 18:31:35 +05301210 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301211
1212 /*
1213 * if no panel timing found for current, need to
1214 * disable it otherwise mark it as active
1215 */
1216 if (pt == pdata->current_timing)
1217 pdata->next->active = !IS_ERR_OR_NULL(spt);
1218 }
1219
1220 if (pt == pdata->current_timing) {
1221 pr_debug("found current mode: %s\n", pt->name);
1222 fbi->mode = modedb + i;
1223 }
1224 i++;
1225 }
1226
1227 fbi->monspecs.modedb = modedb;
1228 fbi->monspecs.modedb_len = num_timings;
1229
1230 /* destroy and recreate modelist */
1231 fb_destroy_modelist(&fbi->modelist);
1232
1233 if (fbi->mode)
1234 fb_videomode_to_var(&fbi->var, fbi->mode);
1235 fb_videomode_to_modelist(modedb, num_timings, &fbi->modelist);
1236
1237 return 0;
1238}
1239
1240static int mdss_fb_probe(struct platform_device *pdev)
1241{
1242 struct msm_fb_data_type *mfd = NULL;
1243 struct mdss_panel_data *pdata;
1244 struct fb_info *fbi;
1245 int rc;
Arun kumardb962812018-05-30 16:31:52 +05301246 const char *data;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301247
1248 if (fbi_list_index >= MAX_FBI_LIST)
1249 return -ENOMEM;
1250
1251 pdata = dev_get_platdata(&pdev->dev);
1252 if (!pdata)
1253 return -EPROBE_DEFER;
1254
1255 if (!mdp_instance) {
1256 pr_err("mdss mdp resource not initialized yet\n");
1257 return -ENODEV;
1258 }
1259
1260 /*
1261 * alloc framebuffer info + par data
1262 */
1263 fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
1264 if (fbi == NULL) {
1265 pr_err("can't allocate framebuffer info data!\n");
1266 return -ENOMEM;
1267 }
1268
1269 mfd = (struct msm_fb_data_type *)fbi->par;
1270 mfd->key = MFD_KEY;
1271 mfd->fbi = fbi;
1272 mfd->panel_info = &pdata->panel_info;
1273 mfd->panel.type = pdata->panel_info.type;
1274 mfd->panel.id = mfd->index;
1275 mfd->fb_page = MDSS_FB_NUM;
1276 mfd->index = fbi_list_index;
1277 mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
1278
1279 mfd->ext_ad_ctrl = -1;
1280 if (mfd->panel_info && mfd->panel_info->brightness_max > 0)
1281 MDSS_BRIGHT_TO_BL(mfd->bl_level, backlight_led.brightness,
1282 mfd->panel_info->bl_max, mfd->panel_info->brightness_max);
1283 else
1284 mfd->bl_level = 0;
1285
1286 mfd->bl_scale = 1024;
1287 mfd->bl_min_lvl = 30;
1288 mfd->ad_bl_level = 0;
1289 mfd->fb_imgType = MDP_RGBA_8888;
1290 mfd->calib_mode_bl = 0;
1291 mfd->unset_bl_level = U32_MAX;
Xu Yang49104572017-03-17 17:15:19 +08001292 mfd->bl_extn_level = -1;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301293
1294 mfd->pdev = pdev;
1295
Arun kumardb962812018-05-30 16:31:52 +05301296 if (mfd->panel.type == SPI_PANEL)
1297 mfd->fb_imgType = MDP_RGB_565;
1298 if (mfd->panel.type == MIPI_VIDEO_PANEL || mfd->panel.type ==
1299 MIPI_CMD_PANEL || mfd->panel.type == SPI_PANEL){
1300 rc = of_property_read_string(pdev->dev.of_node,
1301 "qcom,mdss-fb-format", &data);
1302 if (!rc) {
1303 if (!strcmp(data, "rgb888"))
1304 mfd->fb_imgType = MDP_RGB_888;
1305 else if (!strcmp(data, "rgb565"))
1306 mfd->fb_imgType = MDP_RGB_565;
1307 else
1308 mfd->fb_imgType = MDP_RGBA_8888;
1309 }
1310 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301311 mfd->split_fb_left = mfd->split_fb_right = 0;
1312
1313 mdss_fb_set_split_mode(mfd, pdata);
1314 pr_info("fb%d: split_mode:%d left:%d right:%d\n", mfd->index,
1315 mfd->split_mode, mfd->split_fb_left, mfd->split_fb_right);
1316
1317 mfd->mdp = *mdp_instance;
1318
1319 rc = of_property_read_bool(pdev->dev.of_node,
1320 "qcom,boot-indication-enabled");
1321
1322 if (rc) {
1323 led_trigger_register_simple("boot-indication",
1324 &(mfd->boot_notification_led));
1325 }
1326
1327 INIT_LIST_HEAD(&mfd->file_list);
1328
1329 mutex_init(&mfd->bl_lock);
1330 mutex_init(&mfd->mdss_sysfs_lock);
1331 mutex_init(&mfd->switch_lock);
1332
1333 fbi_list[fbi_list_index++] = fbi;
1334
1335 platform_set_drvdata(pdev, mfd);
1336
1337 rc = mdss_fb_register(mfd);
1338 if (rc)
1339 return rc;
1340
1341 mdss_fb_create_sysfs(mfd);
1342 mdss_fb_send_panel_event(mfd, MDSS_EVENT_FB_REGISTERED, fbi);
1343
1344 if (mfd->mdp.init_fnc) {
1345 rc = mfd->mdp.init_fnc(mfd);
1346 if (rc) {
1347 pr_err("init_fnc failed\n");
1348 return rc;
1349 }
1350 }
1351 mdss_fb_init_fps_info(mfd);
1352
1353 rc = pm_runtime_set_active(mfd->fbi->dev);
1354 if (rc < 0)
1355 pr_err("pm_runtime: fail to set active.\n");
1356 pm_runtime_enable(mfd->fbi->dev);
1357
1358 /* android supports only one lcd-backlight/lcd for now */
1359 if (!lcd_backlight_registered) {
1360 backlight_led.brightness = mfd->panel_info->brightness_max;
1361 backlight_led.max_brightness = mfd->panel_info->brightness_max;
1362 if (led_classdev_register(&pdev->dev, &backlight_led))
1363 pr_err("led_classdev_register failed\n");
1364 else
1365 lcd_backlight_registered = 1;
1366 }
1367
1368 mdss_fb_init_panel_modes(mfd, pdata);
1369
1370 mfd->mdp_sync_pt_data.fence_name = "mdp-fence";
1371 if (mfd->mdp_sync_pt_data.timeline == NULL) {
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05301372 char timeline_name[32];
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301373
1374 snprintf(timeline_name, sizeof(timeline_name),
1375 "mdss_fb_%d", mfd->index);
1376 mfd->mdp_sync_pt_data.timeline =
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05301377 mdss_create_timeline(timeline_name);
1378 if (mfd->mdp_sync_pt_data.timeline == NULL) {
1379 pr_err("cannot create release fence time line\n");
1380 return -ENOMEM;
1381 }
Krishna Manikandanb296a2b2018-03-21 17:16:31 +05301382
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301383 mfd->mdp_sync_pt_data.notifier.notifier_call =
1384 __mdss_fb_sync_buf_done_callback;
1385 }
1386
1387 mdss_fb_set_mdp_sync_pt_threshold(mfd, mfd->panel.type);
1388
1389 if (mfd->mdp.splash_init_fnc)
1390 mfd->mdp.splash_init_fnc(mfd);
1391
1392 /*
1393 * Register with input driver for a callback for command mode panels.
1394 * When there is an input event, mdp clocks will be turned on to reduce
1395 * latency when a frame update happens.
1396 * For video mode panels, idle timeout will be delayed so that userspace
1397 * does not get an idle event while new frames are expected. In case of
1398 * an idle event, user space tries to fall back to GPU composition which
1399 * can lead to increased load when there are new frames.
1400 */
1401 if (mfd->mdp.input_event_handler &&
1402 ((mfd->panel_info->type == MIPI_CMD_PANEL) ||
1403 (mfd->panel_info->type == MIPI_VIDEO_PANEL)))
1404 if (mdss_fb_register_input_handler(mfd))
1405 pr_err("failed to register input handler\n");
1406
1407 INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
1408
1409 return rc;
1410}
1411
1412static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd,
1413 int type)
1414{
1415 if (!mfd)
1416 return;
1417
1418 switch (type) {
1419 case WRITEBACK_PANEL:
1420 mfd->mdp_sync_pt_data.threshold = 1;
1421 mfd->mdp_sync_pt_data.retire_threshold = 0;
1422 break;
Arun kumardb962812018-05-30 16:31:52 +05301423 case SPI_PANEL:
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301424 case MIPI_CMD_PANEL:
1425 mfd->mdp_sync_pt_data.threshold = 1;
1426 mfd->mdp_sync_pt_data.retire_threshold = 1;
1427 break;
1428 default:
1429 mfd->mdp_sync_pt_data.threshold = 2;
1430 mfd->mdp_sync_pt_data.retire_threshold = 0;
1431 break;
1432 }
1433}
1434
1435static int mdss_fb_remove(struct platform_device *pdev)
1436{
1437 struct msm_fb_data_type *mfd;
1438
1439 mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
1440
1441 if (!mfd)
1442 return -ENODEV;
1443
1444 mdss_fb_remove_sysfs(mfd);
1445
1446 pm_runtime_disable(mfd->fbi->dev);
1447
1448 if (mfd->key != MFD_KEY)
1449 return -EINVAL;
1450
1451 mdss_fb_unregister_input_handler(mfd);
1452 mdss_panel_debugfs_cleanup(mfd->panel_info);
1453
1454 if (mdss_fb_suspend_sub(mfd))
1455 pr_err("msm_fb_remove: can't stop the device %d\n",
1456 mfd->index);
1457
1458 /* remove /dev/fb* */
1459 unregister_framebuffer(mfd->fbi);
1460
1461 if (lcd_backlight_registered) {
1462 lcd_backlight_registered = 0;
1463 led_classdev_unregister(&backlight_led);
1464 }
1465
1466 return 0;
1467}
1468
1469static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
1470 int event, void *arg)
1471{
1472 int ret = 0;
1473 struct mdss_panel_data *pdata;
1474
1475 pdata = dev_get_platdata(&mfd->pdev->dev);
1476 if (!pdata) {
1477 pr_err("no panel connected\n");
1478 return -ENODEV;
1479 }
1480
1481 pr_debug("sending event=%d for fb%d\n", event, mfd->index);
1482
1483 do {
1484 if (pdata->event_handler)
1485 ret = pdata->event_handler(pdata, event, arg);
1486
1487 pdata = pdata->next;
1488 } while (!ret && pdata);
1489
1490 return ret;
1491}
1492
1493static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd)
1494{
1495 int ret = 0;
1496
1497 if ((!mfd) || (mfd->key != MFD_KEY))
1498 return 0;
1499
1500 pr_debug("mdss_fb suspend index=%d\n", mfd->index);
1501
1502 ret = mdss_fb_pan_idle(mfd);
1503 if (ret) {
1504 pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d\n",
1505 mfd->index, ret);
1506 goto exit;
1507 }
1508
1509 ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_SUSPEND, NULL);
1510 if (ret) {
1511 pr_warn("unable to suspend fb%d (%d)\n", mfd->index, ret);
1512 goto exit;
1513 }
1514
1515 mfd->suspend.op_enable = mfd->op_enable;
1516 mfd->suspend.panel_power_state = mfd->panel_power_state;
1517
1518 if (mfd->op_enable) {
1519 /*
1520 * Ideally, display should have either been blanked by now, or
1521 * should have transitioned to a low power state. If not, then
1522 * as a fall back option, enter ulp state to leave the display
1523 * on, but turn off all interface clocks.
1524 */
1525 if (mdss_fb_is_power_on(mfd)) {
1526 ret = mdss_fb_blank_sub(BLANK_FLAG_ULP, mfd->fbi,
1527 mfd->suspend.op_enable);
1528 if (ret) {
1529 pr_err("can't turn off display!\n");
1530 goto exit;
1531 }
1532 }
1533 mfd->op_enable = false;
1534 fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED);
1535 }
1536exit:
1537 return ret;
1538}
1539
1540static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd)
1541{
1542 int ret = 0;
1543
1544 if ((!mfd) || (mfd->key != MFD_KEY))
1545 return 0;
1546
1547 reinit_completion(&mfd->power_set_comp);
1548 mfd->is_power_setting = true;
1549 pr_debug("mdss_fb resume index=%d\n", mfd->index);
1550
1551 ret = mdss_fb_pan_idle(mfd);
1552 if (ret) {
1553 pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d\n",
1554 mfd->index, ret);
1555 return ret;
1556 }
1557
1558 ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_RESUME, NULL);
1559 if (ret) {
1560 pr_warn("unable to resume fb%d (%d)\n", mfd->index, ret);
1561 return ret;
1562 }
1563
1564 /* resume state var recover */
1565 mfd->op_enable = mfd->suspend.op_enable;
1566
1567 /*
1568 * If the fb was explicitly blanked or transitioned to ulp during
1569 * suspend, then undo it during resume with the appropriate unblank
1570 * flag. If fb was in ulp state when entering suspend, then nothing
1571 * needs to be done.
1572 */
1573 if (mdss_panel_is_power_on(mfd->suspend.panel_power_state) &&
1574 !mdss_panel_is_power_on_ulp(mfd->suspend.panel_power_state)) {
1575 int unblank_flag = mdss_panel_is_power_on_interactive(
1576 mfd->suspend.panel_power_state) ? FB_BLANK_UNBLANK :
1577 BLANK_FLAG_LP;
1578
1579 ret = mdss_fb_blank_sub(unblank_flag, mfd->fbi, mfd->op_enable);
1580 if (ret)
1581 pr_warn("can't turn on display!\n");
1582 else
1583 fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
1584 }
1585 mfd->is_power_setting = false;
1586 complete_all(&mfd->power_set_comp);
1587
1588 return ret;
1589}
1590
1591#if defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP)
1592static int mdss_fb_suspend(struct platform_device *pdev, pm_message_t state)
1593{
1594 struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
1595
1596 if (!mfd)
1597 return -ENODEV;
1598
1599 dev_dbg(&pdev->dev, "display suspend\n");
1600
1601 return mdss_fb_suspend_sub(mfd);
1602}
1603
1604static int mdss_fb_resume(struct platform_device *pdev)
1605{
1606 struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
1607
1608 if (!mfd)
1609 return -ENODEV;
1610
1611 dev_dbg(&pdev->dev, "display resume\n");
1612
1613 return mdss_fb_resume_sub(mfd);
1614}
1615#else
1616#define mdss_fb_suspend NULL
1617#define mdss_fb_resume NULL
1618#endif
1619
1620#ifdef CONFIG_PM_SLEEP
1621static int mdss_fb_pm_suspend(struct device *dev)
1622{
1623 struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
1624
1625 if (!mfd)
1626 return -ENODEV;
1627
1628 dev_dbg(dev, "display pm suspend\n");
1629
1630 return mdss_fb_suspend_sub(mfd);
1631}
1632
1633static int mdss_fb_pm_resume(struct device *dev)
1634{
1635 struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
1636
1637 if (!mfd)
1638 return -ENODEV;
1639
1640 dev_dbg(dev, "display pm resume\n");
1641
1642 /*
1643 * It is possible that the runtime status of the fb device may
1644 * have been active when the system was suspended. Reset the runtime
1645 * status to suspended state after a complete system resume.
1646 */
1647 pm_runtime_disable(dev);
1648 pm_runtime_set_suspended(dev);
1649 pm_runtime_enable(dev);
1650
1651 return mdss_fb_resume_sub(mfd);
1652}
1653#endif
1654
1655static const struct dev_pm_ops mdss_fb_pm_ops = {
1656 SET_SYSTEM_SLEEP_PM_OPS(mdss_fb_pm_suspend, mdss_fb_pm_resume)
1657};
1658
1659static const struct of_device_id mdss_fb_dt_match[] = {
1660 { .compatible = "qcom,mdss-fb",},
1661 {}
1662};
1663EXPORT_COMPAT("qcom,mdss-fb");
1664
1665static struct platform_driver mdss_fb_driver = {
1666 .probe = mdss_fb_probe,
1667 .remove = mdss_fb_remove,
1668 .suspend = mdss_fb_suspend,
1669 .resume = mdss_fb_resume,
1670 .shutdown = mdss_fb_shutdown,
1671 .driver = {
1672 .name = "mdss_fb",
1673 .of_match_table = mdss_fb_dt_match,
1674 .pm = &mdss_fb_pm_ops,
1675 },
1676};
1677
1678static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
1679{
1680 u32 temp = *bl_lvl;
1681
1682 pr_debug("input = %d, scale = %d\n", temp, mfd->bl_scale);
1683 if (temp >= mfd->bl_min_lvl) {
1684 if (temp > mfd->panel_info->bl_max) {
1685 pr_warn("%s: invalid bl level\n",
1686 __func__);
1687 temp = mfd->panel_info->bl_max;
1688 }
1689 if (mfd->bl_scale > 1024) {
1690 pr_warn("%s: invalid bl scale\n",
1691 __func__);
1692 mfd->bl_scale = 1024;
1693 }
1694 /*
1695 * bl_scale is the numerator of
1696 * scaling fraction (x/1024)
1697 */
1698 temp = (temp * mfd->bl_scale) / 1024;
1699
1700 /*if less than minimum level, use min level*/
1701 if (temp < mfd->bl_min_lvl)
1702 temp = mfd->bl_min_lvl;
1703 }
1704 pr_debug("output = %d\n", temp);
1705
1706 (*bl_lvl) = temp;
1707}
1708
1709/* must call this function from within mfd->bl_lock */
1710void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
1711{
1712 struct mdss_panel_data *pdata;
1713 u32 temp = bkl_lvl;
1714 bool ad_bl_notify_needed = false;
1715 bool bl_notify_needed = false;
Arun kumar162db222018-05-09 17:28:40 +05301716 bool twm_en = false;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301717
1718 if ((((mdss_fb_is_power_off(mfd) && mfd->dcm_state != DCM_ENTER)
Krishna Manikandan695632e2020-03-04 20:50:28 +05301719 || !mfd->allow_bl_update) && !IS_CALIB_MODE_BL(mfd) &&
1720 !mfd->allow_secure_bl_update) ||
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301721 mfd->panel_info->cont_splash_enabled) {
1722 mfd->unset_bl_level = bkl_lvl;
1723 return;
1724 } else if (mdss_fb_is_power_on(mfd) && mfd->panel_info->panel_dead) {
1725 mfd->unset_bl_level = mfd->bl_level;
Krishna Manikandan695632e2020-03-04 20:50:28 +05301726 } else if (!mfd->allow_secure_bl_update) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301727 mfd->unset_bl_level = U32_MAX;
1728 }
1729
1730 pdata = dev_get_platdata(&mfd->pdev->dev);
1731
1732 if ((pdata) && (pdata->set_backlight)) {
1733 if (mfd->mdp.ad_calc_bl)
1734 (*mfd->mdp.ad_calc_bl)(mfd, temp, &temp,
1735 &ad_bl_notify_needed);
1736 if (!IS_CALIB_MODE_BL(mfd))
1737 mdss_fb_scale_bl(mfd, &temp);
Krishna Manikandan695632e2020-03-04 20:50:28 +05301738
1739 if (!temp && !mfd->allow_secure_bl_update && mfd->bl_level)
1740 mfd->unset_bl_level = mfd->bl_level;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301741 /*
1742 * Even though backlight has been scaled, want to show that
1743 * backlight has been set to bkl_lvl to those that read from
1744 * sysfs node. Thus, need to set bl_level even if it appears
1745 * the backlight has already been set to the level it is at,
1746 * as well as setting bl_level to bkl_lvl even though the
1747 * backlight has been set to the scaled value.
1748 */
1749 if (mfd->bl_level_scaled == temp) {
1750 mfd->bl_level = bkl_lvl;
1751 } else {
1752 if (mfd->bl_level != bkl_lvl)
1753 bl_notify_needed = true;
1754 pr_debug("backlight sent to panel :%d\n", temp);
Arun kumar162db222018-05-09 17:28:40 +05301755
1756 if (mfd->mdp.is_twm_en)
1757 twm_en = mfd->mdp.is_twm_en();
1758
1759 if (twm_en) {
1760 pr_info("TWM Enabled skip backlight update\n");
1761 } else {
1762 pdata->set_backlight(pdata, temp);
1763 mfd->bl_level = bkl_lvl;
1764 mfd->bl_level_scaled = temp;
1765 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301766 }
1767 if (ad_bl_notify_needed)
1768 mdss_fb_bl_update_notify(mfd,
1769 NOTIFY_TYPE_BL_AD_ATTEN_UPDATE);
1770 if (bl_notify_needed)
1771 mdss_fb_bl_update_notify(mfd,
1772 NOTIFY_TYPE_BL_UPDATE);
1773 }
1774}
1775
1776void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
1777{
1778 struct mdss_panel_data *pdata;
1779 u32 temp;
1780 bool bl_notify = false;
1781
1782 if (mfd->unset_bl_level == U32_MAX)
1783 return;
1784 mutex_lock(&mfd->bl_lock);
1785 if (!mfd->allow_bl_update) {
1786 pdata = dev_get_platdata(&mfd->pdev->dev);
1787 if ((pdata) && (pdata->set_backlight)) {
1788 mfd->bl_level = mfd->unset_bl_level;
1789 temp = mfd->bl_level;
1790 if (mfd->mdp.ad_calc_bl)
1791 (*mfd->mdp.ad_calc_bl)(mfd, temp, &temp,
1792 &bl_notify);
1793 if (bl_notify)
1794 mdss_fb_bl_update_notify(mfd,
1795 NOTIFY_TYPE_BL_AD_ATTEN_UPDATE);
1796 mdss_fb_bl_update_notify(mfd, NOTIFY_TYPE_BL_UPDATE);
1797 pdata->set_backlight(pdata, temp);
1798 mfd->bl_level_scaled = mfd->unset_bl_level;
1799 mfd->allow_bl_update = true;
1800 }
1801 }
1802 mutex_unlock(&mfd->bl_lock);
1803}
1804
1805static int mdss_fb_start_disp_thread(struct msm_fb_data_type *mfd)
1806{
1807 int ret = 0;
1808
1809 pr_debug("%pS: start display thread fb%d\n",
1810 __builtin_return_address(0), mfd->index);
1811
1812 /* this is needed for new split request from debugfs */
1813 mdss_fb_get_split(mfd);
1814
1815 atomic_set(&mfd->commits_pending, 0);
1816 mfd->disp_thread = kthread_run(__mdss_fb_display_thread,
1817 mfd, "mdss_fb%d", mfd->index);
1818
1819 if (IS_ERR(mfd->disp_thread)) {
1820 pr_err("ERROR: unable to start display thread %d\n",
1821 mfd->index);
1822 ret = PTR_ERR(mfd->disp_thread);
1823 mfd->disp_thread = NULL;
1824 }
1825
1826 return ret;
1827}
1828
1829static void mdss_fb_stop_disp_thread(struct msm_fb_data_type *mfd)
1830{
1831 pr_debug("%pS: stop display thread fb%d\n",
1832 __builtin_return_address(0), mfd->index);
1833
1834 kthread_stop(mfd->disp_thread);
1835 mfd->disp_thread = NULL;
1836}
1837
1838static void mdss_panel_validate_debugfs_info(struct msm_fb_data_type *mfd)
1839{
1840 struct mdss_panel_info *panel_info = mfd->panel_info;
1841 struct fb_info *fbi = mfd->fbi;
1842 struct fb_var_screeninfo *var = &fbi->var;
1843 struct mdss_panel_data *pdata = container_of(panel_info,
1844 struct mdss_panel_data, panel_info);
1845
1846 if (panel_info->debugfs_info->override_flag) {
1847 if (mfd->mdp.off_fnc) {
1848 mfd->panel_reconfig = true;
1849 mfd->mdp.off_fnc(mfd);
1850 mfd->panel_reconfig = false;
1851 }
1852
1853 pr_debug("Overriding panel_info with debugfs_info\n");
1854 panel_info->debugfs_info->override_flag = 0;
1855 mdss_panel_debugfsinfo_to_panelinfo(panel_info);
1856 if (is_panel_split(mfd) && pdata->next)
1857 mdss_fb_validate_split(pdata->panel_info.xres,
1858 pdata->next->panel_info.xres, mfd);
1859 mdss_panelinfo_to_fb_var(panel_info, var);
1860 if (mdss_fb_send_panel_event(mfd, MDSS_EVENT_CHECK_PARAMS,
1861 panel_info))
1862 pr_err("Failed to send panel event CHECK_PARAMS\n");
1863 }
1864}
1865
Animesh Kishore8b42bd92018-12-04 18:57:13 +05301866static void mdss_fb_signal_retire_fence(struct msm_fb_data_type *mfd)
1867{
1868#ifdef TARGET_HW_MDSS_MDP3
1869 struct mdp3_session_data *mdp3_session = mfd_to_mdp3_data(mfd);
1870 int retire_cnt = mdp3_session->retire_cnt;
1871#else
1872 struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
1873 int retire_cnt = mdp5_data->retire_cnt;
1874#endif
1875
1876 if (mfd->mdp.signal_retire_fence)
1877 mfd->mdp.signal_retire_fence(mfd, retire_cnt);
1878}
1879
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301880static int mdss_fb_blank_blank(struct msm_fb_data_type *mfd,
1881 int req_power_state)
1882{
1883 int ret = 0;
1884 int cur_power_state, current_bl;
1885
1886 if (!mfd)
1887 return -EINVAL;
1888
1889 if (!mdss_fb_is_power_on(mfd) || !mfd->mdp.off_fnc)
1890 return 0;
1891
1892 cur_power_state = mfd->panel_power_state;
1893
1894 pr_debug("Transitioning from %d --> %d\n", cur_power_state,
1895 req_power_state);
1896
1897 if (cur_power_state == req_power_state) {
1898 pr_debug("No change in power state\n");
1899 return 0;
1900 }
1901
1902 mutex_lock(&mfd->update.lock);
1903 mfd->update.type = NOTIFY_TYPE_SUSPEND;
1904 mfd->update.is_suspend = 1;
1905 mutex_unlock(&mfd->update.lock);
1906 complete(&mfd->update.comp);
1907 del_timer(&mfd->no_update.timer);
1908 mfd->no_update.value = NOTIFY_TYPE_SUSPEND;
1909 complete(&mfd->no_update.comp);
1910
1911 mfd->op_enable = false;
1912 if (mdss_panel_is_power_off(req_power_state)) {
1913 /* Stop Display thread */
1914 if (mfd->disp_thread)
1915 mdss_fb_stop_disp_thread(mfd);
1916 mutex_lock(&mfd->bl_lock);
Venkata Prahlad Valluru727b9a32020-03-13 17:28:45 +05301917 if (mfd->unset_bl_level != U32_MAX)
1918 current_bl = mfd->unset_bl_level;
1919 else
1920 current_bl = mfd->bl_level;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301921 mfd->allow_bl_update = true;
1922 mdss_fb_set_backlight(mfd, 0);
1923 mfd->allow_bl_update = false;
Krishna Manikandan695632e2020-03-04 20:50:28 +05301924 if (current_bl)
1925 mfd->unset_bl_level = current_bl;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301926 mutex_unlock(&mfd->bl_lock);
1927 }
1928 mfd->panel_power_state = req_power_state;
1929
1930 ret = mfd->mdp.off_fnc(mfd);
Animesh Kishore8b42bd92018-12-04 18:57:13 +05301931 if (ret) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301932 mfd->panel_power_state = cur_power_state;
Animesh Kishore8b42bd92018-12-04 18:57:13 +05301933 } else if (!mdss_panel_is_power_on_interactive(req_power_state)) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301934 mdss_fb_release_fences(mfd);
Animesh Kishore8b42bd92018-12-04 18:57:13 +05301935 if (mfd->panel.type == MIPI_CMD_PANEL)
1936 mdss_fb_signal_retire_fence(mfd);
1937 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301938 mfd->op_enable = true;
1939 complete(&mfd->power_off_comp);
1940
1941 return ret;
1942}
1943
1944static int mdss_fb_blank_unblank(struct msm_fb_data_type *mfd)
1945{
1946 int ret = 0;
1947 int cur_power_state;
1948
1949 if (!mfd)
1950 return -EINVAL;
1951
1952 if (mfd->panel_info->debugfs_info)
1953 mdss_panel_validate_debugfs_info(mfd);
1954
1955 /* Start Display thread */
1956 if (mfd->disp_thread == NULL) {
1957 ret = mdss_fb_start_disp_thread(mfd);
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05301958 if (IS_ERR_VALUE((unsigned long)ret))
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301959 return ret;
1960 }
1961
1962 cur_power_state = mfd->panel_power_state;
1963 pr_debug("Transitioning from %d --> %d\n", cur_power_state,
1964 MDSS_PANEL_POWER_ON);
1965
1966 if (mdss_panel_is_power_on_interactive(cur_power_state)) {
1967 pr_debug("No change in power state\n");
1968 return 0;
1969 }
1970
Krishna Manikandan695632e2020-03-04 20:50:28 +05301971 mfd->allow_secure_bl_update = false;
1972
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301973 if (mfd->mdp.on_fnc) {
1974 struct mdss_panel_info *panel_info = mfd->panel_info;
1975 struct fb_var_screeninfo *var = &mfd->fbi->var;
1976
1977 ret = mfd->mdp.on_fnc(mfd);
1978 if (ret) {
1979 mdss_fb_stop_disp_thread(mfd);
1980 goto error;
1981 }
1982
1983 mfd->panel_power_state = MDSS_PANEL_POWER_ON;
1984 mfd->panel_info->panel_dead = false;
1985 mutex_lock(&mfd->update.lock);
1986 mfd->update.type = NOTIFY_TYPE_UPDATE;
1987 mfd->update.is_suspend = 0;
1988 mutex_unlock(&mfd->update.lock);
1989
1990 /*
1991 * Panel info can change depending in the information
1992 * programmed in the controller.
1993 * Update this info in the upstream structs.
1994 */
1995 mdss_panelinfo_to_fb_var(panel_info, var);
1996
1997 /* Start the work thread to signal idle time */
1998 if (mfd->idle_time)
1999 schedule_delayed_work(&mfd->idle_notify_work,
2000 msecs_to_jiffies(mfd->idle_time));
2001 }
2002
2003 /* Reset the backlight only if the panel was off */
2004 if (mdss_panel_is_power_off(cur_power_state)) {
2005 mutex_lock(&mfd->bl_lock);
2006 if (!mfd->allow_bl_update) {
2007 mfd->allow_bl_update = true;
2008 /*
2009 * If in AD calibration mode then frameworks would not
2010 * be allowed to update backlight hence post unblank
2011 * the backlight would remain 0 (0 is set in blank).
2012 * Hence resetting back to calibration mode value
2013 */
2014 if (IS_CALIB_MODE_BL(mfd))
2015 mdss_fb_set_backlight(mfd, mfd->calib_mode_bl);
2016 else if ((!mfd->panel_info->mipi.post_init_delay) &&
2017 (mfd->unset_bl_level != U32_MAX))
2018 mdss_fb_set_backlight(mfd, mfd->unset_bl_level);
2019
2020 /*
2021 * it blocks the backlight update between unblank and
2022 * first kickoff to avoid backlight turn on before black
2023 * frame is transferred to panel through unblank call.
2024 */
2025 mfd->allow_bl_update = false;
2026 }
2027 mutex_unlock(&mfd->bl_lock);
2028 }
2029
2030error:
2031 return ret;
2032}
2033
2034static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
2035 int op_enable)
2036{
2037 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
2038 int ret = 0;
2039 int cur_power_state, req_power_state = MDSS_PANEL_POWER_OFF;
2040 char trace_buffer[32];
2041
2042 if (!mfd || !op_enable)
2043 return -EPERM;
2044
2045 if (mfd->dcm_state == DCM_ENTER)
2046 return -EPERM;
2047
2048 pr_debug("%pS mode:%d\n", __builtin_return_address(0),
2049 blank_mode);
2050
2051 snprintf(trace_buffer, sizeof(trace_buffer), "fb%d blank %d",
2052 mfd->index, blank_mode);
2053 ATRACE_BEGIN(trace_buffer);
2054
2055 cur_power_state = mfd->panel_power_state;
2056
2057 /*
2058 * Low power (lp) and ultra low power (ulp) modes are currently only
2059 * supported for command mode panels. For all other panel, treat lp
2060 * mode as full unblank and ulp mode as full blank.
2061 */
Abhijith Desai114ef492018-09-11 17:15:52 +05302062 if ((mfd->panel_info->type == SPI_PANEL) &&
2063 ((blank_mode == BLANK_FLAG_LP) ||
2064 (blank_mode == BLANK_FLAG_ULP))) {
2065 pr_debug("lp/ulp mode are not supported for SPI panels\n");
2066 if (mdss_fb_is_power_on_interactive(mfd))
2067 return 0;
2068 }
2069
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302070 if (mfd->panel_info->type != MIPI_CMD_PANEL) {
2071 if (blank_mode == BLANK_FLAG_LP) {
2072 pr_debug("lp mode only valid for cmd mode panels\n");
2073 if (mdss_fb_is_power_on_interactive(mfd))
2074 return 0;
2075 blank_mode = FB_BLANK_UNBLANK;
2076 } else if (blank_mode == BLANK_FLAG_ULP) {
2077 pr_debug("ulp mode valid for cmd mode panels\n");
2078 if (mdss_fb_is_power_off(mfd))
2079 return 0;
2080 blank_mode = FB_BLANK_POWERDOWN;
2081 }
2082 }
2083
2084 switch (blank_mode) {
2085 case FB_BLANK_UNBLANK:
2086 pr_debug("unblank called. cur pwr state=%d\n", cur_power_state);
2087 ret = mdss_fb_blank_unblank(mfd);
2088 break;
2089 case BLANK_FLAG_ULP:
2090 req_power_state = MDSS_PANEL_POWER_LP2;
2091 pr_debug("ultra low power mode requested\n");
2092 if (mdss_fb_is_power_off(mfd)) {
2093 pr_debug("Unsupp transition: off --> ulp\n");
2094 return 0;
2095 }
2096
2097 ret = mdss_fb_blank_blank(mfd, req_power_state);
2098 break;
2099 case BLANK_FLAG_LP:
2100 req_power_state = MDSS_PANEL_POWER_LP1;
2101 pr_debug(" power mode requested\n");
2102
2103 /*
2104 * If low power mode is requested when panel is already off,
2105 * then first unblank the panel before entering low power mode
2106 */
2107 if (mdss_fb_is_power_off(mfd) && mfd->mdp.on_fnc) {
2108 pr_debug("off --> lp. switch to on first\n");
2109 ret = mdss_fb_blank_unblank(mfd);
2110 if (ret)
2111 break;
2112 }
2113
2114 ret = mdss_fb_blank_blank(mfd, req_power_state);
2115 break;
2116 case FB_BLANK_HSYNC_SUSPEND:
2117 case FB_BLANK_POWERDOWN:
2118 default:
2119 req_power_state = MDSS_PANEL_POWER_OFF;
2120 pr_debug("blank powerdown called\n");
2121 ret = mdss_fb_blank_blank(mfd, req_power_state);
2122 break;
2123 }
2124
2125 /* Notify listeners */
2126 sysfs_notify(&mfd->fbi->dev->kobj, NULL, "show_blank_event");
2127
2128 ATRACE_END(trace_buffer);
2129
2130 return ret;
2131}
2132
2133static int mdss_fb_blank(int blank_mode, struct fb_info *info)
2134{
2135 int ret;
2136 struct mdss_panel_data *pdata;
2137 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
Abhijith Desai2956a0e12018-09-27 17:19:18 +05302138 ktime_t start, end;
2139 s64 actual_time;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302140
Abhijith Desai2956a0e12018-09-27 17:19:18 +05302141 start = ktime_get();
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302142 ret = mdss_fb_pan_idle(mfd);
2143 if (ret) {
2144 pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d\n",
2145 mfd->index, ret);
2146 return ret;
2147 }
2148 mutex_lock(&mfd->mdss_sysfs_lock);
2149 if (mfd->op_enable == 0) {
2150 if (blank_mode == FB_BLANK_UNBLANK)
2151 mfd->suspend.panel_power_state = MDSS_PANEL_POWER_ON;
2152 else if (blank_mode == BLANK_FLAG_ULP)
2153 mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP2;
2154 else if (blank_mode == BLANK_FLAG_LP)
2155 mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP1;
2156 else
2157 mfd->suspend.panel_power_state = MDSS_PANEL_POWER_OFF;
2158 ret = 0;
2159 goto end;
2160 }
2161 pr_debug("mode: %d\n", blank_mode);
2162
2163 pdata = dev_get_platdata(&mfd->pdev->dev);
2164
2165 if (pdata->panel_info.is_lpm_mode &&
2166 blank_mode == FB_BLANK_UNBLANK) {
2167 pr_debug("panel is in lpm mode\n");
2168 mfd->mdp.configure_panel(mfd, 0, 1);
2169 mdss_fb_set_mdp_sync_pt_threshold(mfd, mfd->panel.type);
2170 pdata->panel_info.is_lpm_mode = false;
2171 }
2172
2173 ret = mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
Abhijith Desai2956a0e12018-09-27 17:19:18 +05302174 end = ktime_get();
2175 actual_time = ktime_ms_delta(end, start);
2176
2177 MDSS_XLOG(blank_mode, actual_time);
2178 pr_debug("blank_mode: %d and transition time: %lldms\n",
2179 blank_mode, actual_time);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302180
2181end:
2182 mutex_unlock(&mfd->mdss_sysfs_lock);
2183 return ret;
2184}
2185
2186static inline int mdss_fb_create_ion_client(struct msm_fb_data_type *mfd)
2187{
2188 mfd->fb_ion_client = msm_ion_client_create("mdss_fb_iclient");
2189 if (IS_ERR_OR_NULL(mfd->fb_ion_client)) {
2190 pr_err("Err:client not created, val %d\n",
2191 PTR_RET(mfd->fb_ion_client));
2192 mfd->fb_ion_client = NULL;
2193 return PTR_RET(mfd->fb_ion_client);
2194 }
2195 return 0;
2196}
2197
2198void mdss_fb_free_fb_ion_memory(struct msm_fb_data_type *mfd)
2199{
2200 if (!mfd) {
2201 pr_err("no mfd\n");
2202 return;
2203 }
2204
2205 if (!mfd->fbi->screen_base)
2206 return;
2207
2208 if (!mfd->fb_ion_client || !mfd->fb_ion_handle) {
2209 pr_err("invalid input parameters for fb%d\n", mfd->index);
2210 return;
2211 }
2212
2213 mfd->fbi->screen_base = NULL;
2214 mfd->fbi->fix.smem_start = 0;
2215
2216 ion_unmap_kernel(mfd->fb_ion_client, mfd->fb_ion_handle);
2217
2218 if (mfd->mdp.fb_mem_get_iommu_domain && !(!mfd->fb_attachment ||
2219 !mfd->fb_attachment->dmabuf ||
2220 !mfd->fb_attachment->dmabuf->ops)) {
2221 dma_buf_unmap_attachment(mfd->fb_attachment, mfd->fb_table,
2222 DMA_BIDIRECTIONAL);
2223 dma_buf_detach(mfd->fbmem_buf, mfd->fb_attachment);
2224 dma_buf_put(mfd->fbmem_buf);
2225 }
2226
2227 ion_free(mfd->fb_ion_client, mfd->fb_ion_handle);
2228 mfd->fb_ion_handle = NULL;
2229 mfd->fbmem_buf = NULL;
2230}
2231
2232int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd, size_t fb_size)
2233{
2234 int rc = 0;
2235 void *vaddr;
2236 int domain;
2237
2238 if (!mfd) {
2239 pr_err("Invalid input param - no mfd\n");
2240 return -EINVAL;
2241 }
2242
2243 if (!mfd->fb_ion_client) {
2244 rc = mdss_fb_create_ion_client(mfd);
2245 if (rc < 0) {
2246 pr_err("fb ion client couldn't be created - %d\n", rc);
2247 return rc;
2248 }
2249 }
2250
2251 pr_debug("size for mmap = %zu\n", fb_size);
2252 mfd->fb_ion_handle = ion_alloc(mfd->fb_ion_client, fb_size, SZ_4K,
2253 ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
2254 if (IS_ERR_OR_NULL(mfd->fb_ion_handle)) {
2255 pr_err("unable to alloc fbmem from ion - %ld\n",
2256 PTR_ERR(mfd->fb_ion_handle));
2257 return PTR_ERR(mfd->fb_ion_handle);
2258 }
2259
2260 if (mfd->mdp.fb_mem_get_iommu_domain) {
2261 mfd->fbmem_buf = ion_share_dma_buf(mfd->fb_ion_client,
2262 mfd->fb_ion_handle);
2263 if (IS_ERR(mfd->fbmem_buf)) {
2264 rc = PTR_ERR(mfd->fbmem_buf);
2265 goto fb_mmap_failed;
2266 }
2267
2268 domain = mfd->mdp.fb_mem_get_iommu_domain();
2269
2270 mfd->fb_attachment = mdss_smmu_dma_buf_attach(mfd->fbmem_buf,
2271 &mfd->pdev->dev, domain);
2272 if (IS_ERR(mfd->fb_attachment)) {
2273 rc = PTR_ERR(mfd->fb_attachment);
2274 goto err_put;
2275 }
2276
2277 mfd->fb_table = dma_buf_map_attachment(mfd->fb_attachment,
2278 DMA_BIDIRECTIONAL);
2279 if (IS_ERR(mfd->fb_table)) {
2280 rc = PTR_ERR(mfd->fb_table);
2281 goto err_detach;
2282 }
2283 } else {
2284 pr_err("No IOMMU Domain\n");
2285 rc = -EINVAL;
2286 goto fb_mmap_failed;
2287 }
2288
2289 vaddr = ion_map_kernel(mfd->fb_ion_client, mfd->fb_ion_handle);
2290 if (IS_ERR_OR_NULL(vaddr)) {
2291 pr_err("ION memory mapping failed - %ld\n", PTR_ERR(vaddr));
2292 rc = PTR_ERR(vaddr);
2293 goto err_unmap;
2294 }
2295 pr_debug("alloc 0x%zxB vaddr = %pK for fb%d\n", fb_size,
2296 vaddr, mfd->index);
2297
2298 mfd->fbi->screen_base = (char *) vaddr;
2299 mfd->fbi->fix.smem_len = fb_size;
2300
2301 return rc;
2302
2303err_unmap:
2304 dma_buf_unmap_attachment(mfd->fb_attachment, mfd->fb_table,
2305 DMA_BIDIRECTIONAL);
2306err_detach:
2307 dma_buf_detach(mfd->fbmem_buf, mfd->fb_attachment);
2308err_put:
2309 dma_buf_put(mfd->fbmem_buf);
2310fb_mmap_failed:
2311 ion_free(mfd->fb_ion_client, mfd->fb_ion_handle);
2312 mfd->fb_attachment = NULL;
2313 mfd->fb_table = NULL;
2314 mfd->fb_ion_handle = NULL;
2315 mfd->fbmem_buf = NULL;
2316 return rc;
2317}
2318
2319/**
2320 * mdss_fb_fbmem_ion_mmap() - Custom fb mmap() function for MSM driver.
2321 *
2322 * @info - Framebuffer info.
2323 * @vma - VM area which is part of the process virtual memory.
2324 *
2325 * This framebuffer mmap function differs from standard mmap() function by
2326 * allowing for customized page-protection and dynamically allocate framebuffer
2327 * memory from system heap and map to iommu virtual address.
2328 *
2329 * Return: virtual address is returned through vma
2330 */
2331static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
2332 struct vm_area_struct *vma)
2333{
2334 int rc = 0;
2335 size_t req_size, fb_size;
2336 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
2337 struct sg_table *table;
2338 unsigned long addr = vma->vm_start;
2339 unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
2340 struct scatterlist *sg;
2341 unsigned int i;
2342 struct page *page;
2343
2344 if (!mfd || !mfd->pdev || !mfd->pdev->dev.of_node) {
2345 pr_err("Invalid device node\n");
2346 return -ENODEV;
2347 }
2348
2349 req_size = vma->vm_end - vma->vm_start;
2350 fb_size = mfd->fbi->fix.smem_len;
2351 if (req_size > fb_size) {
2352 pr_warn("requested map is greater than framebuffer\n");
2353 return -EOVERFLOW;
2354 }
2355
2356 if (!mfd->fbi->screen_base) {
2357 rc = mdss_fb_alloc_fb_ion_memory(mfd, fb_size);
2358 if (rc < 0) {
2359 pr_err("fb mmap failed!!!!\n");
2360 return rc;
2361 }
2362 }
2363
2364 table = mfd->fb_table;
2365 if (IS_ERR(table)) {
2366 pr_err("Unable to get sg_table from ion:%ld\n", PTR_ERR(table));
2367 mfd->fbi->screen_base = NULL;
2368 return PTR_ERR(table);
2369 } else if (!table) {
2370 pr_err("sg_list is NULL\n");
2371 mfd->fbi->screen_base = NULL;
2372 return -EINVAL;
2373 }
2374
2375 page = sg_page(table->sgl);
2376 if (page) {
2377 for_each_sg(table->sgl, sg, table->nents, i) {
2378 unsigned long remainder = vma->vm_end - addr;
2379 unsigned long len = sg->length;
2380
2381 page = sg_page(sg);
2382
2383 if (offset >= sg->length) {
2384 offset -= sg->length;
2385 continue;
2386 } else if (offset) {
2387 page += offset / PAGE_SIZE;
2388 len = sg->length - offset;
2389 offset = 0;
2390 }
2391 len = min(len, remainder);
2392
2393 if (mfd->mdp_fb_page_protection ==
2394 MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
2395 vma->vm_page_prot =
2396 pgprot_writecombine(vma->vm_page_prot);
2397
2398 pr_debug("vma=%pK, addr=%x len=%ld\n",
2399 vma, (unsigned int)addr, len);
2400 pr_debug("vm_start=%x vm_end=%x vm_page_prot=%ld\n",
Sachin Bhayareb6b5a0f2018-03-02 19:50:39 +05302401 (unsigned int)vma->vm_start,
2402 (unsigned int)vma->vm_end,
2403 (unsigned long int)pgprot_val(
2404 vma->vm_page_prot));
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302405
2406 io_remap_pfn_range(vma, addr, page_to_pfn(page), len,
2407 vma->vm_page_prot);
2408 addr += len;
2409 if (addr >= vma->vm_end)
2410 break;
2411 }
2412 } else {
2413 pr_err("PAGE is null\n");
2414 mdss_fb_free_fb_ion_memory(mfd);
2415 return -ENOMEM;
2416 }
2417
2418 return rc;
2419}
2420
2421/*
2422 * mdss_fb_physical_mmap() - Custom fb mmap() function for MSM driver.
2423 *
2424 * @info - Framebuffer info.
2425 * @vma - VM area which is part of the process virtual memory.
2426 *
2427 * This framebuffer mmap function differs from standard mmap() function as
2428 * map to framebuffer memory from the CMA memory which is allocated during
2429 * bootup.
2430 *
2431 * Return: virtual address is returned through vma
2432 */
2433static int mdss_fb_physical_mmap(struct fb_info *info,
2434 struct vm_area_struct *vma)
2435{
2436 /* Get frame buffer memory range. */
2437 unsigned long start = info->fix.smem_start;
2438 u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
2439 unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
2440 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
2441
2442 if (!start) {
2443 pr_warn("No framebuffer memory is allocated\n");
2444 return -ENOMEM;
2445 }
2446
2447 /* Set VM flags. */
2448 start &= PAGE_MASK;
2449 if ((vma->vm_end <= vma->vm_start) ||
2450 (off >= len) ||
2451 ((vma->vm_end - vma->vm_start) > (len - off)))
2452 return -EINVAL;
2453 off += start;
2454 if (off < start)
2455 return -EINVAL;
2456 vma->vm_pgoff = off >> PAGE_SHIFT;
2457 /* This is an IO map - tell maydump to skip this VMA */
2458 vma->vm_flags |= VM_IO;
2459
2460 if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
2461 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
2462
2463 /* Remap the frame buffer I/O range */
2464 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
2465 vma->vm_end - vma->vm_start,
2466 vma->vm_page_prot))
2467 return -EAGAIN;
2468
2469 return 0;
2470}
2471
2472static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
2473{
2474 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
2475 int rc = -EINVAL;
2476
2477 if (mfd->fb_mmap_type == MDP_FB_MMAP_ION_ALLOC) {
2478 rc = mdss_fb_fbmem_ion_mmap(info, vma);
2479 } else if (mfd->fb_mmap_type == MDP_FB_MMAP_PHYSICAL_ALLOC) {
2480 rc = mdss_fb_physical_mmap(info, vma);
2481 } else {
2482 if (!info->fix.smem_start && !mfd->fb_ion_handle) {
2483 rc = mdss_fb_fbmem_ion_mmap(info, vma);
2484 mfd->fb_mmap_type = MDP_FB_MMAP_ION_ALLOC;
2485 } else {
2486 rc = mdss_fb_physical_mmap(info, vma);
2487 mfd->fb_mmap_type = MDP_FB_MMAP_PHYSICAL_ALLOC;
2488 }
2489 }
2490 if (rc < 0)
2491 pr_err("fb mmap failed with rc = %d\n", rc);
2492
2493 return rc;
2494}
2495
2496static struct fb_ops mdss_fb_ops = {
2497 .owner = THIS_MODULE,
2498 .fb_open = mdss_fb_open,
2499 .fb_release = mdss_fb_release,
2500 .fb_check_var = mdss_fb_check_var, /* vinfo check */
2501 .fb_set_par = mdss_fb_set_par, /* set the video mode */
2502 .fb_blank = mdss_fb_blank, /* blank display */
2503 .fb_pan_display = mdss_fb_pan_display, /* pan display */
2504 .fb_ioctl_v2 = mdss_fb_ioctl, /* perform fb specific ioctl */
2505#ifdef CONFIG_COMPAT
2506 .fb_compat_ioctl_v2 = mdss_fb_compat_ioctl,
2507#endif
2508 .fb_mmap = mdss_fb_mmap,
2509};
2510
2511static int mdss_fb_alloc_fbmem_iommu(struct msm_fb_data_type *mfd, int dom)
2512{
2513 void *virt = NULL;
2514 phys_addr_t phys = 0;
2515 size_t size = 0;
2516 struct platform_device *pdev = mfd->pdev;
2517 int rc = 0;
2518 struct device_node *fbmem_pnode = NULL;
2519
2520 if (!pdev || !pdev->dev.of_node) {
2521 pr_err("Invalid device node\n");
2522 return -ENODEV;
2523 }
2524
2525 fbmem_pnode = of_parse_phandle(pdev->dev.of_node,
2526 "linux,contiguous-region", 0);
2527 if (!fbmem_pnode) {
2528 pr_debug("fbmem is not reserved for %s\n", pdev->name);
2529 mfd->fbi->screen_base = NULL;
2530 mfd->fbi->fix.smem_start = 0;
2531 return 0;
2532 }
2533 {
2534 const u32 *addr;
2535 u64 len;
2536
2537 addr = of_get_address(fbmem_pnode, 0, &len, NULL);
2538 if (!addr) {
2539 pr_err("fbmem size is not specified\n");
2540 of_node_put(fbmem_pnode);
2541 return -EINVAL;
2542 }
2543 size = (size_t)len;
2544 of_node_put(fbmem_pnode);
2545 }
2546
2547 pr_debug("%s frame buffer reserve_size=0x%zx\n", __func__, size);
2548
2549 if (size < PAGE_ALIGN(mfd->fbi->fix.line_length *
2550 mfd->fbi->var.yres_virtual))
2551 pr_warn("reserve size is smaller than framebuffer size\n");
2552
2553 rc = mdss_smmu_dma_alloc_coherent(&pdev->dev, size, &phys, &mfd->iova,
2554 &virt, GFP_KERNEL, dom);
2555 if (rc) {
2556 pr_err("unable to alloc fbmem size=%zx\n", size);
2557 return -ENOMEM;
2558 }
2559
2560 if (MDSS_LPAE_CHECK(phys)) {
2561 pr_warn("fb mem phys %pa > 4GB is not supported.\n", &phys);
2562 mdss_smmu_dma_free_coherent(&pdev->dev, size, &virt,
2563 phys, mfd->iova, dom);
2564 return -ERANGE;
2565 }
2566
2567 pr_debug("alloc 0x%zxB @ (%pa phys) (0x%pK virt) (%pa iova) for fb%d\n",
2568 size, &phys, virt, &mfd->iova, mfd->index);
2569
2570 mfd->fbi->screen_base = virt;
2571 mfd->fbi->fix.smem_start = phys;
2572 mfd->fbi->fix.smem_len = size;
2573
2574 return 0;
2575}
2576
2577static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
2578{
2579
2580 if (mfd->mdp.fb_mem_alloc_fnc) {
2581 return mfd->mdp.fb_mem_alloc_fnc(mfd);
2582 } else if (mfd->mdp.fb_mem_get_iommu_domain) {
2583 int dom = mfd->mdp.fb_mem_get_iommu_domain();
2584
2585 if (dom >= 0)
2586 return mdss_fb_alloc_fbmem_iommu(mfd, dom);
2587 else
2588 return -ENOMEM;
2589 } else {
2590 pr_err("no fb memory allocator function defined\n");
2591 return -ENOMEM;
2592 }
2593}
2594
2595static int mdss_fb_register(struct msm_fb_data_type *mfd)
2596{
2597 int ret = -ENODEV;
2598 int bpp;
2599 char panel_name[20];
2600 struct mdss_panel_info *panel_info = mfd->panel_info;
2601 struct fb_info *fbi = mfd->fbi;
2602 struct fb_fix_screeninfo *fix;
2603 struct fb_var_screeninfo *var;
2604 int *id;
2605
2606 /*
2607 * fb info initialization
2608 */
2609 fix = &fbi->fix;
2610 var = &fbi->var;
2611
2612 fix->type_aux = 0; /* if type == FB_TYPE_INTERLEAVED_PLANES */
2613 fix->visual = FB_VISUAL_TRUECOLOR; /* True Color */
2614 fix->ywrapstep = 0; /* No support */
2615 fix->mmio_start = 0; /* No MMIO Address */
2616 fix->mmio_len = 0; /* No MMIO Address */
2617 fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */
2618
2619 var->xoffset = 0, /* Offset from virtual to visible */
2620 var->yoffset = 0, /* resolution */
2621 var->grayscale = 0, /* No graylevels */
2622 var->nonstd = 0, /* standard pixel format */
2623 var->activate = FB_ACTIVATE_VBL, /* activate it at vsync */
2624 var->height = -1, /* height of picture in mm */
2625 var->width = -1, /* width of picture in mm */
2626 var->accel_flags = 0, /* acceleration flags */
2627 var->sync = 0, /* see FB_SYNC_* */
2628 var->rotate = 0, /* angle we rotate counter clockwise */
2629 mfd->op_enable = false;
2630
2631 switch (mfd->fb_imgType) {
2632 case MDP_RGB_565:
2633 fix->type = FB_TYPE_PACKED_PIXELS;
2634 fix->xpanstep = 1;
2635 fix->ypanstep = 1;
2636 var->vmode = FB_VMODE_NONINTERLACED;
2637 var->blue.offset = 0;
2638 var->green.offset = 5;
2639 var->red.offset = 11;
2640 var->blue.length = 5;
2641 var->green.length = 6;
2642 var->red.length = 5;
2643 var->blue.msb_right = 0;
2644 var->green.msb_right = 0;
2645 var->red.msb_right = 0;
2646 var->transp.offset = 0;
2647 var->transp.length = 0;
2648 bpp = 2;
2649 break;
2650
2651 case MDP_RGB_888:
2652 fix->type = FB_TYPE_PACKED_PIXELS;
2653 fix->xpanstep = 1;
2654 fix->ypanstep = 1;
2655 var->vmode = FB_VMODE_NONINTERLACED;
2656 var->blue.offset = 0;
2657 var->green.offset = 8;
2658 var->red.offset = 16;
2659 var->blue.length = 8;
2660 var->green.length = 8;
2661 var->red.length = 8;
2662 var->blue.msb_right = 0;
2663 var->green.msb_right = 0;
2664 var->red.msb_right = 0;
2665 var->transp.offset = 0;
2666 var->transp.length = 0;
2667 bpp = 3;
2668 break;
2669
2670 case MDP_ARGB_8888:
2671 fix->type = FB_TYPE_PACKED_PIXELS;
2672 fix->xpanstep = 1;
2673 fix->ypanstep = 1;
2674 var->vmode = FB_VMODE_NONINTERLACED;
2675 var->blue.offset = 24;
2676 var->green.offset = 16;
2677 var->red.offset = 8;
2678 var->blue.length = 8;
2679 var->green.length = 8;
2680 var->red.length = 8;
2681 var->blue.msb_right = 0;
2682 var->green.msb_right = 0;
2683 var->red.msb_right = 0;
2684 var->transp.offset = 0;
2685 var->transp.length = 8;
2686 bpp = 4;
2687 break;
2688
2689 case MDP_RGBA_8888:
2690 fix->type = FB_TYPE_PACKED_PIXELS;
2691 fix->xpanstep = 1;
2692 fix->ypanstep = 1;
2693 var->vmode = FB_VMODE_NONINTERLACED;
2694 var->blue.offset = 16;
2695 var->green.offset = 8;
2696 var->red.offset = 0;
2697 var->blue.length = 8;
2698 var->green.length = 8;
2699 var->red.length = 8;
2700 var->blue.msb_right = 0;
2701 var->green.msb_right = 0;
2702 var->red.msb_right = 0;
2703 var->transp.offset = 24;
2704 var->transp.length = 8;
2705 bpp = 4;
2706 break;
2707
2708 case MDP_YCRYCB_H2V1:
2709 fix->type = FB_TYPE_INTERLEAVED_PLANES;
2710 fix->xpanstep = 2;
2711 fix->ypanstep = 1;
2712 var->vmode = FB_VMODE_NONINTERLACED;
2713
2714 /* how about R/G/B offset? */
2715 var->blue.offset = 0;
2716 var->green.offset = 5;
2717 var->red.offset = 11;
2718 var->blue.length = 5;
2719 var->green.length = 6;
2720 var->red.length = 5;
2721 var->blue.msb_right = 0;
2722 var->green.msb_right = 0;
2723 var->red.msb_right = 0;
2724 var->transp.offset = 0;
2725 var->transp.length = 0;
2726 bpp = 2;
2727 break;
2728
2729 default:
2730 pr_err("msm_fb_init: fb %d unknown image type!\n",
2731 mfd->index);
2732 return ret;
2733 }
2734
2735 mdss_panelinfo_to_fb_var(panel_info, var);
2736
2737 fix->type = panel_info->is_3d_panel;
2738 if (mfd->mdp.fb_stride)
2739 fix->line_length = mfd->mdp.fb_stride(mfd->index, var->xres,
2740 bpp);
2741 else
2742 fix->line_length = var->xres * bpp;
2743
2744 var->xres_virtual = var->xres;
2745 var->yres_virtual = panel_info->yres * mfd->fb_page;
2746 var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */
2747
2748 /*
2749 * Populate smem length here for uspace to get the
2750 * Framebuffer size when FBIO_FSCREENINFO ioctl is called.
2751 */
2752 fix->smem_len = PAGE_ALIGN(fix->line_length * var->yres) * mfd->fb_page;
2753
2754 /* id field for fb app */
2755 id = (int *)&mfd->panel;
2756
2757 snprintf(fix->id, sizeof(fix->id), "mdssfb_%x", (u32) *id);
2758
2759 fbi->fbops = &mdss_fb_ops;
2760 fbi->flags = FBINFO_FLAG_DEFAULT;
2761 fbi->pseudo_palette = mdss_fb_pseudo_palette;
2762
2763 mfd->ref_cnt = 0;
2764 mfd->panel_power_state = MDSS_PANEL_POWER_OFF;
2765 mfd->dcm_state = DCM_UNINIT;
2766
2767 if (mdss_fb_alloc_fbmem(mfd))
2768 pr_warn("unable to allocate fb memory in fb register\n");
2769
2770 mfd->op_enable = true;
2771
2772 mutex_init(&mfd->update.lock);
2773 mutex_init(&mfd->no_update.lock);
2774 mutex_init(&mfd->mdp_sync_pt_data.sync_mutex);
2775 atomic_set(&mfd->mdp_sync_pt_data.commit_cnt, 0);
2776 atomic_set(&mfd->commits_pending, 0);
2777 atomic_set(&mfd->ioctl_ref_cnt, 0);
2778 atomic_set(&mfd->kickoff_pending, 0);
2779
2780 init_timer(&mfd->no_update.timer);
2781 mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
2782 mfd->no_update.timer.data = (unsigned long)mfd;
2783 mfd->update.ref_count = 0;
2784 mfd->no_update.ref_count = 0;
2785 mfd->update.init_done = false;
2786 init_completion(&mfd->update.comp);
2787 init_completion(&mfd->no_update.comp);
2788 init_completion(&mfd->power_off_comp);
2789 init_completion(&mfd->power_set_comp);
2790 init_waitqueue_head(&mfd->commit_wait_q);
2791 init_waitqueue_head(&mfd->idle_wait_q);
2792 init_waitqueue_head(&mfd->ioctl_q);
2793 init_waitqueue_head(&mfd->kickoff_wait_q);
2794
2795 ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
2796 if (ret)
2797 pr_err("fb_alloc_cmap() failed!\n");
2798
2799 if (register_framebuffer(fbi) < 0) {
2800 fb_dealloc_cmap(&fbi->cmap);
2801
2802 mfd->op_enable = false;
2803 return -EPERM;
2804 }
2805
2806 snprintf(panel_name, ARRAY_SIZE(panel_name), "mdss_panel_fb%d",
2807 mfd->index);
2808 mdss_panel_debugfs_init(panel_info, panel_name);
2809 pr_info("FrameBuffer[%d] %dx%d registered successfully!\n", mfd->index,
2810 fbi->var.xres, fbi->var.yres);
2811
2812 return 0;
2813}
2814
2815static int mdss_fb_open(struct fb_info *info, int user)
2816{
2817 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
2818 struct mdss_fb_file_info *file_info = NULL;
2819 int result;
2820 struct task_struct *task = current->group_leader;
2821
2822 if (mfd->shutdown_pending) {
2823 pr_err_once("Shutdown pending. Aborting operation. Request from pid:%d name=%s\n",
2824 current->tgid, task->comm);
2825 sysfs_notify(&mfd->fbi->dev->kobj, NULL, "show_blank_event");
2826 return -ESHUTDOWN;
2827 }
2828
2829 file_info = kmalloc(sizeof(*file_info), GFP_KERNEL);
2830 if (!file_info)
2831 return -ENOMEM;
2832
2833 file_info->file = info->file;
2834 list_add(&file_info->list, &mfd->file_list);
2835
2836 result = pm_runtime_get_sync(info->dev);
2837
2838 if (result < 0) {
2839 pr_err("pm_runtime: fail to wake up\n");
2840 goto pm_error;
2841 }
2842
2843 if (!mfd->ref_cnt) {
2844 result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
2845 mfd->op_enable);
2846 if (result) {
2847 pr_err("can't turn on fb%d! rc=%d\n", mfd->index,
2848 result);
2849 goto blank_error;
2850 }
2851 }
2852
2853 mfd->ref_cnt++;
2854 pr_debug("mfd refcount:%d file:%pK\n", mfd->ref_cnt, info->file);
2855
2856 return 0;
2857
2858blank_error:
2859 pm_runtime_put(info->dev);
2860pm_error:
2861 list_del(&file_info->list);
2862 kfree(file_info);
2863 return result;
2864}
2865
2866static int mdss_fb_release_all(struct fb_info *info, bool release_all)
2867{
2868 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
2869 struct mdss_fb_file_info *file_info = NULL, *temp_file_info = NULL;
2870 struct file *file = info->file;
2871 int ret = 0;
2872 bool node_found = false;
2873 struct task_struct *task = current->group_leader;
2874
2875 if (!mfd->ref_cnt) {
2876 pr_info("try to close unopened fb %d! from pid:%d name:%s\n",
2877 mfd->index, current->tgid, task->comm);
2878 return -EINVAL;
2879 }
2880
2881 if (!wait_event_timeout(mfd->ioctl_q,
2882 !atomic_read(&mfd->ioctl_ref_cnt) || !release_all,
2883 msecs_to_jiffies(1000)))
2884 pr_warn("fb%d ioctl could not finish. waited 1 sec.\n",
2885 mfd->index);
2886
2887 /* wait only for the last release */
2888 if (release_all || (mfd->ref_cnt == 1)) {
2889 ret = mdss_fb_pan_idle(mfd);
2890 if (ret && (ret != -ESHUTDOWN))
2891 pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d ignoring.\n",
2892 mfd->index, ret);
2893 }
2894
2895 pr_debug("release_all = %s\n", release_all ? "true" : "false");
2896
2897 list_for_each_entry_safe(file_info, temp_file_info, &mfd->file_list,
2898 list) {
2899 if (!release_all && file_info->file != file)
2900 continue;
2901
2902 pr_debug("found file node mfd->ref=%d\n", mfd->ref_cnt);
2903 list_del(&file_info->list);
2904 kfree(file_info);
2905
2906 mfd->ref_cnt--;
2907 pm_runtime_put(info->dev);
2908
2909 node_found = true;
2910
2911 if (!release_all)
2912 break;
2913 }
2914
2915 if (!node_found || (release_all && mfd->ref_cnt))
2916 pr_warn("file node not found or wrong ref cnt: release all:%d refcnt:%d\n",
2917 release_all, mfd->ref_cnt);
2918
2919 pr_debug("current process=%s pid=%d mfd->ref=%d file:%pK\n",
2920 task->comm, current->tgid, mfd->ref_cnt, info->file);
2921
2922 if (!mfd->ref_cnt || release_all) {
2923 /* resources (if any) will be released during blank */
2924 if (mfd->mdp.release_fnc)
2925 mfd->mdp.release_fnc(mfd, NULL);
2926
2927 if (mfd->mdp.pp_release_fnc) {
2928 ret = (*mfd->mdp.pp_release_fnc)(mfd);
2929 if (ret)
2930 pr_err("PP release failed ret %d\n", ret);
2931 }
2932
2933 /* reset backlight before blank to prevent backlight from
2934 * enabling ahead of unblank. for some special cases like
2935 * adb shell stop/start.
2936 */
Abhijit Kulkarni0abd5fc2016-10-07 11:01:44 -07002937 mutex_lock(&mfd->bl_lock);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302938 mdss_fb_set_backlight(mfd, 0);
Abhijit Kulkarni0abd5fc2016-10-07 11:01:44 -07002939 mutex_unlock(&mfd->bl_lock);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302940
2941 ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
2942 mfd->op_enable);
2943 if (ret) {
2944 pr_err("can't turn off fb%d! rc=%d current process=%s pid=%d\n",
2945 mfd->index, ret, task->comm, current->tgid);
2946 return ret;
2947 }
2948 if (mfd->fb_ion_handle)
2949 mdss_fb_free_fb_ion_memory(mfd);
2950
2951 atomic_set(&mfd->ioctl_ref_cnt, 0);
2952 } else {
2953 if (mfd->mdp.release_fnc)
2954 ret = mfd->mdp.release_fnc(mfd, file);
2955
2956 /* display commit is needed to release resources */
2957 if (ret)
2958 mdss_fb_pan_display(&mfd->fbi->var, mfd->fbi);
2959 }
2960
2961 return ret;
2962}
2963
2964static int mdss_fb_release(struct fb_info *info, int user)
2965{
2966 return mdss_fb_release_all(info, false);
2967}
2968
2969static void mdss_fb_power_setting_idle(struct msm_fb_data_type *mfd)
2970{
2971 int ret;
2972
2973 if (mfd->is_power_setting) {
2974 ret = wait_for_completion_timeout(
2975 &mfd->power_set_comp,
2976 msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT));
2977 if (ret < 0)
2978 ret = -ERESTARTSYS;
2979 else if (!ret)
2980 pr_err("%s wait for power_set_comp timeout %d %d",
2981 __func__, ret, mfd->is_power_setting);
2982 if (ret <= 0) {
2983 mfd->is_power_setting = false;
2984 complete_all(&mfd->power_set_comp);
2985 }
2986 }
2987}
2988
2989static void __mdss_fb_copy_fence(struct msm_sync_pt_data *sync_pt_data,
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05302990 struct mdss_fence **fences, u32 *fence_cnt)
Sachin Bhayareeeb88892018-01-02 16:36:01 +05302991{
2992 pr_debug("%s: wait for fences\n", sync_pt_data->fence_name);
2993
2994 mutex_lock(&sync_pt_data->sync_mutex);
2995 /*
2996 * Assuming that acq_fen_cnt is sanitized in bufsync ioctl
2997 * to check for sync_pt_data->acq_fen_cnt <= MDP_MAX_FENCE_FD
2998 */
2999 *fence_cnt = sync_pt_data->acq_fen_cnt;
3000 sync_pt_data->acq_fen_cnt = 0;
3001 if (*fence_cnt)
3002 memcpy(fences, sync_pt_data->acq_fen,
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05303003 *fence_cnt * sizeof(struct mdss_fence *));
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303004 mutex_unlock(&sync_pt_data->sync_mutex);
3005}
3006
3007static int __mdss_fb_wait_for_fence_sub(struct msm_sync_pt_data *sync_pt_data,
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05303008 struct mdss_fence **fences, int fence_cnt)
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303009{
3010 int i, ret = 0;
3011 unsigned long max_wait = msecs_to_jiffies(WAIT_MAX_FENCE_TIMEOUT);
3012 unsigned long timeout = jiffies + max_wait;
3013 long wait_ms, wait_jf;
3014
3015 /* buf sync */
3016 for (i = 0; i < fence_cnt && !ret; i++) {
3017 wait_jf = timeout - jiffies;
3018 wait_ms = jiffies_to_msecs(wait_jf);
3019
3020 /*
3021 * In this loop, if one of the previous fence took long
3022 * time, give a chance for the next fence to check if
3023 * fence is already signalled. If not signalled it breaks
3024 * in the final wait timeout.
3025 */
3026 if (wait_jf < 0)
3027 wait_ms = WAIT_MIN_FENCE_TIMEOUT;
3028 else
3029 wait_ms = min_t(long, WAIT_FENCE_FIRST_TIMEOUT,
3030 wait_ms);
3031
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05303032 ret = mdss_wait_sync_fence(fences[i], wait_ms);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303033
Animesh Kishore45943bc2018-11-26 17:33:12 +05303034 if (ret == -ETIMEDOUT) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303035 wait_jf = timeout - jiffies;
3036 wait_ms = jiffies_to_msecs(wait_jf);
3037 if (wait_jf < 0)
3038 break;
3039
3040 wait_ms = min_t(long, WAIT_FENCE_FINAL_TIMEOUT,
3041 wait_ms);
3042
3043 pr_warn("%s: sync_fence_wait timed out! ",
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05303044 mdss_get_sync_fence_name(fences[i]));
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303045 pr_cont("Waiting %ld.%ld more seconds\n",
3046 (wait_ms/MSEC_PER_SEC), (wait_ms%MSEC_PER_SEC));
3047 MDSS_XLOG(sync_pt_data->timeline_value);
3048 MDSS_XLOG_TOUT_HANDLER("mdp");
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05303049 ret = mdss_wait_sync_fence(fences[i], wait_ms);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303050
Animesh Kishore45943bc2018-11-26 17:33:12 +05303051 if (ret == -ETIMEDOUT)
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303052 break;
3053 }
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05303054 mdss_put_sync_fence(fences[i]);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303055 }
3056
3057 if (ret < 0) {
Animesh Kishore45943bc2018-11-26 17:33:12 +05303058 pr_err("%s: sync_fence_wait failed! ret = %d\n",
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303059 sync_pt_data->fence_name, ret);
3060 for (; i < fence_cnt; i++)
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05303061 mdss_put_sync_fence(fences[i]);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303062 }
3063 return ret;
3064}
3065
3066int mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data)
3067{
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05303068 struct mdss_fence *fences[MDP_MAX_FENCE_FD];
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303069 int fence_cnt = 0;
3070
3071 __mdss_fb_copy_fence(sync_pt_data, fences, &fence_cnt);
3072
3073 if (fence_cnt)
3074 __mdss_fb_wait_for_fence_sub(sync_pt_data,
3075 fences, fence_cnt);
3076
3077 return fence_cnt;
3078}
3079
3080/**
3081 * mdss_fb_signal_timeline() - signal a single release fence
3082 * @sync_pt_data: Sync point data structure for the timeline which
3083 * should be signaled.
3084 *
3085 * This is called after a frame has been pushed to display. This signals the
3086 * timeline to release the fences associated with this frame.
3087 */
3088void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data)
3089{
Krishna Manikandanb296a2b2018-03-21 17:16:31 +05303090 struct msm_fb_data_type *mfd;
3091
3092 mfd = container_of(sync_pt_data, typeof(*mfd), mdp_sync_pt_data);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303093 mutex_lock(&sync_pt_data->sync_mutex);
Krishna Manikandanb296a2b2018-03-21 17:16:31 +05303094 if (atomic_read(&sync_pt_data->commit_cnt) &&
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303095 sync_pt_data->timeline) {
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05303096 mdss_inc_timeline(sync_pt_data->timeline, 1);
Krishna Manikandanb296a2b2018-03-21 17:16:31 +05303097
3098 /*
3099 * For Command mode panels, the retire timeline is incremented
3100 * whenever we receive a readptr_done. For all other panels,
3101 * the retire fence should be signaled along with the release
3102 * fence once the frame is done.
3103 */
3104 if (mfd->panel.type != MIPI_CMD_PANEL)
3105 mdss_inc_timeline(sync_pt_data->timeline_retire, 1);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303106 MDSS_XLOG(sync_pt_data->timeline_value);
3107 sync_pt_data->timeline_value++;
3108
Krishna Manikandanb296a2b2018-03-21 17:16:31 +05303109 pr_debug("%s: buffer signaled! timeline val=%d commit_cnt=%d\n",
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303110 sync_pt_data->fence_name, sync_pt_data->timeline_value,
3111 atomic_read(&sync_pt_data->commit_cnt));
3112 } else {
3113 pr_debug("%s timeline signaled without commits val=%d\n",
3114 sync_pt_data->fence_name, sync_pt_data->timeline_value);
3115 }
3116 mutex_unlock(&sync_pt_data->sync_mutex);
3117}
3118
3119/**
3120 * mdss_fb_release_fences() - signal all pending release fences
3121 * @mfd: Framebuffer data structure for display
3122 *
3123 * Release all currently pending release fences, including those that are in
3124 * the process to be commtted.
3125 *
3126 * Note: this should only be called during close or suspend sequence.
3127 */
3128static void mdss_fb_release_fences(struct msm_fb_data_type *mfd)
3129{
3130 struct msm_sync_pt_data *sync_pt_data = &mfd->mdp_sync_pt_data;
3131 int val;
3132
3133 mutex_lock(&sync_pt_data->sync_mutex);
3134 if (sync_pt_data->timeline) {
3135 val = sync_pt_data->threshold +
3136 atomic_read(&sync_pt_data->commit_cnt);
Sachin Bhayare9b5caf22018-02-20 22:05:47 +05303137 mdss_resync_timeline(sync_pt_data->timeline);
Krishna Manikandanb296a2b2018-03-21 17:16:31 +05303138 if (mfd->panel.type != MIPI_CMD_PANEL)
3139 mdss_resync_timeline(sync_pt_data->timeline_retire);
3140 sync_pt_data->timeline_value = val;
3141
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303142 }
3143 mutex_unlock(&sync_pt_data->sync_mutex);
3144}
3145
3146static void mdss_fb_release_kickoff(struct msm_fb_data_type *mfd)
3147{
3148 if (mfd->wait_for_kickoff) {
3149 atomic_set(&mfd->kickoff_pending, 0);
3150 wake_up_all(&mfd->kickoff_wait_q);
3151 }
3152}
3153
3154/**
3155 * __mdss_fb_sync_buf_done_callback() - process async display events
3156 * @p: Notifier block registered for async events.
3157 * @event: Event enum to identify the event.
3158 * @data: Optional argument provided with the event.
3159 *
3160 * See enum mdp_notify_event for events handled.
3161 */
3162static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
3163 unsigned long event, void *data)
3164{
3165 struct msm_sync_pt_data *sync_pt_data;
3166 struct msm_fb_data_type *mfd;
3167 int fence_cnt;
3168 int ret = NOTIFY_OK;
3169
3170 sync_pt_data = container_of(p, struct msm_sync_pt_data, notifier);
3171 mfd = container_of(sync_pt_data, struct msm_fb_data_type,
3172 mdp_sync_pt_data);
3173
3174 switch (event) {
3175 case MDP_NOTIFY_FRAME_BEGIN:
3176 if (mfd->idle_time && !mod_delayed_work(system_wq,
3177 &mfd->idle_notify_work,
3178 msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT)))
3179 pr_debug("fb%d: start idle delayed work\n",
3180 mfd->index);
3181
3182 mfd->idle_state = MDSS_FB_NOT_IDLE;
3183 break;
3184 case MDP_NOTIFY_FRAME_READY:
3185 if (sync_pt_data->async_wait_fences &&
3186 sync_pt_data->temp_fen_cnt) {
3187 fence_cnt = sync_pt_data->temp_fen_cnt;
3188 sync_pt_data->temp_fen_cnt = 0;
3189 ret = __mdss_fb_wait_for_fence_sub(sync_pt_data,
3190 sync_pt_data->temp_fen, fence_cnt);
3191 }
3192 if (mfd->idle_time && !mod_delayed_work(system_wq,
3193 &mfd->idle_notify_work,
3194 msecs_to_jiffies(mfd->idle_time)))
3195 pr_debug("fb%d: restarted idle work\n",
3196 mfd->index);
3197 if (ret == -ETIME)
3198 ret = NOTIFY_BAD;
3199 mfd->idle_state = MDSS_FB_IDLE_TIMER_RUNNING;
3200 break;
3201 case MDP_NOTIFY_FRAME_FLUSHED:
3202 pr_debug("%s: frame flushed\n", sync_pt_data->fence_name);
3203 sync_pt_data->flushed = true;
3204 break;
3205 case MDP_NOTIFY_FRAME_TIMEOUT:
3206 pr_err("%s: frame timeout\n", sync_pt_data->fence_name);
3207 mdss_fb_signal_timeline(sync_pt_data);
3208 break;
3209 case MDP_NOTIFY_FRAME_DONE:
3210 pr_debug("%s: frame done\n", sync_pt_data->fence_name);
3211 mdss_fb_signal_timeline(sync_pt_data);
3212 mdss_fb_calc_fps(mfd);
3213 break;
3214 case MDP_NOTIFY_FRAME_CFG_DONE:
3215 if (sync_pt_data->async_wait_fences)
3216 __mdss_fb_copy_fence(sync_pt_data,
3217 sync_pt_data->temp_fen,
3218 &sync_pt_data->temp_fen_cnt);
3219 break;
3220 case MDP_NOTIFY_FRAME_CTX_DONE:
3221 mdss_fb_release_kickoff(mfd);
3222 break;
3223 }
3224
3225 return ret;
3226}
3227
3228/**
3229 * mdss_fb_pan_idle() - wait for panel programming to be idle
3230 * @mfd: Framebuffer data structure for display
3231 *
3232 * Wait for any pending programming to be done if in the process of programming
3233 * hardware configuration. After this function returns it is safe to perform
3234 * software updates for next frame.
3235 */
3236static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
3237{
3238 int ret = 0;
3239
3240 ret = wait_event_timeout(mfd->idle_wait_q,
3241 (!atomic_read(&mfd->commits_pending) ||
3242 mfd->shutdown_pending),
3243 msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT));
3244 if (!ret) {
3245 pr_err("%pS: wait for idle timeout commits=%d\n",
3246 __builtin_return_address(0),
3247 atomic_read(&mfd->commits_pending));
3248 MDSS_XLOG_TOUT_HANDLER("mdp", "vbif", "vbif_nrt",
3249 "dbg_bus", "vbif_dbg_bus");
3250 ret = -ETIMEDOUT;
3251 } else if (mfd->shutdown_pending) {
3252 pr_debug("Shutdown signalled\n");
3253 ret = -ESHUTDOWN;
3254 } else {
3255 ret = 0;
3256 }
3257
3258 return ret;
3259}
3260
3261static int mdss_fb_wait_for_kickoff(struct msm_fb_data_type *mfd)
3262{
3263 int ret = 0;
3264
3265 if (!mfd->wait_for_kickoff)
3266 return mdss_fb_pan_idle(mfd);
3267
3268 ret = wait_event_timeout(mfd->kickoff_wait_q,
3269 (!atomic_read(&mfd->kickoff_pending) ||
3270 mfd->shutdown_pending),
3271 msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT));
3272 if (!ret) {
3273 pr_err("%pS: wait for kickoff timeout koff=%d commits=%d\n",
3274 __builtin_return_address(0),
3275 atomic_read(&mfd->kickoff_pending),
3276 atomic_read(&mfd->commits_pending));
3277 MDSS_XLOG_TOUT_HANDLER("mdp", "vbif", "vbif_nrt",
3278 "dbg_bus", "vbif_dbg_bus");
3279 ret = -ETIMEDOUT;
3280 } else if (mfd->shutdown_pending) {
3281 pr_debug("Shutdown signalled\n");
3282 ret = -ESHUTDOWN;
3283 } else {
3284 ret = 0;
3285 }
3286
3287 return ret;
3288}
3289
3290static int mdss_fb_pan_display_ex(struct fb_info *info,
3291 struct mdp_display_commit *disp_commit)
3292{
3293 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
3294 struct fb_var_screeninfo *var = &disp_commit->var;
3295 u32 wait_for_finish = disp_commit->wait_for_finish;
3296 int ret = 0;
3297
3298 if (!mfd || (!mfd->op_enable))
3299 return -EPERM;
3300
3301 if ((mdss_fb_is_power_off(mfd)) &&
3302 !((mfd->dcm_state == DCM_ENTER) &&
3303 (mfd->panel.type == MIPI_CMD_PANEL)))
3304 return -EPERM;
3305
3306 if (var->xoffset > (info->var.xres_virtual - info->var.xres))
3307 return -EINVAL;
3308
3309 if (var->yoffset > (info->var.yres_virtual - info->var.yres))
3310 return -EINVAL;
3311
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05303312 ret = mdss_fb_wait_for_kickoff(mfd);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303313 if (ret) {
3314 pr_err("wait_for_kick failed. rc=%d\n", ret);
3315 return ret;
3316 }
3317
3318 if (mfd->mdp.pre_commit_fnc) {
3319 ret = mfd->mdp.pre_commit_fnc(mfd);
3320 if (ret) {
3321 pr_err("fb%d: pre commit failed %d\n",
3322 mfd->index, ret);
3323 return ret;
3324 }
3325 }
3326
3327 mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
3328 if (info->fix.xpanstep)
3329 info->var.xoffset =
3330 (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
3331
3332 if (info->fix.ypanstep)
3333 info->var.yoffset =
3334 (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
3335
3336 mfd->msm_fb_backup.info = *info;
3337 mfd->msm_fb_backup.disp_commit = *disp_commit;
3338
Nirmal Abrahamc5bb0bd2020-02-26 15:53:44 +05303339 atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303340 atomic_inc(&mfd->commits_pending);
3341 atomic_inc(&mfd->kickoff_pending);
3342 wake_up_all(&mfd->commit_wait_q);
3343 mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
3344 if (wait_for_finish) {
3345 ret = mdss_fb_pan_idle(mfd);
3346 if (ret)
3347 pr_err("mdss_fb_pan_idle failed. rc=%d\n", ret);
3348 }
3349 return ret;
3350}
3351
3352u32 mdss_fb_get_mode_switch(struct msm_fb_data_type *mfd)
3353{
3354 /* If there is no attached mfd then there is no pending mode switch */
3355 if (!mfd)
3356 return 0;
3357
3358 if (mfd->pending_switch)
3359 return mfd->switch_new_mode;
3360
3361 return 0;
3362}
3363
3364/*
3365 * __ioctl_transition_dyn_mode_state() - State machine for mode switch
3366 * @mfd: Framebuffer data structure for display
3367 * @cmd: ioctl that was called
3368 * @validate: used with atomic commit when doing validate layers
3369 *
3370 * This function assists with dynamic mode switch of DSI panel. States
3371 * are used to make sure that panel mode switch occurs on next
3372 * prepare/sync/commit (for legacy) and validate/pre_commit (for
3373 * atomic commit) pairing. This state machine insure that calculation
3374 * and return values (such as buffer release fences) are based on the
3375 * panel mode being switching into.
3376 */
3377static int __ioctl_transition_dyn_mode_state(struct msm_fb_data_type *mfd,
3378 unsigned int cmd, bool validate, bool null_commit)
3379{
3380 if (mfd->switch_state == MDSS_MDP_NO_UPDATE_REQUESTED)
3381 return 0;
3382
3383 mutex_lock(&mfd->switch_lock);
3384 switch (cmd) {
3385 case MSMFB_ATOMIC_COMMIT:
3386 if ((mfd->switch_state == MDSS_MDP_WAIT_FOR_VALIDATE)
3387 && validate) {
3388 if (mfd->switch_new_mode != SWITCH_RESOLUTION)
3389 mfd->pending_switch = true;
3390 mfd->switch_state = MDSS_MDP_WAIT_FOR_COMMIT;
3391 } else if (mfd->switch_state == MDSS_MDP_WAIT_FOR_COMMIT) {
3392 if (mfd->switch_new_mode != SWITCH_RESOLUTION)
3393 mdss_fb_set_mdp_sync_pt_threshold(mfd,
3394 mfd->switch_new_mode);
3395 mfd->switch_state = MDSS_MDP_WAIT_FOR_KICKOFF;
3396 } else if ((mfd->switch_state == MDSS_MDP_WAIT_FOR_VALIDATE)
3397 && null_commit) {
3398 mfd->switch_state = MDSS_MDP_WAIT_FOR_KICKOFF;
3399 }
3400 break;
3401 }
3402 mutex_unlock(&mfd->switch_lock);
3403 return 0;
3404}
3405
3406static inline bool mdss_fb_is_wb_config_same(struct msm_fb_data_type *mfd,
3407 struct mdp_output_layer *output_layer)
3408{
3409 struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
3410 struct msm_mdp_interface *mdp5_interface = &mfd->mdp;
3411
3412 if (!mdp5_data->wfd
3413 || (mdp5_interface->is_config_same
3414 && !mdp5_interface->is_config_same(mfd, output_layer)))
3415 return false;
3416 return true;
3417}
3418
3419/* update pinfo and var for WB on config change */
3420static void mdss_fb_update_resolution(struct msm_fb_data_type *mfd,
3421 u32 xres, u32 yres, u32 format)
3422{
3423 struct mdss_panel_info *pinfo = mfd->panel_info;
3424 struct fb_var_screeninfo *var = &mfd->fbi->var;
3425 struct fb_fix_screeninfo *fix = &mfd->fbi->fix;
3426 struct mdss_mdp_format_params *fmt = NULL;
3427
3428 pinfo->xres = xres;
3429 pinfo->yres = yres;
3430 mfd->fb_imgType = format;
3431 if (mfd->mdp.get_format_params) {
3432 fmt = mfd->mdp.get_format_params(format);
3433 if (fmt) {
3434 pinfo->bpp = fmt->bpp;
3435 var->bits_per_pixel = fmt->bpp * 8;
3436 }
3437 if (mfd->mdp.fb_stride)
3438 fix->line_length = mfd->mdp.fb_stride(mfd->index,
3439 var->xres,
3440 var->bits_per_pixel / 8);
3441 else
3442 fix->line_length = var->xres * var->bits_per_pixel / 8;
3443
3444 }
3445 var->xres_virtual = var->xres;
3446 var->yres_virtual = pinfo->yres * mfd->fb_page;
3447 mdss_panelinfo_to_fb_var(pinfo, var);
3448}
3449
3450int mdss_fb_atomic_commit(struct fb_info *info,
3451 struct mdp_layer_commit *commit, struct file *file)
3452{
3453 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
3454 struct mdp_layer_commit_v1 *commit_v1;
3455 struct mdp_output_layer *output_layer;
3456 struct mdss_panel_info *pinfo;
3457 bool wait_for_finish, wb_change = false;
3458 int ret = -EPERM;
3459 u32 old_xres, old_yres, old_format;
3460
3461 if (!mfd || (!mfd->op_enable)) {
3462 pr_err("mfd is NULL or operation not permitted\n");
3463 return -EPERM;
3464 }
3465
3466 if ((mdss_fb_is_power_off(mfd)) &&
3467 !((mfd->dcm_state == DCM_ENTER) &&
3468 (mfd->panel.type == MIPI_CMD_PANEL))) {
3469 pr_err("commit is not supported when interface is in off state\n");
3470 goto end;
3471 }
3472 pinfo = mfd->panel_info;
3473
3474 /* only supports version 1.0 */
3475 if (commit->version != MDP_COMMIT_VERSION_1_0) {
3476 pr_err("commit version is not supported\n");
3477 goto end;
3478 }
3479
3480 if (!mfd->mdp.pre_commit || !mfd->mdp.atomic_validate) {
3481 pr_err("commit callback is not registered\n");
3482 goto end;
3483 }
3484
3485 commit_v1 = &commit->commit_v1;
3486 if (commit_v1->flags & MDP_VALIDATE_LAYER) {
3487 ret = mdss_fb_wait_for_kickoff(mfd);
3488 if (ret) {
3489 pr_err("wait for kickoff failed\n");
3490 } else {
3491 __ioctl_transition_dyn_mode_state(mfd,
3492 MSMFB_ATOMIC_COMMIT, true, false);
3493 if (mfd->panel.type == WRITEBACK_PANEL) {
3494 output_layer = commit_v1->output_layer;
3495 if (!output_layer) {
3496 pr_err("Output layer is null\n");
3497 goto end;
3498 }
3499 wb_change = !mdss_fb_is_wb_config_same(mfd,
3500 commit_v1->output_layer);
3501 if (wb_change) {
3502 old_xres = pinfo->xres;
3503 old_yres = pinfo->yres;
3504 old_format = mfd->fb_imgType;
3505 mdss_fb_update_resolution(mfd,
3506 output_layer->buffer.width,
3507 output_layer->buffer.height,
3508 output_layer->buffer.format);
3509 }
3510 }
3511 ret = mfd->mdp.atomic_validate(mfd, file, commit_v1);
3512 if (!ret)
3513 mfd->atomic_commit_pending = true;
3514 }
3515 goto end;
3516 } else {
3517 ret = mdss_fb_pan_idle(mfd);
3518 if (ret) {
3519 pr_err("pan display idle call failed\n");
3520 goto end;
3521 }
3522 __ioctl_transition_dyn_mode_state(mfd,
3523 MSMFB_ATOMIC_COMMIT, false,
3524 (commit_v1->input_layer_cnt ? 0 : 1));
3525
3526 ret = mfd->mdp.pre_commit(mfd, file, commit_v1);
3527 if (ret) {
3528 pr_err("atomic pre commit failed\n");
3529 goto end;
3530 }
3531 }
3532
3533 wait_for_finish = commit_v1->flags & MDP_COMMIT_WAIT_FOR_FINISH;
3534 mfd->msm_fb_backup.atomic_commit = true;
3535 mfd->msm_fb_backup.disp_commit.l_roi = commit_v1->left_roi;
3536 mfd->msm_fb_backup.disp_commit.r_roi = commit_v1->right_roi;
Xu Yang2057d112017-02-15 09:29:27 +08003537 mfd->msm_fb_backup.disp_commit.flags = commit_v1->flags;
3538 if (commit_v1->flags & MDP_COMMIT_UPDATE_BRIGHTNESS) {
3539 MDSS_BRIGHT_TO_BL(mfd->bl_extn_level, commit_v1->bl_level,
3540 mfd->panel_info->bl_max,
3541 mfd->panel_info->brightness_max);
3542 if (!mfd->bl_extn_level && commit_v1->bl_level)
3543 mfd->bl_extn_level = 1;
3544 } else
3545 mfd->bl_extn_level = -1;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303546
3547 mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
3548 atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);
3549 atomic_inc(&mfd->commits_pending);
3550 atomic_inc(&mfd->kickoff_pending);
3551 wake_up_all(&mfd->commit_wait_q);
3552 mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
3553
3554 if (wait_for_finish)
3555 ret = mdss_fb_pan_idle(mfd);
3556
3557end:
3558 if (ret && (mfd->panel.type == WRITEBACK_PANEL) && wb_change)
3559 mdss_fb_update_resolution(mfd, old_xres, old_yres, old_format);
3560 return ret;
3561}
3562
3563static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
3564 struct fb_info *info)
3565{
3566 struct mdp_display_commit disp_commit;
3567 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
3568
3569 /*
3570 * during mode switch through mode sysfs node, it will trigger a
3571 * pan_display after switch. This assumes that fb has been adjusted,
3572 * however when using overlays we may not have the right size at this
3573 * point, so it needs to go through PREPARE first. Abort pan_display
3574 * operations until that happens
3575 */
3576 if (mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED) {
3577 pr_debug("fb%d: pan_display skipped during switch\n",
3578 mfd->index);
3579 return 0;
3580 }
3581
3582 memset(&disp_commit, 0, sizeof(disp_commit));
3583 disp_commit.wait_for_finish = true;
3584 memcpy(&disp_commit.var, var, sizeof(struct fb_var_screeninfo));
3585 return mdss_fb_pan_display_ex(info, &disp_commit);
3586}
3587
3588static int mdss_fb_pan_display_sub(struct fb_var_screeninfo *var,
3589 struct fb_info *info)
3590{
3591 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
3592
Chirag Khuranaa39796a2019-11-26 18:16:16 +05303593 if (!mfd)
3594 return -EPERM;
3595
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303596 if (!mfd->op_enable)
3597 return -EPERM;
3598
3599 if ((mdss_fb_is_power_off(mfd)) &&
3600 !((mfd->dcm_state == DCM_ENTER) &&
3601 (mfd->panel.type == MIPI_CMD_PANEL)))
3602 return -EPERM;
3603
3604 if (var->xoffset > (info->var.xres_virtual - info->var.xres))
3605 return -EINVAL;
3606
3607 if (var->yoffset > (info->var.yres_virtual - info->var.yres))
3608 return -EINVAL;
3609
3610 if (info->fix.xpanstep)
3611 info->var.xoffset =
3612 (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
3613
3614 if (info->fix.ypanstep)
3615 info->var.yoffset =
3616 (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
3617
3618 if (mfd->mdp.dma_fnc)
3619 mfd->mdp.dma_fnc(mfd);
3620 else
3621 pr_warn("dma function not set for panel type=%d\n",
3622 mfd->panel.type);
3623
3624 return 0;
3625}
3626
3627static int mdss_grayscale_to_mdp_format(u32 grayscale)
3628{
3629 switch (grayscale) {
3630 case V4L2_PIX_FMT_RGB24:
3631 return MDP_RGB_888;
3632 case V4L2_PIX_FMT_NV12:
3633 return MDP_Y_CBCR_H2V2;
3634 default:
3635 return -EINVAL;
3636 }
3637}
3638
3639static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var,
3640 struct mdss_panel_info *pinfo)
3641{
3642 int format = -EINVAL;
3643
3644 pinfo->xres = var->xres;
3645 pinfo->yres = var->yres;
3646 pinfo->lcdc.v_front_porch = var->lower_margin;
3647 pinfo->lcdc.v_back_porch = var->upper_margin;
3648 pinfo->lcdc.v_pulse_width = var->vsync_len;
3649 pinfo->lcdc.h_front_porch = var->right_margin;
3650 pinfo->lcdc.h_back_porch = var->left_margin;
3651 pinfo->lcdc.h_pulse_width = var->hsync_len;
3652
3653 if (var->grayscale > 1) {
3654 format = mdss_grayscale_to_mdp_format(var->grayscale);
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05303655 if (!IS_ERR_VALUE((unsigned long)format))
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303656 pinfo->out_format = format;
3657 else
3658 pr_warn("Failed to map grayscale value (%d) to an MDP format\n",
3659 var->grayscale);
3660 }
3661
3662 /*
3663 * if greater than 1M, then rate would fall below 1mhz which is not
3664 * even supported. In this case it means clock rate is actually
3665 * passed directly in hz.
3666 */
3667 if (var->pixclock > SZ_1M)
3668 pinfo->clk_rate = var->pixclock;
3669 else
3670 pinfo->clk_rate = PICOS2KHZ(var->pixclock) * 1000;
3671
3672 /*
3673 * if it is a DBA panel i.e. HDMI TV connected through
3674 * DSI interface, then store the pixel clock value in
3675 * DSI specific variable.
3676 */
3677 if (pinfo->is_dba_panel)
3678 pinfo->mipi.dsi_pclk_rate = pinfo->clk_rate;
3679}
3680
3681void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo,
3682 struct fb_var_screeninfo *var)
3683{
3684 u32 frame_rate;
3685
3686 var->xres = mdss_fb_get_panel_xres(pinfo);
3687 var->yres = pinfo->yres;
3688 var->lower_margin = pinfo->lcdc.v_front_porch -
3689 pinfo->prg_fet;
3690 var->upper_margin = pinfo->lcdc.v_back_porch +
3691 pinfo->prg_fet;
3692 var->vsync_len = pinfo->lcdc.v_pulse_width;
3693 var->right_margin = pinfo->lcdc.h_front_porch;
3694 var->left_margin = pinfo->lcdc.h_back_porch;
3695 var->hsync_len = pinfo->lcdc.h_pulse_width;
3696
3697 frame_rate = mdss_panel_get_framerate(pinfo,
3698 FPS_RESOLUTION_HZ);
3699 if (frame_rate) {
3700 unsigned long clk_rate, h_total, v_total;
3701
3702 h_total = var->xres + var->left_margin
3703 + var->right_margin + var->hsync_len;
3704 v_total = var->yres + var->lower_margin
3705 + var->upper_margin + var->vsync_len;
3706 clk_rate = h_total * v_total * frame_rate;
3707 var->pixclock = KHZ2PICOS(clk_rate / 1000);
3708 } else if (pinfo->clk_rate) {
3709 var->pixclock = KHZ2PICOS(
3710 (unsigned long int) pinfo->clk_rate / 1000);
3711 }
3712
3713 if (pinfo->physical_width)
3714 var->width = pinfo->physical_width;
3715 if (pinfo->physical_height)
3716 var->height = pinfo->physical_height;
3717
3718 pr_debug("ScreenInfo: res=%dx%d [%d, %d] [%d, %d]\n",
3719 var->xres, var->yres, var->left_margin,
3720 var->right_margin, var->upper_margin,
3721 var->lower_margin);
3722}
3723
3724/**
3725 * __mdss_fb_perform_commit() - process a frame to display
3726 * @mfd: Framebuffer data structure for display
3727 *
3728 * Processes all layers and buffers programmed and ensures all pending release
3729 * fences are signaled once the buffer is transferred to display.
3730 */
3731static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd)
3732{
3733 struct msm_sync_pt_data *sync_pt_data = &mfd->mdp_sync_pt_data;
3734 struct msm_fb_backup_type *fb_backup = &mfd->msm_fb_backup;
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05303735 int ret = -ENOTSUPP;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303736 u32 new_dsi_mode, dynamic_dsi_switch = 0;
3737
Nirmal Abrahame2c9cb42018-11-22 09:22:02 +05303738 if (mfd->panel_info->panel_dead) {
3739 pr_debug("Panel dead, Signal fence and exit commit\n");
3740 /*
3741 * In case of ESD attack, return early from commit
3742 * after signalling fences.
3743 */
3744 mdss_fb_release_kickoff(mfd);
3745 mdss_fb_signal_timeline(sync_pt_data);
Animesh Kishore8b42bd92018-12-04 18:57:13 +05303746 if (mfd->panel.type == MIPI_CMD_PANEL)
3747 mdss_fb_signal_retire_fence(mfd);
Nirmal Abrahame2c9cb42018-11-22 09:22:02 +05303748 return ret;
3749 }
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303750 if (!sync_pt_data->async_wait_fences)
3751 mdss_fb_wait_for_fence(sync_pt_data);
3752 sync_pt_data->flushed = false;
3753
3754 mutex_lock(&mfd->switch_lock);
3755 if (mfd->switch_state == MDSS_MDP_WAIT_FOR_KICKOFF) {
3756 dynamic_dsi_switch = 1;
3757 new_dsi_mode = mfd->switch_new_mode;
3758 } else if (mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED) {
3759 pr_err("invalid commit on fb%d with state = %d\n",
3760 mfd->index, mfd->switch_state);
3761 mutex_unlock(&mfd->switch_lock);
3762 goto skip_commit;
3763 }
3764 mutex_unlock(&mfd->switch_lock);
3765 if (dynamic_dsi_switch) {
3766 MDSS_XLOG(mfd->index, mfd->split_mode, new_dsi_mode,
3767 XLOG_FUNC_ENTRY);
3768 pr_debug("Triggering dyn mode switch to %d\n", new_dsi_mode);
3769 ret = mfd->mdp.mode_switch(mfd, new_dsi_mode);
3770 if (ret)
3771 pr_err("DSI mode switch has failed");
3772 else
3773 mfd->pending_switch = false;
3774 }
3775 if (fb_backup->disp_commit.flags & MDP_DISPLAY_COMMIT_OVERLAY) {
3776 if (mfd->mdp.kickoff_fnc)
3777 ret = mfd->mdp.kickoff_fnc(mfd,
3778 &fb_backup->disp_commit);
3779 else
3780 pr_warn("no kickoff function setup for fb%d\n",
3781 mfd->index);
3782 } else if (fb_backup->atomic_commit) {
3783 if (mfd->mdp.kickoff_fnc)
3784 ret = mfd->mdp.kickoff_fnc(mfd,
3785 &fb_backup->disp_commit);
3786 else
3787 pr_warn("no kickoff function setup for fb%d\n",
3788 mfd->index);
3789 fb_backup->atomic_commit = false;
3790 } else {
3791 ret = mdss_fb_pan_display_sub(&fb_backup->disp_commit.var,
3792 &fb_backup->info);
3793 if (ret)
3794 pr_err("pan display failed %x on fb%d\n", ret,
3795 mfd->index);
3796 }
3797
3798skip_commit:
3799 if (!ret)
3800 mdss_fb_update_backlight(mfd);
3801
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05303802 if (IS_ERR_VALUE((unsigned long)ret) || !sync_pt_data->flushed) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303803 mdss_fb_release_kickoff(mfd);
3804 mdss_fb_signal_timeline(sync_pt_data);
Animesh Kishore8b42bd92018-12-04 18:57:13 +05303805 if (mfd->panel.type == MIPI_CMD_PANEL)
3806 mdss_fb_signal_retire_fence(mfd);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303807 }
3808
3809 if (dynamic_dsi_switch) {
3810 MDSS_XLOG(mfd->index, mfd->split_mode, new_dsi_mode,
3811 XLOG_FUNC_EXIT);
3812 mfd->mdp.mode_switch_post(mfd, new_dsi_mode);
3813 mutex_lock(&mfd->switch_lock);
3814 mfd->switch_state = MDSS_MDP_NO_UPDATE_REQUESTED;
3815 mutex_unlock(&mfd->switch_lock);
3816 if (new_dsi_mode != SWITCH_RESOLUTION)
3817 mfd->panel.type = new_dsi_mode;
3818 pr_debug("Dynamic mode switch completed\n");
3819 }
3820
3821 return ret;
3822}
3823
3824static int __mdss_fb_display_thread(void *data)
3825{
3826 struct msm_fb_data_type *mfd = data;
3827 int ret;
3828 struct sched_param param;
3829
3830 /*
3831 * this priority was found during empiric testing to have appropriate
3832 * realtime scheduling to process display updates and interact with
3833 * other real time and normal priority tasks
3834 */
3835 param.sched_priority = 16;
3836 ret = sched_setscheduler(current, SCHED_FIFO, &param);
3837 if (ret)
3838 pr_warn("set priority failed for fb%d display thread\n",
3839 mfd->index);
3840
3841 while (1) {
3842 wait_event(mfd->commit_wait_q,
3843 (atomic_read(&mfd->commits_pending) ||
3844 kthread_should_stop()));
3845
3846 if (kthread_should_stop())
3847 break;
3848
3849 MDSS_XLOG(mfd->index, XLOG_FUNC_ENTRY);
3850 ret = __mdss_fb_perform_commit(mfd);
3851 MDSS_XLOG(mfd->index, XLOG_FUNC_EXIT);
3852
3853 atomic_dec(&mfd->commits_pending);
3854 wake_up_all(&mfd->idle_wait_q);
3855 }
3856
3857 mdss_fb_release_kickoff(mfd);
3858 atomic_set(&mfd->commits_pending, 0);
3859 wake_up_all(&mfd->idle_wait_q);
3860
3861 return ret;
3862}
3863
3864static int mdss_fb_check_var(struct fb_var_screeninfo *var,
3865 struct fb_info *info)
3866{
3867 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
3868
3869 if (var->rotate != FB_ROTATE_UR && var->rotate != FB_ROTATE_UD)
3870 return -EINVAL;
3871
3872 switch (var->bits_per_pixel) {
3873 case 16:
3874 if ((var->green.offset != 5) ||
3875 !((var->blue.offset == 11)
3876 || (var->blue.offset == 0)) ||
3877 !((var->red.offset == 11)
3878 || (var->red.offset == 0)) ||
3879 (var->blue.length != 5) ||
3880 (var->green.length != 6) ||
3881 (var->red.length != 5) ||
3882 (var->blue.msb_right != 0) ||
3883 (var->green.msb_right != 0) ||
3884 (var->red.msb_right != 0) ||
3885 (var->transp.offset != 0) ||
3886 (var->transp.length != 0))
3887 return -EINVAL;
3888 break;
3889
3890 case 24:
3891 if ((var->blue.offset != 0) ||
3892 (var->green.offset != 8) ||
3893 (var->red.offset != 16) ||
3894 (var->blue.length != 8) ||
3895 (var->green.length != 8) ||
3896 (var->red.length != 8) ||
3897 (var->blue.msb_right != 0) ||
3898 (var->green.msb_right != 0) ||
3899 (var->red.msb_right != 0) ||
3900 !(((var->transp.offset == 0) &&
3901 (var->transp.length == 0)) ||
3902 ((var->transp.offset == 24) &&
3903 (var->transp.length == 8))))
3904 return -EINVAL;
3905 break;
3906
3907 case 32:
3908 /*
3909 * Check user specified color format BGRA/ARGB/RGBA
3910 * and verify the position of the RGB components
3911 */
3912
3913 if (!((var->transp.offset == 24) &&
3914 (var->blue.offset == 0) &&
3915 (var->green.offset == 8) &&
3916 (var->red.offset == 16)) &&
3917 !((var->transp.offset == 0) &&
3918 (var->blue.offset == 24) &&
3919 (var->green.offset == 16) &&
3920 (var->red.offset == 8)) &&
3921 !((var->transp.offset == 24) &&
3922 (var->blue.offset == 16) &&
3923 (var->green.offset == 8) &&
3924 (var->red.offset == 0)))
3925 return -EINVAL;
3926
3927 /* Check the common values for both RGBA and ARGB */
3928
3929 if ((var->blue.length != 8) ||
3930 (var->green.length != 8) ||
3931 (var->red.length != 8) ||
3932 (var->transp.length != 8) ||
3933 (var->blue.msb_right != 0) ||
3934 (var->green.msb_right != 0) ||
3935 (var->red.msb_right != 0))
3936 return -EINVAL;
3937
3938 break;
3939
3940 default:
3941 return -EINVAL;
3942 }
3943
3944 if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
3945 return -EINVAL;
3946
3947 if ((var->xres == 0) || (var->yres == 0))
3948 return -EINVAL;
3949
3950 if (var->xoffset > (var->xres_virtual - var->xres))
3951 return -EINVAL;
3952
3953 if (var->yoffset > (var->yres_virtual - var->yres))
3954 return -EINVAL;
3955
3956 if (info->mode) {
3957 const struct fb_videomode *mode;
3958
3959 mode = fb_match_mode(var, &info->modelist);
3960 if (mode == NULL)
3961 return -EINVAL;
3962 } else if (mfd->panel_info && !(var->activate & FB_ACTIVATE_TEST)) {
3963 struct mdss_panel_info *panel_info;
3964 int rc;
3965
3966 panel_info = kzalloc(sizeof(struct mdss_panel_info),
3967 GFP_KERNEL);
3968 if (!panel_info)
3969 return -ENOMEM;
3970
3971 memcpy(panel_info, mfd->panel_info,
3972 sizeof(struct mdss_panel_info));
3973 mdss_fb_var_to_panelinfo(var, panel_info);
3974 rc = mdss_fb_send_panel_event(mfd, MDSS_EVENT_CHECK_PARAMS,
3975 panel_info);
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05303976 if (IS_ERR_VALUE((unsigned long)rc)) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05303977 kfree(panel_info);
3978 return rc;
3979 }
3980 mfd->panel_reconfig = rc;
3981 kfree(panel_info);
3982 }
3983
3984 return 0;
3985}
3986
3987static int mdss_fb_videomode_switch(struct msm_fb_data_type *mfd,
3988 const struct fb_videomode *mode)
3989{
3990 int ret = 0;
3991 struct mdss_panel_data *pdata, *tmp;
3992 struct mdss_panel_timing *timing;
3993
3994 pdata = dev_get_platdata(&mfd->pdev->dev);
3995 if (!pdata) {
3996 pr_err("no panel connected\n");
3997 return -ENODEV;
3998 }
3999
4000 /* make sure that we are idle while switching */
4001 mdss_fb_wait_for_kickoff(mfd);
4002
4003 pr_debug("fb%d: changing display mode to %s\n", mfd->index, mode->name);
4004 MDSS_XLOG(mfd->index, mode->name,
4005 mdss_fb_get_panel_xres(mfd->panel_info),
4006 mfd->panel_info->yres, mfd->split_mode,
4007 XLOG_FUNC_ENTRY);
4008 tmp = pdata;
4009 do {
4010 if (!tmp->event_handler) {
4011 pr_warn("no event handler for panel\n");
4012 continue;
4013 }
4014 timing = mdss_panel_get_timing_by_name(tmp, mode->name);
4015 ret = tmp->event_handler(tmp,
4016 MDSS_EVENT_PANEL_TIMING_SWITCH, timing);
4017
4018 tmp->active = timing != NULL;
4019 tmp = tmp->next;
4020 } while (tmp && !ret);
4021
4022 if (!ret)
4023 mdss_fb_set_split_mode(mfd, pdata);
4024
4025 if (!ret && mfd->mdp.configure_panel) {
4026 int dest_ctrl = 1;
4027
4028 /* todo: currently assumes no changes in video/cmd mode */
4029 if (!mdss_fb_is_power_off(mfd)) {
4030 mutex_lock(&mfd->switch_lock);
4031 mfd->switch_state = MDSS_MDP_WAIT_FOR_VALIDATE;
4032 mfd->switch_new_mode = SWITCH_RESOLUTION;
4033 mutex_unlock(&mfd->switch_lock);
4034 dest_ctrl = 0;
4035 }
4036 ret = mfd->mdp.configure_panel(mfd,
4037 pdata->panel_info.mipi.mode, dest_ctrl);
4038 }
4039
4040 MDSS_XLOG(mfd->index, mode->name,
4041 mdss_fb_get_panel_xres(mfd->panel_info),
4042 mfd->panel_info->yres, mfd->split_mode,
4043 XLOG_FUNC_EXIT);
4044 pr_debug("fb%d: %s mode change complete\n", mfd->index, mode->name);
4045
4046 return ret;
4047}
4048
4049static int mdss_fb_set_par(struct fb_info *info)
4050{
4051 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
4052 struct fb_var_screeninfo *var = &info->var;
4053 int old_imgType, old_format;
4054 int ret = 0;
4055
4056 ret = mdss_fb_pan_idle(mfd);
4057 if (ret) {
4058 pr_err("mdss_fb_pan_idle failed. rc=%d\n", ret);
4059 return ret;
4060 }
4061
4062 old_imgType = mfd->fb_imgType;
4063 switch (var->bits_per_pixel) {
4064 case 16:
4065 if (var->red.offset == 0)
4066 mfd->fb_imgType = MDP_BGR_565;
4067 else
4068 mfd->fb_imgType = MDP_RGB_565;
4069 break;
4070
4071 case 24:
4072 if ((var->transp.offset == 0) && (var->transp.length == 0))
4073 mfd->fb_imgType = MDP_RGB_888;
4074 else if ((var->transp.offset == 24) &&
4075 (var->transp.length == 8)) {
4076 mfd->fb_imgType = MDP_ARGB_8888;
4077 info->var.bits_per_pixel = 32;
4078 }
4079 break;
4080
4081 case 32:
4082 if ((var->red.offset == 0) &&
4083 (var->green.offset == 8) &&
4084 (var->blue.offset == 16) &&
4085 (var->transp.offset == 24))
4086 mfd->fb_imgType = MDP_RGBA_8888;
4087 else if ((var->red.offset == 16) &&
4088 (var->green.offset == 8) &&
4089 (var->blue.offset == 0) &&
4090 (var->transp.offset == 24))
4091 mfd->fb_imgType = MDP_BGRA_8888;
4092 else if ((var->red.offset == 8) &&
4093 (var->green.offset == 16) &&
4094 (var->blue.offset == 24) &&
4095 (var->transp.offset == 0))
4096 mfd->fb_imgType = MDP_ARGB_8888;
4097 else
4098 mfd->fb_imgType = MDP_RGBA_8888;
4099 break;
4100
4101 default:
4102 return -EINVAL;
4103 }
4104
4105 if (info->mode) {
4106 const struct fb_videomode *mode;
4107
4108 mode = fb_match_mode(var, &info->modelist);
4109 if (!mode)
4110 return -EINVAL;
4111
4112 pr_debug("found mode: %s\n", mode->name);
4113
4114 if (fb_mode_is_equal(mode, info->mode)) {
4115 pr_debug("mode is equal to current mode\n");
4116 return 0;
4117 }
4118
4119 ret = mdss_fb_videomode_switch(mfd, mode);
4120 if (ret)
4121 return ret;
4122 }
4123
4124 if (mfd->mdp.fb_stride)
4125 mfd->fbi->fix.line_length = mfd->mdp.fb_stride(mfd->index,
4126 var->xres,
4127 var->bits_per_pixel / 8);
4128 else
4129 mfd->fbi->fix.line_length = var->xres * var->bits_per_pixel / 8;
4130
4131 /* if memory is not allocated yet, change memory size for fb */
4132 if (!info->fix.smem_start)
4133 mfd->fbi->fix.smem_len = PAGE_ALIGN(mfd->fbi->fix.line_length *
4134 mfd->fbi->var.yres) * mfd->fb_page;
4135
4136 old_format = mdss_grayscale_to_mdp_format(var->grayscale);
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05304137 if (!IS_ERR_VALUE((unsigned long)old_format)) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304138 if (old_format != mfd->panel_info->out_format)
4139 mfd->panel_reconfig = true;
4140 }
4141
4142 if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
4143 mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
4144 mdss_fb_var_to_panelinfo(var, mfd->panel_info);
4145 if (mfd->panel_info->is_dba_panel &&
4146 mdss_fb_send_panel_event(mfd, MDSS_EVENT_UPDATE_PARAMS,
4147 mfd->panel_info))
4148 pr_debug("Failed to send panel event UPDATE_PARAMS\n");
4149 mdss_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
4150 mfd->panel_reconfig = false;
4151 }
4152
4153 return ret;
4154}
4155
4156int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
4157{
4158 int ret = 0;
4159
4160 if (req_state == mfd->dcm_state) {
4161 pr_warn("Already in correct DCM/DTM state\n");
4162 return ret;
4163 }
4164
4165 switch (req_state) {
4166 case DCM_UNBLANK:
4167 if (mfd->dcm_state == DCM_UNINIT &&
4168 mdss_fb_is_power_off(mfd) && mfd->mdp.on_fnc) {
4169 if (mfd->disp_thread == NULL) {
4170 ret = mdss_fb_start_disp_thread(mfd);
4171 if (ret < 0)
4172 return ret;
4173 }
4174 ret = mfd->mdp.on_fnc(mfd);
4175 if (ret == 0) {
4176 mfd->panel_power_state = MDSS_PANEL_POWER_ON;
4177 mfd->dcm_state = DCM_UNBLANK;
4178 }
4179 }
4180 break;
4181 case DCM_ENTER:
4182 if (mfd->dcm_state == DCM_UNBLANK) {
4183 /*
4184 * Keep unblank path available for only
4185 * DCM operation
4186 */
4187 mfd->panel_power_state = MDSS_PANEL_POWER_OFF;
4188 mfd->dcm_state = DCM_ENTER;
4189 }
4190 break;
4191 case DCM_EXIT:
4192 if (mfd->dcm_state == DCM_ENTER) {
4193 /* Release the unblank path for exit */
4194 mfd->panel_power_state = MDSS_PANEL_POWER_ON;
4195 mfd->dcm_state = DCM_EXIT;
4196 }
4197 break;
4198 case DCM_BLANK:
4199 if ((mfd->dcm_state == DCM_EXIT ||
4200 mfd->dcm_state == DCM_UNBLANK) &&
4201 mdss_fb_is_power_on(mfd) && mfd->mdp.off_fnc) {
4202 mfd->panel_power_state = MDSS_PANEL_POWER_OFF;
4203 ret = mfd->mdp.off_fnc(mfd);
4204 if (ret == 0)
4205 mfd->dcm_state = DCM_UNINIT;
4206 else
4207 pr_err("DCM_BLANK failed\n");
4208
4209 if (mfd->disp_thread)
4210 mdss_fb_stop_disp_thread(mfd);
4211 }
4212 break;
4213 case DTM_ENTER:
4214 if (mfd->dcm_state == DCM_UNINIT)
4215 mfd->dcm_state = DTM_ENTER;
4216 break;
4217 case DTM_EXIT:
4218 if (mfd->dcm_state == DTM_ENTER)
4219 mfd->dcm_state = DCM_UNINIT;
4220 break;
4221 }
4222
4223 return ret;
4224}
4225
4226static int mdss_fb_cursor(struct fb_info *info, void __user *p)
4227{
4228 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
4229 struct fb_cursor cursor;
4230 int ret;
4231
4232 if (!mfd->mdp.cursor_update)
4233 return -ENODEV;
4234
4235 ret = copy_from_user(&cursor, p, sizeof(cursor));
4236 if (ret)
4237 return ret;
4238
4239 return mfd->mdp.cursor_update(mfd, &cursor);
4240}
4241
4242int mdss_fb_async_position_update(struct fb_info *info,
4243 struct mdp_position_update *update_pos)
4244{
4245 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
4246
4247 if (!update_pos->input_layer_cnt) {
4248 pr_err("no input layers for position update\n");
4249 return -EINVAL;
4250 }
4251 return mfd->mdp.async_position_update(mfd, update_pos);
4252}
4253
4254static int mdss_fb_async_position_update_ioctl(struct fb_info *info,
4255 unsigned long *argp)
4256{
4257 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
4258 struct mdp_position_update update_pos;
4259 int ret, rc;
4260 u32 buffer_size, layer_cnt;
4261 struct mdp_async_layer *layer_list = NULL;
4262 struct mdp_async_layer __user *input_layer_list;
4263
4264 if (!mfd->mdp.async_position_update)
4265 return -ENODEV;
4266
4267 ret = copy_from_user(&update_pos, argp, sizeof(update_pos));
4268 if (ret) {
4269 pr_err("copy from user failed\n");
4270 return ret;
4271 }
4272 input_layer_list = update_pos.input_layers;
4273
4274 layer_cnt = update_pos.input_layer_cnt;
4275 if ((!layer_cnt) || (layer_cnt > MAX_LAYER_COUNT)) {
4276 pr_err("invalid async layers :%d to update\n", layer_cnt);
4277 return -EINVAL;
4278 }
4279
4280 buffer_size = sizeof(struct mdp_async_layer) * layer_cnt;
4281 layer_list = kmalloc(buffer_size, GFP_KERNEL);
4282 if (!layer_list) {
4283 pr_err("unable to allocate memory for layers\n");
4284 return -ENOMEM;
4285 }
4286
4287 ret = copy_from_user(layer_list, input_layer_list, buffer_size);
4288 if (ret) {
4289 pr_err("layer list copy from user failed\n");
4290 goto end;
4291 }
4292 update_pos.input_layers = layer_list;
4293
4294 ret = mdss_fb_async_position_update(info, &update_pos);
4295 if (ret)
4296 pr_err("async position update failed ret:%d\n", ret);
4297
4298 rc = copy_to_user(input_layer_list, layer_list, buffer_size);
4299 if (rc)
4300 pr_err("layer error code copy to user failed\n");
4301
4302 update_pos.input_layers = input_layer_list;
4303 rc = copy_to_user(argp, &update_pos,
4304 sizeof(struct mdp_position_update));
4305 if (rc)
4306 pr_err("copy to user for layers failed");
4307
4308end:
4309 kfree(layer_list);
4310 return ret;
4311}
4312
4313static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
4314{
4315 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
4316 struct fb_cmap cmap;
4317 int ret;
4318
4319 if (!mfd->mdp.lut_update)
4320 return -ENODEV;
4321
4322 ret = copy_from_user(&cmap, p, sizeof(cmap));
4323 if (ret)
4324 return ret;
4325
4326 mfd->mdp.lut_update(mfd, &cmap);
4327 return 0;
4328}
4329
4330/**
4331 * mdss_fb_sync_get_fence() - get fence from timeline
4332 * @timeline: Timeline to create the fence on
4333 * @fence_name: Name of the fence that will be created for debugging
4334 * @val: Timeline value at which the fence will be signaled
4335 *
4336 * Function returns a fence on the timeline given with the name provided.
4337 * The fence created will be signaled when the timeline is advanced.
4338 */
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304339struct mdss_fence *mdss_fb_sync_get_fence(struct mdss_timeline *timeline,
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304340 const char *fence_name, int val)
4341{
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304342 struct mdss_fence *fence;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304343
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304344
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304345 fence = mdss_get_sync_fence(timeline, fence_name, NULL, val);
4346 pr_debug("%s: buf sync fence timeline=%d\n",
4347 mdss_get_sync_fence_name(fence), val);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304348 if (fence == NULL) {
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304349 pr_err("%s: cannot create fence\n", fence_name);
4350 return NULL;
4351 }
4352
4353 return fence;
4354}
4355
4356static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
4357 struct mdp_buf_sync *buf_sync)
4358{
4359 int i, ret = 0;
4360 int acq_fen_fd[MDP_MAX_FENCE_FD];
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304361 struct mdss_fence *fence, *rel_fence, *retire_fence;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304362 int rel_fen_fd;
4363 int retire_fen_fd;
4364 int val;
4365
4366 if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
4367 (sync_pt_data->timeline == NULL))
4368 return -EINVAL;
4369
4370 if (buf_sync->acq_fen_fd_cnt)
4371 ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
4372 buf_sync->acq_fen_fd_cnt * sizeof(int));
4373 if (ret) {
4374 pr_err("%s: copy_from_user failed\n", sync_pt_data->fence_name);
4375 return ret;
4376 }
4377
4378 i = mdss_fb_wait_for_fence(sync_pt_data);
4379 if (i > 0)
4380 pr_warn("%s: waited on %d active fences\n",
4381 sync_pt_data->fence_name, i);
4382
4383 mutex_lock(&sync_pt_data->sync_mutex);
4384 for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304385 fence = mdss_get_fd_sync_fence(acq_fen_fd[i]);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304386 if (fence == NULL) {
4387 pr_err("%s: null fence! i=%d fd=%d\n",
4388 sync_pt_data->fence_name, i,
4389 acq_fen_fd[i]);
4390 ret = -EINVAL;
4391 break;
4392 }
4393 sync_pt_data->acq_fen[i] = fence;
4394 }
4395 sync_pt_data->acq_fen_cnt = i;
4396 if (ret)
4397 goto buf_sync_err_1;
4398
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304399 val = sync_pt_data->threshold +
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304400 atomic_read(&sync_pt_data->commit_cnt);
4401
4402 MDSS_XLOG(sync_pt_data->timeline_value, val,
4403 atomic_read(&sync_pt_data->commit_cnt));
4404 pr_debug("%s: fence CTL%d Commit_cnt%d\n", sync_pt_data->fence_name,
4405 sync_pt_data->timeline_value,
4406 atomic_read(&sync_pt_data->commit_cnt));
4407 /* Set release fence */
4408 rel_fence = mdss_fb_sync_get_fence(sync_pt_data->timeline,
4409 sync_pt_data->fence_name, val);
4410 if (IS_ERR_OR_NULL(rel_fence)) {
4411 pr_err("%s: unable to retrieve release fence\n",
4412 sync_pt_data->fence_name);
4413 ret = rel_fence ? PTR_ERR(rel_fence) : -ENOMEM;
4414 goto buf_sync_err_1;
4415 }
4416
4417 /* create fd */
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304418 rel_fen_fd = mdss_get_sync_fence_fd(rel_fence);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304419 if (rel_fen_fd < 0) {
4420 pr_err("%s: get_unused_fd_flags failed error:0x%x\n",
4421 sync_pt_data->fence_name, rel_fen_fd);
4422 ret = rel_fen_fd;
4423 goto buf_sync_err_2;
4424 }
4425
4426 ret = copy_to_user(buf_sync->rel_fen_fd, &rel_fen_fd, sizeof(int));
4427 if (ret) {
4428 pr_err("%s: copy_to_user failed\n", sync_pt_data->fence_name);
4429 goto buf_sync_err_3;
4430 }
4431
4432 if (!(buf_sync->flags & MDP_BUF_SYNC_FLAG_RETIRE_FENCE))
4433 goto skip_retire_fence;
4434
4435 if (sync_pt_data->get_retire_fence)
4436 retire_fence = sync_pt_data->get_retire_fence(sync_pt_data);
4437 else
4438 retire_fence = NULL;
4439
4440 if (IS_ERR_OR_NULL(retire_fence)) {
4441 val += sync_pt_data->retire_threshold;
4442 retire_fence = mdss_fb_sync_get_fence(
Nirmal Abrahamc5bb0bd2020-02-26 15:53:44 +05304443 sync_pt_data->timeline_retire, "mdp-retire", val);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304444 }
4445
4446 if (IS_ERR_OR_NULL(retire_fence)) {
4447 pr_err("%s: unable to retrieve retire fence\n",
4448 sync_pt_data->fence_name);
4449 ret = retire_fence ? PTR_ERR(rel_fence) : -ENOMEM;
4450 goto buf_sync_err_3;
4451 }
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304452 retire_fen_fd = mdss_get_sync_fence_fd(retire_fence);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304453
4454 if (retire_fen_fd < 0) {
4455 pr_err("%s: get_unused_fd_flags failed for retire fence error:0x%x\n",
4456 sync_pt_data->fence_name, retire_fen_fd);
4457 ret = retire_fen_fd;
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304458 mdss_put_sync_fence(retire_fence);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304459 goto buf_sync_err_3;
4460 }
4461
4462 ret = copy_to_user(buf_sync->retire_fen_fd, &retire_fen_fd,
4463 sizeof(int));
4464 if (ret) {
4465 pr_err("%s: copy_to_user failed for retire fence\n",
4466 sync_pt_data->fence_name);
4467 put_unused_fd(retire_fen_fd);
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304468 mdss_put_sync_fence(retire_fence);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304469 goto buf_sync_err_3;
4470 }
4471
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304472skip_retire_fence:
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304473 mutex_unlock(&sync_pt_data->sync_mutex);
4474
4475 if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
4476 mdss_fb_wait_for_fence(sync_pt_data);
4477
4478 return ret;
4479buf_sync_err_3:
4480 put_unused_fd(rel_fen_fd);
4481buf_sync_err_2:
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304482 mdss_put_sync_fence(rel_fence);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304483buf_sync_err_1:
4484 for (i = 0; i < sync_pt_data->acq_fen_cnt; i++)
Sachin Bhayare2b6d0042018-01-13 19:38:21 +05304485 mdss_put_sync_fence(sync_pt_data->acq_fen[i]);
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304486 sync_pt_data->acq_fen_cnt = 0;
4487 mutex_unlock(&sync_pt_data->sync_mutex);
4488 return ret;
4489}
4490static int mdss_fb_display_commit(struct fb_info *info,
4491 unsigned long *argp)
4492{
4493 int ret;
4494 struct mdp_display_commit disp_commit;
4495
4496 ret = copy_from_user(&disp_commit, argp,
4497 sizeof(disp_commit));
4498 if (ret) {
4499 pr_err("%s:copy_from_user failed\n", __func__);
4500 return ret;
4501 }
4502 ret = mdss_fb_pan_display_ex(info, &disp_commit);
4503 return ret;
4504}
4505
4506/**
4507 * __mdss_fb_copy_pixel_ext() - copy pixel extension payload
4508 * @src: pixel extn structure
4509 * @dest: Qseed3/pixel extn common payload
4510 *
4511 * Function copies the pixel extension parameters into the scale data structure,
4512 * this is required to allow using the scale_v2 data structure for both
4513 * QSEED2 and QSEED3
4514 */
4515static void __mdss_fb_copy_pixel_ext(struct mdp_scale_data *src,
4516 struct mdp_scale_data_v2 *dest)
4517{
4518 if (!src || !dest)
4519 return;
4520 memcpy(dest->init_phase_x, src->init_phase_x,
4521 sizeof(src->init_phase_x));
4522 memcpy(dest->phase_step_x, src->phase_step_x,
4523 sizeof(src->init_phase_x));
4524 memcpy(dest->init_phase_y, src->init_phase_y,
4525 sizeof(src->init_phase_x));
4526 memcpy(dest->phase_step_y, src->phase_step_y,
4527 sizeof(src->init_phase_x));
4528
4529 memcpy(dest->num_ext_pxls_left, src->num_ext_pxls_left,
4530 sizeof(src->num_ext_pxls_left));
4531 memcpy(dest->num_ext_pxls_right, src->num_ext_pxls_right,
4532 sizeof(src->num_ext_pxls_right));
4533 memcpy(dest->num_ext_pxls_top, src->num_ext_pxls_top,
4534 sizeof(src->num_ext_pxls_top));
4535 memcpy(dest->num_ext_pxls_btm, src->num_ext_pxls_btm,
4536 sizeof(src->num_ext_pxls_btm));
4537
4538 memcpy(dest->left_ftch, src->left_ftch, sizeof(src->left_ftch));
4539 memcpy(dest->left_rpt, src->left_rpt, sizeof(src->left_rpt));
4540 memcpy(dest->right_ftch, src->right_ftch, sizeof(src->right_ftch));
4541 memcpy(dest->right_rpt, src->right_rpt, sizeof(src->right_rpt));
4542
4543
4544 memcpy(dest->top_rpt, src->top_rpt, sizeof(src->top_rpt));
4545 memcpy(dest->btm_rpt, src->btm_rpt, sizeof(src->btm_rpt));
4546 memcpy(dest->top_ftch, src->top_ftch, sizeof(src->top_ftch));
4547 memcpy(dest->btm_ftch, src->btm_ftch, sizeof(src->btm_ftch));
4548
4549 memcpy(dest->roi_w, src->roi_w, sizeof(src->roi_w));
4550}
4551
4552static int __mdss_fb_scaler_handler(struct mdp_input_layer *layer)
4553{
4554 int ret = 0;
4555 struct mdp_scale_data *pixel_ext = NULL;
4556 struct mdp_scale_data_v2 *scale = NULL;
4557
4558 if ((layer->flags & MDP_LAYER_ENABLE_PIXEL_EXT) &&
4559 (layer->flags & MDP_LAYER_ENABLE_QSEED3_SCALE)) {
4560 pr_err("Invalid flag configuration for scaler, %x\n",
4561 layer->flags);
4562 ret = -EINVAL;
4563 goto err;
4564 }
4565
4566 if (layer->flags & MDP_LAYER_ENABLE_PIXEL_EXT) {
4567 scale = kzalloc(sizeof(struct mdp_scale_data_v2),
4568 GFP_KERNEL);
4569 pixel_ext = kzalloc(sizeof(struct mdp_scale_data),
4570 GFP_KERNEL);
4571 if (!scale || !pixel_ext) {
4572 mdss_mdp_free_layer_pp_info(layer);
4573 ret = -ENOMEM;
4574 goto err;
4575 }
4576 ret = copy_from_user(pixel_ext, layer->scale,
4577 sizeof(struct mdp_scale_data));
4578 if (ret) {
4579 mdss_mdp_free_layer_pp_info(layer);
4580 ret = -EFAULT;
4581 goto err;
4582 }
4583 __mdss_fb_copy_pixel_ext(pixel_ext, scale);
4584 layer->scale = scale;
4585 } else if (layer->flags & MDP_LAYER_ENABLE_QSEED3_SCALE) {
4586 scale = kzalloc(sizeof(struct mdp_scale_data_v2),
4587 GFP_KERNEL);
4588 if (!scale) {
4589 mdss_mdp_free_layer_pp_info(layer);
4590 ret = -ENOMEM;
4591 goto err;
4592 }
4593
4594 ret = copy_from_user(scale, layer->scale,
4595 sizeof(struct mdp_scale_data_v2));
4596 if (ret) {
4597 mdss_mdp_free_layer_pp_info(layer);
4598 ret = -EFAULT;
4599 goto err;
4600 }
4601 layer->scale = scale;
4602 } else {
4603 layer->scale = NULL;
4604 }
4605 kfree(pixel_ext);
4606 return ret;
4607err:
4608 kfree(pixel_ext);
4609 kfree(scale);
4610 layer->scale = NULL;
4611 return ret;
4612}
4613
4614static int mdss_fb_atomic_commit_ioctl(struct fb_info *info,
4615 unsigned long *argp, struct file *file)
4616{
4617 int ret, i = 0, j = 0, rc;
4618 struct mdp_layer_commit commit;
4619 u32 buffer_size, layer_count;
4620 struct mdp_input_layer *layer, *layer_list = NULL;
4621 struct mdp_input_layer __user *input_layer_list;
4622 struct mdp_output_layer *output_layer = NULL;
4623 struct mdp_output_layer __user *output_layer_user;
4624 struct mdp_frc_info *frc_info = NULL;
4625 struct mdp_frc_info __user *frc_info_user;
4626 struct msm_fb_data_type *mfd;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304627
4628 ret = copy_from_user(&commit, argp, sizeof(struct mdp_layer_commit));
4629 if (ret) {
4630 pr_err("%s:copy_from_user failed\n", __func__);
4631 return ret;
4632 }
4633
4634 mfd = (struct msm_fb_data_type *)info->par;
4635 if (!mfd)
4636 return -EINVAL;
4637
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304638 output_layer_user = commit.commit_v1.output_layer;
4639 if (output_layer_user) {
4640 buffer_size = sizeof(struct mdp_output_layer);
4641 output_layer = kzalloc(buffer_size, GFP_KERNEL);
4642 if (!output_layer) {
4643 pr_err("unable to allocate memory for output layer\n");
4644 return -ENOMEM;
4645 }
4646
4647 ret = copy_from_user(output_layer,
4648 output_layer_user, buffer_size);
4649 if (ret) {
4650 pr_err("layer list copy from user failed\n");
4651 goto err;
4652 }
4653 commit.commit_v1.output_layer = output_layer;
4654 }
4655
4656 layer_count = commit.commit_v1.input_layer_cnt;
4657 input_layer_list = commit.commit_v1.input_layers;
4658
4659 if (layer_count > MAX_LAYER_COUNT) {
4660 ret = -EINVAL;
4661 goto err;
4662 } else if (layer_count) {
4663 buffer_size = sizeof(struct mdp_input_layer) * layer_count;
4664 layer_list = kzalloc(buffer_size, GFP_KERNEL);
4665 if (!layer_list) {
4666 pr_err("unable to allocate memory for layers\n");
4667 ret = -ENOMEM;
4668 goto err;
4669 }
4670
4671 ret = copy_from_user(layer_list, input_layer_list, buffer_size);
4672 if (ret) {
4673 pr_err("layer list copy from user failed\n");
4674 goto err;
4675 }
4676
4677 commit.commit_v1.input_layers = layer_list;
4678
4679 for (i = 0; i < layer_count; i++) {
4680 layer = &layer_list[i];
4681
4682 if (!(layer->flags & MDP_LAYER_PP)) {
4683 layer->pp_info = NULL;
4684 } else {
4685 ret = mdss_mdp_copy_layer_pp_info(layer);
4686 if (ret) {
4687 pr_err("failure to copy pp_info data for layer %d, ret = %d\n",
4688 i, ret);
4689 goto err;
4690 }
4691 }
4692
4693 if ((layer->flags & MDP_LAYER_ENABLE_PIXEL_EXT) ||
4694 (layer->flags &
4695 MDP_LAYER_ENABLE_QSEED3_SCALE)) {
4696 ret = __mdss_fb_scaler_handler(layer);
4697 if (ret) {
4698 pr_err("failure to copy scale params for layer %d, ret = %d\n",
4699 i, ret);
4700 goto err;
4701 }
4702 } else {
4703 layer->scale = NULL;
4704 }
4705 }
4706 }
4707
4708 /* Copy Deterministic Frame Rate Control info from userspace */
4709 frc_info_user = commit.commit_v1.frc_info;
4710 if (frc_info_user) {
4711 frc_info = kzalloc(sizeof(struct mdp_frc_info), GFP_KERNEL);
4712 if (!frc_info) {
4713 pr_err("unable to allocate memory for frc\n");
4714 ret = -ENOMEM;
4715 goto err;
4716 }
4717
4718 ret = copy_from_user(frc_info, frc_info_user,
4719 sizeof(struct mdp_frc_info));
4720 if (ret) {
4721 pr_err("frc info copy from user failed\n");
4722 goto frc_err;
4723 }
4724
4725 commit.commit_v1.frc_info = frc_info;
4726 }
4727
4728 ATRACE_BEGIN("ATOMIC_COMMIT");
4729 ret = mdss_fb_atomic_commit(info, &commit, file);
4730 if (ret)
4731 pr_err("atomic commit failed ret:%d\n", ret);
4732 ATRACE_END("ATOMIC_COMMIT");
4733
4734 if (layer_count) {
4735 for (j = 0; j < layer_count; j++) {
4736 rc = copy_to_user(&input_layer_list[j].error_code,
4737 &layer_list[j].error_code, sizeof(int));
4738 if (rc)
4739 pr_err("layer error code copy to user failed\n");
4740 }
4741
4742 commit.commit_v1.input_layers = input_layer_list;
4743 commit.commit_v1.output_layer = output_layer_user;
4744 commit.commit_v1.frc_info = frc_info_user;
4745 rc = copy_to_user(argp, &commit,
4746 sizeof(struct mdp_layer_commit));
4747 if (rc)
4748 pr_err("copy to user for release & retire fence failed\n");
4749 }
4750
4751frc_err:
4752 kfree(frc_info);
4753err:
4754 for (i--; i >= 0; i--) {
4755 kfree(layer_list[i].scale);
4756 layer_list[i].scale = NULL;
4757 mdss_mdp_free_layer_pp_info(&layer_list[i]);
4758 }
4759 kfree(layer_list);
4760 kfree(output_layer);
4761
4762 return ret;
4763}
4764
4765int mdss_fb_switch_check(struct msm_fb_data_type *mfd, u32 mode)
4766{
4767 struct mdss_panel_info *pinfo = NULL;
4768 int panel_type;
4769
4770 if (!mfd || !mfd->panel_info)
4771 return -EINVAL;
4772
4773 pinfo = mfd->panel_info;
4774
4775 if ((!mfd->op_enable) || (mdss_fb_is_power_off(mfd)))
4776 return -EPERM;
4777
4778 if (pinfo->mipi.dms_mode != DYNAMIC_MODE_SWITCH_IMMEDIATE) {
4779 pr_warn("Panel does not support immediate dynamic switch!\n");
4780 return -EPERM;
4781 }
4782
4783 if (mfd->dcm_state != DCM_UNINIT) {
4784 pr_warn("Switch not supported during DCM!\n");
4785 return -EPERM;
4786 }
4787
4788 mutex_lock(&mfd->switch_lock);
4789 if (mode == pinfo->type) {
4790 pr_debug("Already in requested mode!\n");
4791 mutex_unlock(&mfd->switch_lock);
4792 return -EPERM;
4793 }
4794 mutex_unlock(&mfd->switch_lock);
4795
4796 panel_type = mfd->panel.type;
4797 if (panel_type != MIPI_VIDEO_PANEL && panel_type != MIPI_CMD_PANEL) {
4798 pr_debug("Panel not in mipi video or cmd mode, cannot change\n");
4799 return -EPERM;
4800 }
4801
4802 return 0;
4803}
4804
4805static int mdss_fb_immediate_mode_switch(struct msm_fb_data_type *mfd, u32 mode)
4806{
4807 int ret;
4808 u32 tranlated_mode;
4809
4810 if (mode)
4811 tranlated_mode = MIPI_CMD_PANEL;
4812 else
4813 tranlated_mode = MIPI_VIDEO_PANEL;
4814
4815 pr_debug("%s: Request to switch to %d,", __func__, tranlated_mode);
4816
4817 ret = mdss_fb_switch_check(mfd, tranlated_mode);
4818 if (ret)
4819 return ret;
4820
4821 mutex_lock(&mfd->switch_lock);
4822 if (mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED) {
4823 pr_err("%s: Mode switch already in progress\n", __func__);
4824 ret = -EAGAIN;
4825 goto exit;
4826 }
4827 mfd->switch_state = MDSS_MDP_WAIT_FOR_VALIDATE;
4828 mfd->switch_new_mode = tranlated_mode;
4829
4830exit:
4831 mutex_unlock(&mfd->switch_lock);
4832 return ret;
4833}
4834
4835/*
4836 * mdss_fb_mode_switch() - Function to change DSI mode
4837 * @mfd: Framebuffer data structure for display
4838 * @mode: Enabled/Disable LowPowerMode
4839 * 1: Switch to Command Mode
4840 * 0: Switch to video Mode
4841 *
4842 * This function is used to change from DSI mode based on the
4843 * argument @mode on the next frame to be displayed.
4844 */
4845static int mdss_fb_mode_switch(struct msm_fb_data_type *mfd, u32 mode)
4846{
4847 struct mdss_panel_info *pinfo = NULL;
4848 int ret = 0;
4849
4850 if (!mfd || !mfd->panel_info)
4851 return -EINVAL;
4852
Veera Sundaram Sankaran7f87b6d2016-09-12 11:10:30 -07004853 /* make sure that we are idle while switching */
4854 mdss_fb_wait_for_kickoff(mfd);
4855
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304856 pinfo = mfd->panel_info;
4857 if (pinfo->mipi.dms_mode == DYNAMIC_MODE_SWITCH_SUSPEND_RESUME) {
4858 ret = mdss_fb_blanking_mode_switch(mfd, mode);
4859 } else if (pinfo->mipi.dms_mode == DYNAMIC_MODE_SWITCH_IMMEDIATE) {
4860 ret = mdss_fb_immediate_mode_switch(mfd, mode);
4861 } else {
4862 pr_warn("Panel does not support dynamic mode switch!\n");
4863 ret = -EPERM;
4864 }
4865
4866 return ret;
4867}
4868
4869static int __ioctl_wait_idle(struct msm_fb_data_type *mfd, u32 cmd)
4870{
4871 int ret = 0;
4872
4873 if (mfd->wait_for_kickoff &&
4874 ((cmd == MSMFB_OVERLAY_PREPARE) ||
4875 (cmd == MSMFB_BUFFER_SYNC) ||
4876 (cmd == MSMFB_OVERLAY_PLAY) ||
4877 (cmd == MSMFB_CURSOR) ||
4878 (cmd == MSMFB_METADATA_GET) ||
4879 (cmd == MSMFB_METADATA_SET) ||
4880 (cmd == MSMFB_OVERLAY_GET) ||
4881 (cmd == MSMFB_OVERLAY_UNSET) ||
4882 (cmd == MSMFB_OVERLAY_SET))) {
4883 ret = mdss_fb_wait_for_kickoff(mfd);
4884 }
4885
4886 if (ret && (ret != -ESHUTDOWN))
4887 pr_err("wait_idle failed. cmd=0x%x rc=%d\n", cmd, ret);
4888
4889 return ret;
4890}
4891
4892#ifdef TARGET_HW_MDSS_MDP3
4893static bool check_not_supported_ioctl(u32 cmd)
4894{
4895 return false;
4896}
4897#else
4898static bool check_not_supported_ioctl(u32 cmd)
4899{
4900 return((cmd == MSMFB_OVERLAY_SET) || (cmd == MSMFB_OVERLAY_UNSET) ||
4901 (cmd == MSMFB_OVERLAY_GET) || (cmd == MSMFB_OVERLAY_PREPARE) ||
4902 (cmd == MSMFB_DISPLAY_COMMIT) || (cmd == MSMFB_OVERLAY_PLAY) ||
4903 (cmd == MSMFB_BUFFER_SYNC) || (cmd == MSMFB_OVERLAY_QUEUE) ||
4904 (cmd == MSMFB_NOTIFY_UPDATE));
4905}
4906#endif
4907
4908/*
4909 * mdss_fb_do_ioctl() - MDSS Framebuffer ioctl function
4910 * @info: pointer to framebuffer info
4911 * @cmd: ioctl command
4912 * @arg: argument to ioctl
4913 *
4914 * This function provides an architecture agnostic implementation
4915 * of the mdss framebuffer ioctl. This function can be called
4916 * by compat ioctl or regular ioctl to handle the supported commands.
4917 */
4918int mdss_fb_do_ioctl(struct fb_info *info, unsigned int cmd,
4919 unsigned long arg, struct file *file)
4920{
4921 struct msm_fb_data_type *mfd;
4922 void __user *argp = (void __user *)arg;
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05304923 int ret = -ENOTSUPP;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05304924 struct mdp_buf_sync buf_sync;
4925 unsigned int dsi_mode = 0;
4926 struct mdss_panel_data *pdata = NULL;
4927
4928 if (!info || !info->par)
4929 return -EINVAL;
4930
4931 mfd = (struct msm_fb_data_type *)info->par;
4932 if (!mfd)
4933 return -EINVAL;
4934
4935 if (mfd->shutdown_pending)
4936 return -ESHUTDOWN;
4937
4938 pdata = dev_get_platdata(&mfd->pdev->dev);
4939 if (!pdata || pdata->panel_info.dynamic_switch_pending)
4940 return -EPERM;
4941
4942 if (check_not_supported_ioctl(cmd)) {
4943 pr_err("Unsupported ioctl\n");
4944 return -EINVAL;
4945 }
4946
4947 atomic_inc(&mfd->ioctl_ref_cnt);
4948
4949 mdss_fb_power_setting_idle(mfd);
4950
4951 ret = __ioctl_wait_idle(mfd, cmd);
4952 if (ret)
4953 goto exit;
4954
4955 switch (cmd) {
4956 case MSMFB_CURSOR:
4957 ret = mdss_fb_cursor(info, argp);
4958 break;
4959
4960 case MSMFB_SET_LUT:
4961 ret = mdss_fb_set_lut(info, argp);
4962 break;
4963
4964 case MSMFB_BUFFER_SYNC:
4965 ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
4966 if (ret)
4967 goto exit;
4968
4969 if ((!mfd->op_enable) || (mdss_fb_is_power_off(mfd))) {
4970 ret = -EPERM;
4971 goto exit;
4972 }
4973
4974 ret = mdss_fb_handle_buf_sync_ioctl(&mfd->mdp_sync_pt_data,
4975 &buf_sync);
4976 if (!ret)
4977 ret = copy_to_user(argp, &buf_sync, sizeof(buf_sync));
4978 break;
4979
4980 case MSMFB_NOTIFY_UPDATE:
4981 ret = mdss_fb_notify_update(mfd, argp);
4982 break;
4983
4984 case MSMFB_DISPLAY_COMMIT:
4985 ret = mdss_fb_display_commit(info, argp);
4986 break;
4987
4988 case MSMFB_LPM_ENABLE:
4989 ret = copy_from_user(&dsi_mode, argp, sizeof(dsi_mode));
4990 if (ret) {
4991 pr_err("%s: MSMFB_LPM_ENABLE ioctl failed\n", __func__);
4992 goto exit;
4993 }
4994
4995 ret = mdss_fb_mode_switch(mfd, dsi_mode);
4996 break;
4997 case MSMFB_ATOMIC_COMMIT:
4998 ret = mdss_fb_atomic_commit_ioctl(info, argp, file);
4999 break;
5000
5001 case MSMFB_ASYNC_POSITION_UPDATE:
5002 ret = mdss_fb_async_position_update_ioctl(info, argp);
5003 break;
5004
5005 default:
5006 if (mfd->mdp.ioctl_handler)
5007 ret = mfd->mdp.ioctl_handler(mfd, cmd, argp);
5008 break;
5009 }
5010
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05305011 if (ret == -ENOTSUPP)
Sachin Bhayareeeb88892018-01-02 16:36:01 +05305012 pr_err("unsupported ioctl (%x)\n", cmd);
5013
5014exit:
5015 if (!atomic_dec_return(&mfd->ioctl_ref_cnt))
5016 wake_up_all(&mfd->ioctl_q);
5017
5018 return ret;
5019}
5020
5021static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
5022 unsigned long arg, struct file *file)
5023{
5024 if (!info || !info->par)
5025 return -EINVAL;
5026
5027 return mdss_fb_do_ioctl(info, cmd, arg, file);
5028}
5029
5030static int mdss_fb_register_extra_panel(struct platform_device *pdev,
5031 struct mdss_panel_data *pdata)
5032{
5033 struct mdss_panel_data *fb_pdata;
5034
5035 fb_pdata = dev_get_platdata(&pdev->dev);
5036 if (!fb_pdata) {
5037 pr_err("framebuffer device %s contains invalid panel data\n",
5038 dev_name(&pdev->dev));
5039 return -EINVAL;
5040 }
5041
5042 if (fb_pdata->next) {
5043 pr_err("split panel already setup for framebuffer device %s\n",
5044 dev_name(&pdev->dev));
5045 return -EEXIST;
5046 }
5047
5048 fb_pdata->next = pdata;
5049
5050 return 0;
5051}
5052
5053int mdss_register_panel(struct platform_device *pdev,
5054 struct mdss_panel_data *pdata)
5055{
5056 struct platform_device *fb_pdev, *mdss_pdev;
5057 struct device_node *node = NULL;
5058 int rc = 0;
5059 bool master_panel = true;
5060
5061 if (!pdev || !pdev->dev.of_node) {
5062 pr_err("Invalid device node\n");
5063 return -ENODEV;
5064 }
5065
5066 if (!mdp_instance) {
5067 pr_err("mdss mdp resource not initialized yet\n");
5068 return -EPROBE_DEFER;
5069 }
5070
5071 if (pdata->get_fb_node)
5072 node = pdata->get_fb_node(pdev);
5073
5074 if (!node) {
5075 node = of_parse_phandle(pdev->dev.of_node,
5076 "qcom,mdss-fb-map", 0);
5077 if (!node) {
5078 pr_err("Unable to find fb node for device: %s\n",
5079 pdev->name);
5080 return -ENODEV;
5081 }
5082 }
5083 mdss_pdev = of_find_device_by_node(node->parent);
5084 if (!mdss_pdev) {
5085 pr_err("Unable to find mdss for node: %s\n", node->full_name);
5086 rc = -ENODEV;
5087 goto mdss_notfound;
5088 }
5089
5090 pdata->active = true;
5091 fb_pdev = of_find_device_by_node(node);
5092 if (fb_pdev) {
5093 rc = mdss_fb_register_extra_panel(fb_pdev, pdata);
5094 if (rc == 0)
5095 master_panel = false;
5096 } else {
5097 pr_info("adding framebuffer device %s\n", dev_name(&pdev->dev));
5098 fb_pdev = of_platform_device_create(node, NULL,
5099 &mdss_pdev->dev);
5100 if (fb_pdev)
5101 fb_pdev->dev.platform_data = pdata;
5102 }
5103
5104 if (master_panel && mdp_instance->panel_register_done)
5105 mdp_instance->panel_register_done(pdata);
5106
5107mdss_notfound:
5108 of_node_put(node);
5109 return rc;
5110}
5111EXPORT_SYMBOL(mdss_register_panel);
5112
5113int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp)
5114{
5115 if (mdp_instance) {
5116 pr_err("multiple MDP instance registration\n");
5117 return -EINVAL;
5118 }
5119
5120 mdp_instance = mdp;
5121 return 0;
5122}
5123EXPORT_SYMBOL(mdss_fb_register_mdp_instance);
5124
5125int mdss_fb_get_phys_info(dma_addr_t *start, unsigned long *len, int fb_num)
5126{
5127 struct fb_info *info;
5128 struct msm_fb_data_type *mfd;
5129
5130 if (fb_num >= MAX_FBI_LIST)
5131 return -EINVAL;
5132
5133 info = fbi_list[fb_num];
5134 if (!info)
5135 return -ENOENT;
5136
5137 mfd = (struct msm_fb_data_type *)info->par;
5138 if (!mfd)
5139 return -ENODEV;
5140
5141 if (mfd->iova)
5142 *start = mfd->iova;
5143 else
5144 *start = info->fix.smem_start;
5145 *len = info->fix.smem_len;
5146
5147 return 0;
5148}
5149EXPORT_SYMBOL(mdss_fb_get_phys_info);
5150
5151int __init mdss_fb_init(void)
5152{
5153 int rc = -ENODEV;
5154
5155 if (fb_get_options("msmfb", NULL))
5156 return rc;
5157
5158 if (platform_driver_register(&mdss_fb_driver))
5159 return rc;
5160
5161 return 0;
5162}
5163
5164module_init(mdss_fb_init);
5165
5166int mdss_fb_suspres_panel(struct device *dev, void *data)
5167{
5168 struct msm_fb_data_type *mfd;
5169 int rc = 0;
5170 u32 event;
5171
5172 if (!data) {
5173 pr_err("Device state not defined\n");
5174 return -EINVAL;
5175 }
5176 mfd = dev_get_drvdata(dev);
5177 if (!mfd)
5178 return 0;
5179
5180 event = *((bool *) data) ? MDSS_EVENT_RESUME : MDSS_EVENT_SUSPEND;
5181
5182 /* Do not send runtime suspend/resume for HDMI primary */
5183 if (!mdss_fb_is_hdmi_primary(mfd)) {
5184 rc = mdss_fb_send_panel_event(mfd, event, NULL);
5185 if (rc)
5186 pr_warn("unable to %s fb%d (%d)\n",
5187 event == MDSS_EVENT_RESUME ?
5188 "resume" : "suspend",
5189 mfd->index, rc);
5190 }
5191 return rc;
5192}
5193
5194/*
5195 * mdss_fb_report_panel_dead() - Sends the PANEL_ALIVE=0 status to HAL layer.
5196 * @mfd : frame buffer structure associated with fb device.
5197 *
5198 * This function is called if the panel fails to respond as expected to
5199 * the register read/BTA or if the TE signal is not coming as expected
5200 * from the panel. The function sends the PANEL_ALIVE=0 status to HAL
5201 * layer.
5202 */
5203void mdss_fb_report_panel_dead(struct msm_fb_data_type *mfd)
5204{
5205 char *envp[2] = {"PANEL_ALIVE=0", NULL};
5206 struct mdss_panel_data *pdata =
5207 dev_get_platdata(&mfd->pdev->dev);
5208 if (!pdata) {
5209 pr_err("Panel data not available\n");
5210 return;
5211 }
5212
5213 pdata->panel_info.panel_dead = true;
5214 kobject_uevent_env(&mfd->fbi->dev->kobj,
5215 KOBJ_CHANGE, envp);
5216 pr_err("Panel has gone bad, sending uevent - %s\n", envp[0]);
5217}
5218
5219
5220/*
5221 * mdss_fb_calc_fps() - Calculates fps value.
5222 * @mfd : frame buffer structure associated with fb device.
5223 *
5224 * This function is called at frame done. It counts the number
5225 * of frames done for every 1 sec. Stores the value in measured_fps.
5226 * measured_fps value is 10 times the calculated fps value.
5227 * For example, measured_fps= 594 for calculated fps of 59.4
5228 */
5229void mdss_fb_calc_fps(struct msm_fb_data_type *mfd)
5230{
5231 ktime_t current_time_us;
5232 u64 fps, diff_us;
5233
5234 current_time_us = ktime_get();
5235 diff_us = (u64)ktime_us_delta(current_time_us,
5236 mfd->fps_info.last_sampled_time_us);
5237 mfd->fps_info.frame_count++;
5238
5239 if (diff_us >= MDP_TIME_PERIOD_CALC_FPS_US) {
5240 fps = ((u64)mfd->fps_info.frame_count) * 10000000;
5241 do_div(fps, diff_us);
5242 mfd->fps_info.measured_fps = (unsigned int)fps;
5243 pr_debug(" MDP_FPS for fb%d is %d.%d\n",
5244 mfd->index, (unsigned int)fps/10, (unsigned int)fps%10);
5245 mfd->fps_info.last_sampled_time_us = current_time_us;
5246 mfd->fps_info.frame_count = 0;
5247 }
5248}
Abhijit Kulkarnic8c7eec2017-02-08 16:41:16 -08005249
5250void mdss_fb_idle_pc(struct msm_fb_data_type *mfd)
5251{
5252 struct mdss_overlay_private *mdp5_data;
5253
5254 if (!mfd || mdss_fb_is_power_off(mfd))
5255 return;
5256
5257 mdp5_data = mfd_to_mdp5_data(mfd);
5258
5259 if ((mfd->panel_info->type == MIPI_CMD_PANEL) && mdp5_data) {
5260 pr_debug("Notify fb%d idle power collapsed\n", mfd->index);
5261 sysfs_notify(&mfd->fbi->dev->kobj, NULL, "idle_power_collapse");
5262 }
5263}