Created
March 23, 2015 22:34
-
-
Save invisiblek/d0ecab05688158d14e41 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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