Skip to content

Instantly share code, notes, and snippets.

@invisiblek
Created March 23, 2015 22:34
Show Gist options
  • Save invisiblek/d0ecab05688158d14e41 to your computer and use it in GitHub Desktop.
Save invisiblek/d0ecab05688158d14e41 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 93c43ed..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
@@ -53,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
@@ -106,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;
@@ -117,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)
{
@@ -132,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;
@@ -143,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);
}
}
@@ -234,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,
@@ -334,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,
@@ -347,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,
};
@@ -414,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;
@@ -424,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;
@@ -477,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;
@@ -491,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;
@@ -725,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 {
@@ -754,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);
/*
@@ -764,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;
}
}
}
@@ -785,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,
@@ -821,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 */
@@ -828,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:
@@ -840,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)
@@ -860,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);
@@ -876,28 +1048,19 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info)
mfd->suspend.panel_power_on = false;
return 0;
}
- return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
-}
+ pr_debug("mode: %d\n", blank_mode);
-/* Set VM page protection */
-static inline void __mdss_fb_set_page_protection(struct vm_area_struct *vma,
- struct msm_fb_data_type *mfd)
-{
- 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);
+ 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)
@@ -928,7 +1091,7 @@ void mdss_fb_free_fb_ion_memory(struct msm_fb_data_type *mfd)
}
mfd->fbi->screen_base = NULL;
- mfd->fbi->fix.smem_len = 0;
+ mfd->fbi->fix.smem_start = 0;
ion_unmap_kernel(mfd->fb_ion_client, mfd->fb_ion_handle);
@@ -998,6 +1161,7 @@ int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd, size_t 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;
@@ -1038,7 +1202,7 @@ static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
}
req_size = vma->vm_end - vma->vm_start;
- fb_size = mfd->fbi->fix.line_length * mfd->fbi->var.yres * MDSS_FB_NUM;
+ fb_size = mfd->fbi->fix.smem_len;
if (req_size > fb_size) {
pr_warn("requested map is greater than framebuffer");
return -EOVERFLOW;
@@ -1056,12 +1220,10 @@ static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
if (IS_ERR(table)) {
pr_err("Unable to get sg_table from ion:%ld\n", PTR_ERR(table));
mfd->fbi->screen_base = NULL;
- mfd->fbi->fix.smem_len = 0;
return PTR_ERR(table);
} else if (!table) {
pr_err("sg_list is NULL\n");
mfd->fbi->screen_base = NULL;
- mfd->fbi->fix.smem_len = 0;
return -EINVAL;
}
@@ -1069,21 +1231,24 @@ static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
if (page) {
for_each_sg(table->sgl, sg, table->nents, i) {
unsigned long remainder = vma->vm_end - addr;
- unsigned long len = sg_dma_len(sg);
+ unsigned long len = sg->length;
page = sg_page(sg);
- if (offset >= sg_dma_len(sg)) {
- offset -= sg_dma_len(sg);
+ if (offset >= sg->length) {
+ offset -= sg->length;
continue;
} else if (offset) {
page += offset / PAGE_SIZE;
- len = sg_dma_len(sg) - offset;
+ len = sg->length - offset;
offset = 0;
}
len = min(len, remainder);
- __mdss_fb_set_page_protection(vma, mfd);
+ 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);
@@ -1126,6 +1291,7 @@ static int mdss_fb_physical_mmap(struct fb_info *info,
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;
if (!start) {
pr_warn("No framebuffer memory is allocated\n");
@@ -1135,8 +1301,8 @@ static int mdss_fb_physical_mmap(struct fb_info *info,
/* 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)
@@ -1145,10 +1311,13 @@ static int mdss_fb_physical_mmap(struct fb_info *info,
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO;
+ if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
+ vma->vm_page_prot = pgprot_writecombine(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;
@@ -1205,7 +1374,6 @@ static int mdss_fb_alloc_fbmem_iommu(struct msm_fb_data_type *mfd, int dom)
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;
@@ -1431,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);
@@ -1445,7 +1619,7 @@ 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_warn("unable to allocate fb memory in fb register\n");
@@ -1463,6 +1637,8 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd)
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);
@@ -1495,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;
}
@@ -1902,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))
@@ -1954,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))
@@ -2049,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()));
@@ -2233,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);
@@ -2535,7 +2723,8 @@ static int __ioctl_wait_idle(struct msm_fb_data_type *mfd, u32 cmd)
(cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
(cmd != MSMFB_ASYNC_BLIT) &&
(cmd != MSMFB_BLIT) &&
- (cmd != MSMFB_NOTIFY_UPDATE)) {
+ (cmd != MSMFB_NOTIFY_UPDATE) &&
+ (cmd != MSMFB_OVERLAY_PREPARE)) {
ret = mdss_fb_pan_idle(mfd);
}
@@ -2553,9 +2742,7 @@ 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;
@@ -2622,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)
@@ -2679,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;
@@ -2731,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)
@@ -2760,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];
@@ -2792,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