Skip to content

Instantly share code, notes, and snippets.

@invisiblek
Created March 23, 2015 22:17
Show Gist options
  • Save invisiblek/e127265b3136230e7594 to your computer and use it in GitHub Desktop.
Save invisiblek/e127265b3136230e7594 to your computer and use it in GitHub Desktop.
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index a71d6f8..db66761 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -2,7 +2,7 @@
* Core MDSS framebuffer driver.
*
* Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2015, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -44,6 +44,7 @@
#include <linux/file.h>
#include <linux/memory_alloc.h>
#include <linux/kthread.h>
+#include <linux/of_address.h>
#include <mach/board.h>
#include <mach/memory.h>
@@ -52,13 +53,7 @@
#include <mach/msm_memtypes.h>
#include "mdss_fb.h"
-
-#ifdef CONFIG_MACH_LGE
-#include "mdss_mdp.h"
-#include <mach/board_lge.h>
-static int force_set_bl_f;
-unsigned long msm_fb_phys_addr_backup;
-#endif
+#include "mdss_mdp_splash_logo.h"
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
#define MDSS_FB_NUM 3
@@ -93,7 +88,10 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd);
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg);
-static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
+ struct vm_area_struct *vma);
+static int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd,
+ size_t size);
static void mdss_fb_release_fences(struct msm_fb_data_type *mfd);
static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
unsigned long val, void *data);
@@ -102,6 +100,7 @@ static int __mdss_fb_display_thread(void *data);
static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
int event, void *arg);
+static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd);
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
@@ -113,6 +112,31 @@ void mdss_fb_no_update_notify_timer_cb(unsigned long data)
complete(&mfd->no_update.comp);
}
+void mdss_fb_bl_update_notify(struct msm_fb_data_type *mfd)
+{
+ if (!mfd) {
+ pr_err("%s mfd NULL\n", __func__);
+ return;
+ }
+ mutex_lock(&mfd->update.lock);
+ if (mfd->update.ref_count > 0) {
+ mutex_unlock(&mfd->update.lock);
+ mfd->update.value = NOTIFY_TYPE_BL_UPDATE;
+ complete(&mfd->update.comp);
+ mutex_lock(&mfd->update.lock);
+ }
+ mutex_unlock(&mfd->update.lock);
+
+ mutex_lock(&mfd->no_update.lock);
+ if (mfd->no_update.ref_count > 0) {
+ mutex_unlock(&mfd->no_update.lock);
+ mfd->no_update.value = NOTIFY_TYPE_BL_UPDATE;
+ complete(&mfd->no_update.comp);
+ mutex_lock(&mfd->no_update.lock);
+ }
+ mutex_unlock(&mfd->no_update.lock);
+}
+
static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
unsigned long *argp)
{
@@ -128,10 +152,20 @@ static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
if (notify > NOTIFY_UPDATE_POWER_OFF)
return -EINVAL;
- if (notify == NOTIFY_UPDATE_START) {
+ if (mfd->update.is_suspend) {
+ to_user = NOTIFY_TYPE_SUSPEND;
+ mfd->update.is_suspend = 0;
+ ret = 1;
+ } else if (notify == NOTIFY_UPDATE_START) {
INIT_COMPLETION(mfd->update.comp);
- ret = wait_for_completion_timeout(
+ mutex_lock(&mfd->update.lock);
+ mfd->update.ref_count++;
+ mutex_unlock(&mfd->update.lock);
+ ret = wait_for_completion_interruptible_timeout(
&mfd->update.comp, 4 * HZ);
+ mutex_lock(&mfd->update.lock);
+ mfd->update.ref_count--;
+ mutex_unlock(&mfd->update.lock);
to_user = (unsigned int)mfd->update.value;
if (mfd->update.type == NOTIFY_TYPE_SUSPEND) {
to_user = (unsigned int)mfd->update.type;
@@ -139,13 +173,19 @@ static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
}
} else if (notify == NOTIFY_UPDATE_STOP) {
INIT_COMPLETION(mfd->no_update.comp);
- ret = wait_for_completion_timeout(
+ mutex_lock(&mfd->no_update.lock);
+ mfd->no_update.ref_count++;
+ mutex_unlock(&mfd->no_update.lock);
+ ret = wait_for_completion_interruptible_timeout(
&mfd->no_update.comp, 4 * HZ);
+ mutex_lock(&mfd->no_update.lock);
+ mfd->no_update.ref_count--;
+ mutex_unlock(&mfd->no_update.lock);
to_user = (unsigned int)mfd->no_update.value;
} else {
if (mfd->panel_power_on) {
INIT_COMPLETION(mfd->power_off_comp);
- ret = wait_for_completion_timeout(
+ ret = wait_for_completion_interruptible_timeout(
&mfd->power_off_comp, 1 * HZ);
}
}
@@ -230,23 +270,32 @@ static ssize_t mdss_fb_get_type(struct device *dev,
return ret;
}
-static void mdss_fb_parse_dt_split(struct msm_fb_data_type *mfd)
+static void mdss_fb_parse_dt(struct msm_fb_data_type *mfd)
{
- u32 data[2];
+ u32 data[2] = {0};
+ u32 panel_xres;
struct platform_device *pdev = mfd->pdev;
- if (of_property_read_u32_array(pdev->dev.of_node, "qcom,mdss-fb-split",
- data, 2))
- return;
- if (data[0] && data[1] &&
- (mfd->panel_info->xres == (data[0] + data[1]))) {
- mfd->split_fb_left = data[0];
- mfd->split_fb_right = data[1];
- pr_info("split framebuffer left=%d right=%d\n",
- mfd->split_fb_left, mfd->split_fb_right);
+
+ of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,mdss-fb-split", data, 2);
+
+ panel_xres = mfd->panel_info->xres;
+ if (data[0] && data[1]) {
+ if (mfd->split_display)
+ panel_xres *= 2;
+
+ if (panel_xres == data[0] + data[1]) {
+ mfd->split_fb_left = data[0];
+ mfd->split_fb_right = data[1];
+ }
} else {
- mfd->split_fb_left = 0;
- mfd->split_fb_right = 0;
+ if (mfd->split_display)
+ mfd->split_fb_left = mfd->split_fb_right = panel_xres;
+ else
+ mfd->split_fb_left = mfd->split_fb_right = 0;
}
+ pr_info("split framebuffer left=%d right=%d\n",
+ mfd->split_fb_left, mfd->split_fb_right);
}
static ssize_t mdss_fb_get_split(struct device *dev,
@@ -330,12 +379,117 @@ static ssize_t mdss_fb_get_idle_notify(struct device *dev,
return ret;
}
+static ssize_t mdss_fb_get_panel_info(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = fbi->par;
+ struct mdss_panel_info *pinfo = mfd->panel_info;
+ int ret;
+
+ ret = scnprintf(buf, PAGE_SIZE,
+ "pu_en=%d\nxstart=%d\nwalign=%d\nystart=%d\nhalign=%d\n"
+ "min_w=%d\nmin_h=%d",
+ pinfo->partial_update_enabled, pinfo->xstart_pix_align,
+ pinfo->width_pix_align, pinfo->ystart_pix_align,
+ pinfo->height_pix_align, pinfo->min_width,
+ pinfo->min_height);
+
+ return ret;
+}
+
+/*
+ * mdss_fb_lpm_enable() - Function to Control LowPowerMode
+ * @mfd: Framebuffer data structure for display
+ * @mode: Enabled/Disable LowPowerMode
+ * 1: Enter into LowPowerMode
+ * 0: Exit from LowPowerMode
+ *
+ * This Function dynamically switches to and from LowPowerMode
+ * based on the argument @mode.
+ */
+static int mdss_fb_lpm_enable(struct msm_fb_data_type *mfd, int mode)
+{
+ int ret = 0;
+ u32 bl_lvl = 0;
+ struct mdss_panel_info *pinfo = NULL;
+ struct mdss_panel_data *pdata;
+
+ if (!mfd || !mfd->panel_info)
+ return -EINVAL;
+
+ pinfo = mfd->panel_info;
+
+ if (!pinfo->mipi.dynamic_switch_enabled) {
+ pr_warn("Panel does not support dynamic switch!\n");
+ return 0;
+ }
+
+ if (mode == pinfo->mipi.mode) {
+ pr_debug("Already in requested mode!\n");
+ return 0;
+ }
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ pr_debug("Enter mode: %d\n", mode);
+ pdata->panel_info.dynamic_switch_pending = true;
+
+ mutex_lock(&mfd->bl_lock);
+ bl_lvl = mfd->bl_level;
+ mdss_fb_set_backlight(mfd, 0);
+ mutex_unlock(&mfd->bl_lock);
+
+ lock_fb_info(mfd->fbi);
+ ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
+ mfd->op_enable);
+ if (ret) {
+ pr_err("can't turn off display!\n");
+ unlock_fb_info(mfd->fbi);
+ return ret;
+ }
+
+ mfd->op_enable = false;
+
+ ret = mfd->mdp.configure_panel(mfd, mode);
+ mdss_fb_set_mdp_sync_pt_threshold(mfd);
+
+ mfd->op_enable = true;
+
+ ret = mdss_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
+ mfd->op_enable);
+ if (ret) {
+ pr_err("can't turn on display!\n");
+ unlock_fb_info(mfd->fbi);
+ return ret;
+ }
+ unlock_fb_info(mfd->fbi);
+
+ mutex_lock(&mfd->bl_lock);
+ mfd->bl_updated = true;
+ mdss_fb_set_backlight(mfd, bl_lvl);
+ mutex_unlock(&mfd->bl_lock);
+
+ pdata->panel_info.dynamic_switch_pending = false;
+ pdata->panel_info.is_lpm_mode = mode ? 1 : 0;
+
+ if (ret) {
+ pr_err("can't turn on display!\n");
+ return ret;
+ }
+
+ pr_debug("Exit mode: %d\n", mode);
+
+ return 0;
+}
+
static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL);
static DEVICE_ATTR(idle_time, S_IRUGO | S_IWUSR | S_IWGRP,
mdss_fb_get_idle_time, mdss_fb_set_idle_time);
static DEVICE_ATTR(idle_notify, S_IRUGO, mdss_fb_get_idle_notify, NULL);
+static DEVICE_ATTR(msm_fb_panel_info, S_IRUGO, mdss_fb_get_panel_info, NULL);
static struct attribute *mdss_fb_attrs[] = {
&dev_attr_msm_fb_type.attr,
@@ -343,6 +497,7 @@ static struct attribute *mdss_fb_attrs[] = {
&dev_attr_show_blank_event.attr,
&dev_attr_idle_time.attr,
&dev_attr_idle_notify.attr,
+ &dev_attr_msm_fb_panel_info.attr,
NULL,
};
@@ -410,8 +565,10 @@ static int mdss_fb_probe(struct platform_device *pdev)
mfd->ext_ad_ctrl = -1;
mfd->bl_level = 0;
+ mfd->bl_level_prev_scaled = 0;
mfd->bl_scale = 1024;
mfd->bl_min_lvl = 30;
+ mfd->ad_bl_level = 0;
mfd->fb_imgType = MDP_RGBA_8888;
mfd->pdev = pdev;
@@ -420,7 +577,6 @@ static int mdss_fb_probe(struct platform_device *pdev)
mfd->mdp = *mdp_instance;
INIT_LIST_HEAD(&mfd->proc_list);
- mutex_init(&mfd->lock);
mutex_init(&mfd->bl_lock);
fbi_list[fbi_list_index++] = fbi;
@@ -473,6 +629,21 @@ static int mdss_fb_probe(struct platform_device *pdev)
__mdss_fb_sync_buf_done_callback;
}
+ mdss_fb_set_mdp_sync_pt_threshold(mfd);
+
+ if (mfd->mdp.splash_init_fnc)
+ mfd->mdp.splash_init_fnc(mfd);
+
+ INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
+
+ return rc;
+}
+
+static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd)
+{
+ if (!mfd)
+ return;
+
switch (mfd->panel.type) {
case WRITEBACK_PANEL:
mfd->mdp_sync_pt_data.threshold = 1;
@@ -487,25 +658,20 @@ static int mdss_fb_probe(struct platform_device *pdev)
mfd->mdp_sync_pt_data.retire_threshold = 0;
break;
}
-
- INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
-
- return rc;
}
-
static int mdss_fb_remove(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+ if (!mfd)
+ return -ENODEV;
+
mdss_fb_remove_sysfs(mfd);
pm_runtime_disable(mfd->fbi->dev);
- if (!mfd)
- return -ENODEV;
-
if (mfd->key != MFD_KEY)
return -EINVAL;
@@ -721,26 +887,12 @@ static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
{
struct mdss_panel_data *pdata;
- int (*update_ad_input)(struct msm_fb_data_type *mfd);
u32 temp = bkl_lvl;
+ bool bl_notify_needed = false;
-#ifdef CONFIG_MACH_LGE
- if(force_set_bl_f || lge_get_boot_mode()== LGE_BOOT_MODE_QEM_130K) {
-
- pdata = dev_get_platdata(&mfd->pdev->dev);
-
- if ((pdata) && (pdata->set_backlight)) {
- mdss_fb_scale_bl(mfd, &temp);
- pdata->set_backlight(pdata, temp);
- pr_info("regardless bl_updated, force to set bl. level=%d, laf_mode=%d\n",
- temp, lge_get_laf_mode());
- }
- return;
- }
-#endif
-
- if (((!mfd->panel_power_on && mfd->dcm_state != DCM_ENTER)
- || !mfd->bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
+ if ((((!mfd->panel_power_on && mfd->dcm_state != DCM_ENTER)
+ || !mfd->bl_updated) && !IS_CALIB_MODE_BL(mfd)) ||
+ mfd->panel_info->cont_splash_enabled) {
mfd->unset_bl_level = bkl_lvl;
return;
} else {
@@ -750,6 +902,13 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
+ if (mfd->mdp.ad_calc_bl)
+ (*mfd->mdp.ad_calc_bl)(mfd, temp, &temp,
+ &bl_notify_needed);
+ if (bl_notify_needed)
+ mdss_fb_bl_update_notify(mfd);
+
+ mfd->bl_level_prev_scaled = mfd->bl_level_scaled;
if (!IS_CALIB_MODE_BL(mfd))
mdss_fb_scale_bl(mfd, &temp);
/*
@@ -760,20 +919,13 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
* as well as setting bl_level to bkl_lvl even though the
* backlight has been set to the scaled value.
*/
- if (mfd->bl_level_old == temp) {
+ if (mfd->bl_level_scaled == temp) {
mfd->bl_level = bkl_lvl;
- return;
- }
- pdata->set_backlight(pdata, temp);
- mfd->bl_level = bkl_lvl;
- mfd->bl_level_old = temp;
-
- if (mfd->mdp.update_ad_input) {
- update_ad_input = mfd->mdp.update_ad_input;
- mutex_unlock(&mfd->bl_lock);
- /* Will trigger ad_setup which will grab bl_lock */
- update_ad_input(mfd);
- mutex_lock(&mfd->bl_lock);
+ } else {
+ pr_debug("backlight sent to panel :%d\n", temp);
+ pdata->set_backlight(pdata, temp);
+ mfd->bl_level = bkl_lvl;
+ mfd->bl_level_scaled = temp;
}
}
}
@@ -781,18 +933,26 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
{
struct mdss_panel_data *pdata;
+ u32 temp;
+ bool bl_notify = false;
+ mutex_lock(&mfd->bl_lock);
if (mfd->unset_bl_level && !mfd->bl_updated) {
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
- mutex_lock(&mfd->bl_lock);
mfd->bl_level = mfd->unset_bl_level;
- pdata->set_backlight(pdata, mfd->bl_level);
- mfd->bl_level_old = mfd->unset_bl_level;
- mutex_unlock(&mfd->bl_lock);
+ temp = mfd->bl_level;
+ if (mfd->mdp.ad_calc_bl)
+ (*mfd->mdp.ad_calc_bl)(mfd, temp, &temp,
+ &bl_notify);
+ if (bl_notify)
+ mdss_fb_bl_update_notify(mfd);
+ pdata->set_backlight(pdata, temp);
+ mfd->bl_level_scaled = mfd->unset_bl_level;
mfd->bl_updated = 1;
}
}
+ mutex_unlock(&mfd->bl_lock);
}
static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
@@ -817,6 +977,7 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
}
mutex_lock(&mfd->update.lock);
mfd->update.type = NOTIFY_TYPE_UPDATE;
+ mfd->update.is_suspend = 0;
mutex_unlock(&mfd->update.lock);
/* Start the work thread to signal idle time */
@@ -824,6 +985,13 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
schedule_delayed_work(&mfd->idle_notify_work,
msecs_to_jiffies(mfd->idle_time));
}
+
+ mutex_lock(&mfd->bl_lock);
+ if (!mfd->bl_updated) {
+ mfd->bl_updated = 1;
+ mdss_fb_set_backlight(mfd, mfd->bl_level_prev_scaled);
+ }
+ mutex_unlock(&mfd->bl_lock);
break;
case FB_BLANK_VSYNC_SUSPEND:
@@ -836,15 +1004,20 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
mutex_lock(&mfd->update.lock);
mfd->update.type = NOTIFY_TYPE_SUSPEND;
+ mfd->update.is_suspend = 1;
mutex_unlock(&mfd->update.lock);
+ complete(&mfd->update.comp);
del_timer(&mfd->no_update.timer);
mfd->no_update.value = NOTIFY_TYPE_SUSPEND;
complete(&mfd->no_update.comp);
mfd->op_enable = false;
curr_pwr_state = mfd->panel_power_on;
+ mutex_lock(&mfd->bl_lock);
+ mdss_fb_set_backlight(mfd, 0);
mfd->panel_power_on = false;
mfd->bl_updated = 0;
+ mutex_unlock(&mfd->bl_lock);
ret = mfd->mdp.off_fnc(mfd);
if (ret)
@@ -856,12 +1029,15 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
}
break;
}
+ /* Notify listeners */
+ sysfs_notify(&mfd->fbi->dev->kobj, NULL, "show_blank_event");
return ret;
}
static int mdss_fb_blank(int blank_mode, struct fb_info *info)
{
+ struct mdss_panel_data *pdata;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
mdss_fb_pan_idle(mfd);
@@ -872,71 +1048,297 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info)
mfd->suspend.panel_power_on = false;
return 0;
}
+ pr_debug("mode: %d\n", blank_mode);
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ if (pdata->panel_info.is_lpm_mode &&
+ blank_mode == FB_BLANK_UNBLANK) {
+ pr_debug("panel is in lpm mode\n");
+ mfd->mdp.configure_panel(mfd, 0);
+ mdss_fb_set_mdp_sync_pt_threshold(mfd);
+ pdata->panel_info.is_lpm_mode = false;
+ }
+
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
+static inline int mdss_fb_create_ion_client(struct msm_fb_data_type *mfd)
+{
+ mfd->fb_ion_client = msm_ion_client_create(-1 , "mdss_fb_iclient");
+ if (IS_ERR_OR_NULL(mfd->fb_ion_client)) {
+ pr_err("Err:client not created, val %d\n",
+ PTR_RET(mfd->fb_ion_client));
+ mfd->fb_ion_client = NULL;
+ return PTR_RET(mfd->fb_ion_client);
+ }
+ return 0;
+}
+
+void mdss_fb_free_fb_ion_memory(struct msm_fb_data_type *mfd)
+{
+ if (!mfd) {
+ pr_err("no mfd\n");
+ return;
+ }
+
+ if (!mfd->fbi->screen_base)
+ return;
+
+ if (!mfd->fb_ion_client || !mfd->fb_ion_handle) {
+ pr_err("invalid input parameters for fb%d\n", mfd->index);
+ return;
+ }
+
+ mfd->fbi->screen_base = NULL;
+ mfd->fbi->fix.smem_start = 0;
+
+ ion_unmap_kernel(mfd->fb_ion_client, mfd->fb_ion_handle);
+
+ if (mfd->mdp.fb_mem_get_iommu_domain) {
+ ion_unmap_iommu(mfd->fb_ion_client, mfd->fb_ion_handle,
+ mfd->mdp.fb_mem_get_iommu_domain(), 0);
+ }
+
+ ion_free(mfd->fb_ion_client, mfd->fb_ion_handle);
+ mfd->fb_ion_handle = NULL;
+}
+
+int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd, size_t fb_size)
+{
+ unsigned long buf_size;
+ int rc;
+ void *vaddr;
+
+ if (!mfd) {
+ pr_err("Invalid input param - no mfd");
+ return -EINVAL;
+ }
+
+ if (!mfd->fb_ion_client) {
+ rc = mdss_fb_create_ion_client(mfd);
+ if (rc < 0) {
+ pr_err("fb ion client couldn't be created - %d\n", rc);
+ return rc;
+ }
+ }
+
+ pr_debug("size for mmap = %zu", fb_size);
+ mfd->fb_ion_handle = ion_alloc(mfd->fb_ion_client, fb_size, SZ_4K,
+ ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(mfd->fb_ion_handle)) {
+ pr_err("unable to alloc fbmem from ion - %ld\n",
+ PTR_ERR(mfd->fb_ion_handle));
+ return PTR_ERR(mfd->fb_ion_handle);
+ }
+
+ if (mfd->mdp.fb_mem_get_iommu_domain) {
+ rc = ion_map_iommu(mfd->fb_ion_client, mfd->fb_ion_handle,
+ mfd->mdp.fb_mem_get_iommu_domain(), 0, SZ_4K, 0,
+ &mfd->iova, &buf_size, 0, 0);
+ if (rc) {
+ pr_err("Cannot map fb_mem to IOMMU. rc=%d\n", rc);
+ goto fb_mmap_failed;
+ }
+ } else {
+ pr_err("No IOMMU Domain");
+ goto fb_mmap_failed;
+
+ }
+
+ vaddr = ion_map_kernel(mfd->fb_ion_client, mfd->fb_ion_handle);
+ if (IS_ERR_OR_NULL(vaddr)) {
+ pr_err("ION memory mapping failed - %ld\n", PTR_ERR(vaddr));
+ rc = PTR_ERR(vaddr);
+ if (mfd->mdp.fb_mem_get_iommu_domain) {
+ ion_unmap_iommu(mfd->fb_ion_client, mfd->fb_ion_handle,
+ mfd->mdp.fb_mem_get_iommu_domain(), 0);
+ }
+ goto fb_mmap_failed;
+ }
+
+ pr_debug("alloc 0x%zuB vaddr = %p (%pa iova) for fb%d\n", fb_size,
+ vaddr, &mfd->iova, mfd->index);
+
+ mfd->fbi->screen_base = (char *) vaddr;
+ mfd->fbi->fix.smem_start = (unsigned int) mfd->iova;
+ mfd->fbi->fix.smem_len = fb_size;
+
+ return rc;
+
+fb_mmap_failed:
+ ion_free(mfd->fb_ion_client, mfd->fb_ion_handle);
+ return rc;
+}
+
+/**
+ * mdss_fb_fbmem_ion_mmap() - Custom fb mmap() function for MSM driver.
+ *
+ * @info - Framebuffer info.
+ * @vma - VM area which is part of the process virtual memory.
+ *
+ * This framebuffer mmap function differs from standard mmap() function by
+ * allowing for customized page-protection and dynamically allocate framebuffer
+ * memory from system heap and map to iommu virtual address.
+ *
+ * Return: virtual address is returned through vma
+ */
+static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
+{
+ int rc = 0;
+ size_t req_size, fb_size;
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct sg_table *table;
+ unsigned long addr = vma->vm_start;
+ unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+ struct scatterlist *sg;
+ unsigned int i;
+ struct page *page;
+
+ if (!mfd || !mfd->pdev || !mfd->pdev->dev.of_node) {
+ pr_err("Invalid device node\n");
+ return -ENODEV;
+ }
+
+ req_size = vma->vm_end - vma->vm_start;
+ fb_size = mfd->fbi->fix.smem_len;
+ if (req_size > fb_size) {
+ pr_warn("requested map is greater than framebuffer");
+ return -EOVERFLOW;
+ }
+
+ if (!mfd->fbi->screen_base) {
+ rc = mdss_fb_alloc_fb_ion_memory(mfd, fb_size);
+ if (rc < 0) {
+ pr_err("fb mmap failed!!!!");
+ return rc;
+ }
+ }
+
+ table = ion_sg_table(mfd->fb_ion_client, mfd->fb_ion_handle);
+ if (IS_ERR(table)) {
+ pr_err("Unable to get sg_table from ion:%ld\n", PTR_ERR(table));
+ mfd->fbi->screen_base = NULL;
+ return PTR_ERR(table);
+ } else if (!table) {
+ pr_err("sg_list is NULL\n");
+ mfd->fbi->screen_base = NULL;
+ return -EINVAL;
+ }
+
+ page = sg_page(table->sgl);
+ if (page) {
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ unsigned long remainder = vma->vm_end - addr;
+ unsigned long len = sg->length;
+
+ page = sg_page(sg);
+
+ if (offset >= sg->length) {
+ offset -= sg->length;
+ continue;
+ } else if (offset) {
+ page += offset / PAGE_SIZE;
+ len = sg->length - offset;
+ offset = 0;
+ }
+ len = min(len, remainder);
+
+ if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
+ vma->vm_page_prot =
+ pgprot_writecombine(vma->vm_page_prot);
+
+ pr_debug("vma=%p, addr=%x len=%ld",
+ vma, (unsigned int)addr, len);
+ pr_cont("vm_start=%x vm_end=%x vm_page_prot=%ld\n",
+ (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end,
+ (unsigned long int)vma->vm_page_prot);
+
+ io_remap_pfn_range(vma, addr, page_to_pfn(page), len,
+ vma->vm_page_prot);
+ addr += len;
+ if (addr >= vma->vm_end)
+ break;
+ }
+ } else {
+ pr_err("PAGE is null\n");
+ mdss_fb_free_fb_ion_memory(mfd);
+ return -ENOMEM;
+ }
+
+ return rc;
+}
+
/*
- * Custom Framebuffer mmap() function for MSM driver.
- * Differs from standard mmap() function by allowing for customized
- * page-protection.
+ * mdss_fb_physical_mmap() - Custom fb mmap() function for MSM driver.
+ *
+ * @info - Framebuffer info.
+ * @vma - VM area which is part of the process virtual memory.
+ *
+ * This framebuffer mmap function differs from standard mmap() function as
+ * map to framebuffer memory from the CMA memory which is allocated during
+ * bootup.
+ *
+ * Return: virtual address is returned through vma
*/
-static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+static int mdss_fb_physical_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
{
/* Get frame buffer memory range. */
unsigned long start = info->fix.smem_start;
u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- int ret = 0;
if (!start) {
- pr_warn("No framebuffer memory is allocated.\n");
+ pr_warn("No framebuffer memory is allocated\n");
return -ENOMEM;
}
- ret = mdss_fb_pan_idle(mfd);
- if (ret) {
- pr_err("Shutdown pending. Aborting operation\n");
- return ret;
- }
-
/* Set VM flags. */
start &= PAGE_MASK;
if ((vma->vm_end <= vma->vm_start) ||
- (off >= len) ||
- ((vma->vm_end - vma->vm_start) > (len - off)))
+ (off >= len) ||
+ ((vma->vm_end - vma->vm_start) > (len - off)))
return -EINVAL;
off += start;
if (off < start)
return -EINVAL;
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
- vma->vm_flags |= VM_IO | VM_RESERVED;
+ vma->vm_flags |= VM_IO;
- /* Set VM page protection */
if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
- vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
- vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
- vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
/* Remap the frame buffer I/O range */
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
return -EAGAIN;
return 0;
}
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int rc = 0;
+
+ if (!info->fix.smem_start && !mfd->fb_ion_handle)
+ rc = mdss_fb_fbmem_ion_mmap(info, vma);
+ else
+ rc = mdss_fb_physical_mmap(info, vma);
+
+ if (rc < 0)
+ pr_err("fb mmap failed with rc = %d", rc);
+
+ return rc;
+}
+
static struct fb_ops mdss_fb_ops = {
.owner = THIS_MODULE,
.fb_open = mdss_fb_open,
@@ -946,56 +1348,70 @@ static struct fb_ops mdss_fb_ops = {
.fb_blank = mdss_fb_blank, /* blank display */
.fb_pan_display = mdss_fb_pan_display, /* pan display */
.fb_ioctl = mdss_fb_ioctl, /* perform fb specific ioctl */
+#ifdef CONFIG_COMPAT
+ .fb_compat_ioctl = mdss_fb_compat_ioctl,
+#endif
.fb_mmap = mdss_fb_mmap,
};
static int mdss_fb_alloc_fbmem_iommu(struct msm_fb_data_type *mfd, int dom)
{
void *virt = NULL;
- unsigned long phys = 0;
+ phys_addr_t phys = 0;
size_t size = 0;
struct platform_device *pdev = mfd->pdev;
+ int rc = 0;
+ struct device_node *fbmem_pnode = NULL;
if (!pdev || !pdev->dev.of_node) {
pr_err("Invalid device node\n");
return -ENODEV;
}
- if (of_property_read_u32(pdev->dev.of_node,
- "qcom,memory-reservation-size",
- &size) || !size) {
+ fbmem_pnode = of_parse_phandle(pdev->dev.of_node,
+ "linux,contiguous-region", 0);
+ if (!fbmem_pnode) {
+ pr_debug("fbmem is not reserved for %s\n", pdev->name);
mfd->fbi->screen_base = NULL;
mfd->fbi->fix.smem_start = 0;
- mfd->fbi->fix.smem_len = 0;
return 0;
+ } else {
+ const u32 *addr;
+ u64 len;
+
+ addr = of_get_address(fbmem_pnode, 0, &len, NULL);
+ if (!addr) {
+ pr_err("fbmem size is not specified\n");
+ of_node_put(fbmem_pnode);
+ return -EINVAL;
+ }
+ size = (size_t)len;
+ of_node_put(fbmem_pnode);
}
- pr_info("%s frame buffer reserve_size=0x%x\n", __func__, size);
+ pr_debug("%s frame buffer reserve_size=0x%zx\n", __func__, size);
if (size < PAGE_ALIGN(mfd->fbi->fix.line_length *
mfd->fbi->var.yres_virtual))
pr_warn("reserve size is smaller than framebuffer size\n");
- virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+ virt = dma_alloc_coherent(&pdev->dev, size, &phys, GFP_KERNEL);
if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
+ pr_err("unable to alloc fbmem size=%zx\n", size);
return -ENOMEM;
}
- phys = memory_pool_node_paddr(virt);
-
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+ rc = msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
&mfd->iova);
- pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
- size, virt, phys, mfd->index);
+ if (rc)
+ pr_warn("Cannot map fb_mem %pa to IOMMU. rc=%d\n", &phys, rc);
+
+ pr_debug("alloc 0x%zxB @ (%pa phys) (0x%p virt) (%pa iova) for fb%d\n",
+ size, &phys, virt, &mfd->iova, mfd->index);
mfd->fbi->screen_base = virt;
mfd->fbi->fix.smem_start = phys;
mfd->fbi->fix.smem_len = size;
-#ifdef CONFIG_MACH_LGE
- msm_fb_phys_addr_backup = phys;
- memset(virt,0,size);
-#endif
return 0;
}
@@ -1003,9 +1419,9 @@ static int mdss_fb_alloc_fbmem_iommu(struct msm_fb_data_type *mfd, int dom)
static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
{
- if (mfd->mdp.fb_mem_alloc_fnc)
+ if (mfd->mdp.fb_mem_alloc_fnc) {
return mfd->mdp.fb_mem_alloc_fnc(mfd);
- else if (mfd->mdp.fb_mem_get_iommu_domain) {
+ } else if (mfd->mdp.fb_mem_get_iommu_domain) {
int dom = mfd->mdp.fb_mem_get_iommu_domain();
if (dom >= 0)
return mdss_fb_alloc_fbmem_iommu(mfd, dom);
@@ -1183,8 +1599,14 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd)
var->hsync_len = panel_info->lcdc.h_pulse_width;
var->pixclock = panel_info->clk_rate / 1000;
- /* id field for fb app */
+ /*
+ * Populate smem length here for uspace to get the
+ * Framebuffer size when FBIO_FSCREENINFO ioctl is
+ * called.
+ */
+ fix->smem_len = PAGE_ALIGN(fix->line_length * var->yres) * mfd->fb_page;
+ /* id field for fb app */
id = (int *)&mfd->panel;
snprintf(fix->id, sizeof(fix->id), "mdssfb_%x", (u32) *id);
@@ -1197,12 +1619,10 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd)
mfd->panel_power_on = false;
mfd->dcm_state = DCM_UNINIT;
- mdss_fb_parse_dt_split(mfd);
+ mdss_fb_parse_dt(mfd);
- if (mdss_fb_alloc_fbmem(mfd)) {
- pr_err("unable to allocate framebuffer memory\n");
- return -ENOMEM;
- }
+ if (mdss_fb_alloc_fbmem(mfd))
+ pr_warn("unable to allocate fb memory in fb register\n");
mfd->op_enable = true;
@@ -1211,16 +1631,22 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd)
mutex_init(&mfd->mdp_sync_pt_data.sync_mutex);
atomic_set(&mfd->mdp_sync_pt_data.commit_cnt, 0);
atomic_set(&mfd->commits_pending, 0);
+ atomic_set(&mfd->ioctl_ref_cnt, 0);
+ atomic_set(&mfd->kickoff_pending, 0);
init_timer(&mfd->no_update.timer);
mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
mfd->no_update.timer.data = (unsigned long)mfd;
+ mfd->update.ref_count = 0;
+ mfd->no_update.ref_count = 0;
init_completion(&mfd->update.comp);
init_completion(&mfd->no_update.comp);
init_completion(&mfd->power_off_comp);
init_completion(&mfd->power_set_comp);
init_waitqueue_head(&mfd->commit_wait_q);
init_waitqueue_head(&mfd->idle_wait_q);
+ init_waitqueue_head(&mfd->ioctl_q);
+ init_waitqueue_head(&mfd->kickoff_wait_q);
ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (ret)
@@ -1233,9 +1659,8 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd)
return -EPERM;
}
- pr_info("FrameBuffer[%d] %dx%d size=%d registered successfully!\n",
- mfd->index, fbi->var.xres, fbi->var.yres,
- fbi->fix.smem_len);
+ pr_info("FrameBuffer[%d] %dx%d registered successfully!\n", mfd->index,
+ fbi->var.xres, fbi->var.yres);
return 0;
}
@@ -1246,9 +1671,11 @@ static int mdss_fb_open(struct fb_info *info, int user)
struct mdss_fb_proc_info *pinfo = NULL;
int result;
int pid = current->tgid;
+ struct task_struct *task = current->group_leader;
if (mfd->shutdown_pending) {
- pr_err("Shutdown pending. Aborting operation\n");
+ pr_err("Shutdown pending. Aborting operation. Request from pid:%d name=%s\n",
+ pid, task->comm);
return -EPERM;
}
@@ -1331,6 +1758,12 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
return -EINVAL;
}
+ if (!wait_event_timeout(mfd->ioctl_q,
+ !atomic_read(&mfd->ioctl_ref_cnt) || !release_all,
+ msecs_to_jiffies(1000)))
+ pr_warn("fb%d ioctl could not finish. waited 1 sec.\n",
+ mfd->index);
+
mdss_fb_pan_idle(mfd);
pr_debug("release_all = %s\n", release_all ? "true" : "false");
@@ -1401,6 +1834,16 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
mfd->disp_thread = NULL;
}
+ if (mfd->mdp.release_fnc) {
+ ret = mfd->mdp.release_fnc(mfd, true);
+ if (ret)
+ pr_err("error fb%d release process %s pid=%d\n",
+ mfd->index, task->comm, pid);
+ }
+
+ if (mfd->fb_ion_handle)
+ mdss_fb_free_fb_ion_memory(mfd);
+
ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
mfd->op_enable);
if (ret) {
@@ -1408,6 +1851,7 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
mfd->index, ret, task->comm, pid);
return ret;
}
+ atomic_set(&mfd->ioctl_ref_cnt, 0);
}
return ret;
@@ -1608,6 +2052,25 @@ static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
return 0;
}
+static int mdss_fb_wait_for_kickoff(struct msm_fb_data_type *mfd)
+{
+ int ret = 0;
+
+ ret = wait_event_timeout(mfd->kickoff_wait_q,
+ (!atomic_read(&mfd->kickoff_pending) ||
+ mfd->shutdown_pending),
+ msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT / 2));
+ if (!ret) {
+ pr_err("wait for kickoff timeout %d pending=%d\n",
+ ret, atomic_read(&mfd->kickoff_pending));
+
+ } else if (mfd->shutdown_pending) {
+ pr_debug("Shutdown signalled\n");
+ return -EPERM;
+ }
+
+ return 0;
+}
static int mdss_fb_pan_display_ex(struct fb_info *info,
struct mdp_display_commit *disp_commit)
@@ -1617,7 +2080,11 @@ static int mdss_fb_pan_display_ex(struct fb_info *info,
u32 wait_for_finish = disp_commit->wait_for_finish;
int ret = 0;
- if (!mfd || (!mfd->op_enable) || (!mfd->panel_power_on))
+ if (!mfd || (!mfd->op_enable))
+ return -EPERM;
+
+ if ((!mfd->panel_power_on) && !((mfd->dcm_state == DCM_ENTER) &&
+ (mfd->panel.type == MIPI_CMD_PANEL)))
return -EPERM;
if (var->xoffset > (info->var.xres_virtual - info->var.xres))
@@ -1646,6 +2113,7 @@ static int mdss_fb_pan_display_ex(struct fb_info *info,
atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);
atomic_inc(&mfd->commits_pending);
+ atomic_inc(&mfd->kickoff_pending);
wake_up_all(&mfd->commit_wait_q);
mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
if (wait_for_finish)
@@ -1668,7 +2136,11 @@ static int mdss_fb_pan_display_sub(struct fb_var_screeninfo *var,
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if ((!mfd->op_enable) || (!mfd->panel_power_on))
+ if (!mfd->op_enable)
+ return -EPERM;
+
+ if ((!mfd->panel_power_on) && !((mfd->dcm_state == DCM_ENTER) &&
+ (mfd->panel.type == MIPI_CMD_PANEL)))
return -EPERM;
if (var->xoffset > (info->var.xres_virtual - info->var.xres))
@@ -1738,6 +2210,8 @@ static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd)
if (ret)
pr_err("pan display failed %x on fb%d\n", ret,
mfd->index);
+ atomic_set(&mfd->kickoff_pending, 0);
+ wake_up_all(&mfd->kickoff_wait_q);
}
if (!ret)
mdss_fb_update_backlight(mfd);
@@ -1761,7 +2235,7 @@ static int __mdss_fb_display_thread(void *data)
mfd->index);
while (1) {
- wait_event_interruptible(mfd->commit_wait_q,
+ wait_event(mfd->commit_wait_q,
(atomic_read(&mfd->commits_pending) ||
kthread_should_stop()));
@@ -1774,6 +2248,7 @@ static int __mdss_fb_display_thread(void *data)
}
atomic_set(&mfd->commits_pending, 0);
+ atomic_set(&mfd->kickoff_pending, 0);
wake_up_all(&mfd->idle_wait_q);
return ret;
@@ -1944,6 +2419,8 @@ static int mdss_fb_set_par(struct fb_info *info)
else
mfd->fbi->fix.line_length = var->xres * var->bits_per_pixel / 8;
+ mfd->fbi->fix.smem_len = mfd->fbi->fix.line_length *
+ mfd->fbi->var.yres_virtual;
if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
@@ -2233,6 +2710,28 @@ static int mdss_fb_display_commit(struct fb_info *info,
return ret;
}
+static int __ioctl_wait_idle(struct msm_fb_data_type *mfd, u32 cmd)
+{
+ int ret = 0;
+
+ if (mfd->wait_for_kickoff &&
+ ((cmd == MSMFB_OVERLAY_PREPARE) ||
+ (cmd == MSMFB_BUFFER_SYNC) ||
+ (cmd == MSMFB_OVERLAY_SET))) {
+ ret = mdss_fb_wait_for_kickoff(mfd);
+ } else if ((cmd != MSMFB_VSYNC_CTRL) &&
+ (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
+ (cmd != MSMFB_ASYNC_BLIT) &&
+ (cmd != MSMFB_BLIT) &&
+ (cmd != MSMFB_NOTIFY_UPDATE) &&
+ (cmd != MSMFB_OVERLAY_PREPARE)) {
+ ret = mdss_fb_pan_idle(mfd);
+ }
+
+ if (ret)
+ pr_debug("Shutdown pending. Aborting operation %x\n", cmd);
+ return ret;
+}
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
@@ -2243,25 +2742,25 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
int ret = -ENOSYS;
struct mdp_buf_sync buf_sync;
struct msm_sync_pt_data *sync_pt_data = NULL;
-#ifdef CONFIG_MACH_LGE
- u32 dsi_panel_invert = 0;
-#endif
+ unsigned int dsi_mode = 0;
if (!info || !info->par)
return -EINVAL;
+
mfd = (struct msm_fb_data_type *)info->par;
+ if (!mfd)
+ return -EINVAL;
+
+ if (mfd->shutdown_pending)
+ return -EPERM;
+
+ atomic_inc(&mfd->ioctl_ref_cnt);
+
mdss_fb_power_setting_idle(mfd);
- if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
- (cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT) &&
- (cmd != MSMFB_NOTIFY_UPDATE) &&
- (cmd != MSMFB_OVERLAY_PREPARE)) {
- ret = mdss_fb_pan_idle(mfd);
- if (ret) {
- pr_debug("Shutdown pending. Aborting operation %x\n",
- cmd);
- return ret;
- }
- }
+
+ ret = __ioctl_wait_idle(mfd, cmd);
+ if (ret)
+ goto exit;
switch (cmd) {
case MSMFB_CURSOR:
@@ -2278,15 +2777,19 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
ret = copy_to_user(argp, &fb_page_protection,
sizeof(fb_page_protection));
if (ret)
- return ret;
+ goto exit;
break;
case MSMFB_BUFFER_SYNC:
ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
if (ret)
- return ret;
- if ((!mfd->op_enable) || (!mfd->panel_power_on))
- return -EPERM;
+ goto exit;
+
+ if ((!mfd->op_enable) || (!mfd->panel_power_on)) {
+ ret = -EPERM;
+ goto exit;
+ }
+
if (mfd->mdp.get_sync_fnc)
sync_pt_data = mfd->mdp.get_sync_fnc(mfd, &buf_sync);
if (!sync_pt_data)
@@ -2306,14 +2809,15 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
ret = mdss_fb_display_commit(info, argp);
break;
-#ifdef CONFIG_MACH_LGE
- case MSMFB_INVERT_PANEL:
- ret = copy_from_user(&dsi_panel_invert, argp, sizeof(int));
- if(ret)
- return ret;
- ret = mdss_dsi_panel_invert(dsi_panel_invert);
- break;
-#endif
+ case MSMFB_LPM_ENABLE:
+ ret = copy_from_user(&dsi_mode, argp, sizeof(dsi_mode));
+ if (ret) {
+ pr_err("%s: MSMFB_LPM_ENABLE ioctl failed\n", __func__);
+ goto exit;
+ }
+
+ ret = mdss_fb_lpm_enable(mfd, dsi_mode);
+ break;
default:
if (mfd->mdp.ioctl_handler)
@@ -2324,6 +2828,10 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
if (ret == -ENOSYS)
pr_err("unsupported ioctl (%x)\n", cmd);
+exit:
+ if (!atomic_dec_return(&mfd->ioctl_ref_cnt))
+ wake_up_all(&mfd->ioctl_q);
+
return ret;
}
@@ -2359,13 +2867,6 @@ static int mdss_fb_register_extra_panel(struct platform_device *pdev,
return -EEXIST;
}
- if ((fb_pdata->panel_info.type != MIPI_VIDEO_PANEL) ||
- (pdata->panel_info.type != MIPI_VIDEO_PANEL)) {
- pr_err("Split panel not supported for panel type %d\n",
- pdata->panel_info.type);
- return -EINVAL;
- }
-
fb_pdata->next = pdata;
return 0;
@@ -2411,7 +2912,8 @@ int mdss_register_panel(struct platform_device *pdev,
pr_info("adding framebuffer device %s\n", dev_name(&pdev->dev));
fb_pdev = of_platform_device_create(node, NULL,
&mdss_pdev->dev);
- fb_pdev->dev.platform_data = pdata;
+ if (fb_pdev)
+ fb_pdev->dev.platform_data = pdata;
}
if (master_panel && mdp_instance->panel_register_done)
@@ -2440,7 +2942,7 @@ int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
struct fb_info *info;
struct msm_fb_data_type *mfd;
- if (fb_num > MAX_FBI_LIST)
+ if (fb_num >= MAX_FBI_LIST)
return -EINVAL;
info = fbi_list[fb_num];
@@ -2472,3 +2974,27 @@ int __init mdss_fb_init(void)
}
module_init(mdss_fb_init);
+
+int mdss_fb_suspres_panel(struct device *dev, void *data)
+{
+ struct msm_fb_data_type *mfd;
+ int rc;
+ u32 event;
+
+ if (!data) {
+ pr_err("Device state not defined\n");
+ return -EINVAL;
+ }
+ mfd = dev_get_drvdata(dev);
+ if (!mfd)
+ return 0;
+
+ event = *((bool *) data) ? MDSS_EVENT_RESUME : MDSS_EVENT_SUSPEND;
+
+ rc = mdss_fb_send_panel_event(mfd, event, NULL);
+ if (rc)
+ pr_warn("unable to %s fb%d (%d)\n",
+ event == MDSS_EVENT_RESUME ? "resume" : "suspend",
+ mfd->index, rc);
+ return rc;
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment