summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/Kconfig2
-rw-r--r--drivers/video/fbdev/asiliantfb.c3
-rw-r--r--drivers/video/fbdev/chipsfb.c5
-rw-r--r--drivers/video/fbdev/core/fbcmap.c8
-rw-r--r--drivers/video/fbdev/core/fbmem.c13
-rw-r--r--drivers/video/fbdev/geode/video_gx.c2
-rw-r--r--drivers/video/fbdev/hgafb.c21
-rw-r--r--drivers/video/fbdev/hyperv_fb.c5
-rw-r--r--drivers/video/fbdev/imsttfb.c5
-rw-r--r--drivers/video/fbdev/kyro/fbdev.c8
-rw-r--r--drivers/video/fbdev/msm/Makefile2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c9
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_status.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c56
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_cec.c10
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c128
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c114
-rw-r--r--drivers/video/fbdev/msm/mdss_livedisplay.c653
-rw-r--r--drivers/video/fbdev/msm/mdss_livedisplay.h124
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_splash_logo.c7
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h5
-rw-r--r--drivers/video/fbdev/msm/mdss_util.c2
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c20
-rw-r--r--drivers/video/fbdev/neofb.c1
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.c2
-rw-r--r--drivers/video/fbdev/omap2/dss/omapdss-boot-init.c4
-rw-r--r--drivers/video/fbdev/pvr2fb.c2
-rw-r--r--drivers/video/fbdev/riva/fbdev.c3
-rw-r--r--drivers/video/fbdev/sis/init.c11
-rw-r--r--drivers/video/fbdev/sis/init301.c4
-rw-r--r--drivers/video/fbdev/sm712fb.c2
-rw-r--r--drivers/video/fbdev/vga16fb.c16
-rw-r--r--drivers/video/fbdev/w100fb.c2
39 files changed, 1194 insertions, 78 deletions
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 759aaeb6a196..a6c67e189efa 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1397,6 +1397,7 @@ config FB_ATY
select FB_CFB_IMAGEBLIT
select FB_BACKLIGHT if FB_ATY_BACKLIGHT
select FB_MACMODES if PPC
+ select FB_ATY_CT if SPARC64 && PCI
help
This driver supports graphics boards with the ATI Mach64 chips.
Say Y if you have such a graphics board.
@@ -1407,7 +1408,6 @@ config FB_ATY
config FB_ATY_CT
bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support"
depends on PCI && FB_ATY
- default y if SPARC64 && PCI
help
Say Y here to support use of ATI's 64-bit Rage boards (or other
boards based on the Mach64 CT, VT, GT, and LT chipsets) as a
diff --git a/drivers/video/fbdev/asiliantfb.c b/drivers/video/fbdev/asiliantfb.c
index 7e8ddf00ccc2..dbcc6ebaf904 100644
--- a/drivers/video/fbdev/asiliantfb.c
+++ b/drivers/video/fbdev/asiliantfb.c
@@ -227,6 +227,9 @@ static int asiliantfb_check_var(struct fb_var_screeninfo *var,
{
unsigned long Ftarget, ratio, remainder;
+ if (!var->pixclock)
+ return -EINVAL;
+
ratio = 1000000 / var->pixclock;
remainder = 1000000 % var->pixclock;
Ftarget = 1000000 * ratio + (1000000 * remainder) / var->pixclock;
diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c
index 59abdc6a97f6..84a3778552eb 100644
--- a/drivers/video/fbdev/chipsfb.c
+++ b/drivers/video/fbdev/chipsfb.c
@@ -332,7 +332,7 @@ static struct fb_var_screeninfo chipsfb_var = {
static void init_chips(struct fb_info *p, unsigned long addr)
{
- memset(p->screen_base, 0, 0x100000);
+ fb_memset(p->screen_base, 0, 0x100000);
p->fix = chipsfb_fix;
p->fix.smem_start = addr;
@@ -350,7 +350,7 @@ static void init_chips(struct fb_info *p, unsigned long addr)
static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
{
struct fb_info *p;
- unsigned long addr, size;
+ unsigned long addr;
unsigned short cmd;
int rc = -ENODEV;
@@ -362,7 +362,6 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
goto err_disable;
addr = pci_resource_start(dp, 0);
- size = pci_resource_len(dp, 0);
if (addr == 0)
goto err_disable;
diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c
index 1f8b480b1a4d..1555106ae38f 100644
--- a/drivers/video/fbdev/core/fbcmap.c
+++ b/drivers/video/fbdev/core/fbcmap.c
@@ -101,17 +101,17 @@ int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
if (!len)
return 0;
- cmap->red = kmalloc(size, flags);
+ cmap->red = kzalloc(size, flags);
if (!cmap->red)
goto fail;
- cmap->green = kmalloc(size, flags);
+ cmap->green = kzalloc(size, flags);
if (!cmap->green)
goto fail;
- cmap->blue = kmalloc(size, flags);
+ cmap->blue = kzalloc(size, flags);
if (!cmap->blue)
goto fail;
if (transp) {
- cmap->transp = kmalloc(size, flags);
+ cmap->transp = kzalloc(size, flags);
if (!cmap->transp)
goto fail;
} else {
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 4bb5d68189a0..cf533f1fa699 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -32,6 +32,7 @@
#include <linux/device.h>
#include <linux/efi.h>
#include <linux/fb.h>
+#include <linux/overflow.h>
#include <asm/fb.h>
@@ -981,6 +982,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
if ((var->activate & FB_ACTIVATE_FORCE) ||
memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
u32 activate = var->activate;
+ u32 unused;
/* When using FOURCC mode, make sure the red, green, blue and
* transp fields are set to 0.
@@ -1001,6 +1003,15 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
goto done;
}
+ /* bitfill_aligned() assumes that it's at least 8x8 */
+ if (var->xres < 8 || var->yres < 8)
+ return -EINVAL;
+
+ /* Too huge resolution causes multiplication overflow. */
+ if (check_mul_overflow(var->xres, var->yres, &unused) ||
+ check_mul_overflow(var->xres_virtual, var->yres_virtual, &unused))
+ return -EINVAL;
+
ret = info->fbops->fb_check_var(var, info);
if (ret)
@@ -1139,7 +1150,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
case FBIOGET_FSCREENINFO:
if (!lock_fb_info(info))
return -ENODEV;
- fix = info->fix;
+ memcpy(&fix, &info->fix, sizeof(fix));
unlock_fb_info(info);
ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
diff --git a/drivers/video/fbdev/geode/video_gx.c b/drivers/video/fbdev/geode/video_gx.c
index 6082f653c68a..67773e8bbb95 100644
--- a/drivers/video/fbdev/geode/video_gx.c
+++ b/drivers/video/fbdev/geode/video_gx.c
@@ -127,7 +127,7 @@ void gx_set_dclk_frequency(struct fb_info *info)
int timeout = 1000;
/* Rev. 1 Geode GXs use a 14 MHz reference clock instead of 48 MHz. */
- if (cpu_data(0).x86_mask == 1) {
+ if (cpu_data(0).x86_stepping == 1) {
pll_table = gx_pll_table_14MHz;
pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
} else {
diff --git a/drivers/video/fbdev/hgafb.c b/drivers/video/fbdev/hgafb.c
index 4a397c7c1b56..46ac8bbb376d 100644
--- a/drivers/video/fbdev/hgafb.c
+++ b/drivers/video/fbdev/hgafb.c
@@ -286,7 +286,7 @@ static int hga_card_detect(void)
hga_vram = ioremap(0xb0000, hga_vram_len);
if (!hga_vram)
- goto error;
+ return -ENOMEM;
if (request_region(0x3b0, 12, "hgafb"))
release_io_ports = 1;
@@ -346,13 +346,18 @@ static int hga_card_detect(void)
hga_type_name = "Hercules";
break;
}
- return 1;
+ return 0;
error:
if (release_io_ports)
release_region(0x3b0, 12);
if (release_io_port)
release_region(0x3bf, 1);
- return 0;
+
+ iounmap(hga_vram);
+
+ pr_err("hgafb: HGA card not detected.\n");
+
+ return -EINVAL;
}
/**
@@ -550,13 +555,11 @@ static struct fb_ops hgafb_ops = {
static int hgafb_probe(struct platform_device *pdev)
{
struct fb_info *info;
+ int ret;
- if (! hga_card_detect()) {
- printk(KERN_INFO "hgafb: HGA card not detected.\n");
- if (hga_vram)
- iounmap(hga_vram);
- return -EINVAL;
- }
+ ret = hga_card_detect();
+ if (ret)
+ return ret;
printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n",
hga_type_name, hga_vram_len/1024);
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index e2451bdb4525..883c06381e7c 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -712,7 +712,10 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
goto err1;
}
- fb_virt = ioremap(par->mem->start, screen_fb_size);
+ /*
+ * Map the VRAM cacheable for performance.
+ */
+ fb_virt = ioremap_wc(par->mem->start, screen_fb_size);
if (!fb_virt)
goto err2;
diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c
index 4994a540f680..9b167f7ef6c6 100644
--- a/drivers/video/fbdev/imsttfb.c
+++ b/drivers/video/fbdev/imsttfb.c
@@ -1517,11 +1517,6 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
info->fix.smem_start = addr;
info->screen_base = (__u8 *)ioremap(addr, par->ramdac == IBM ?
0x400000 : 0x800000);
- if (!info->screen_base) {
- release_mem_region(addr, size);
- framebuffer_release(info);
- return -ENOMEM;
- }
info->fix.mmio_start = addr + 0x800000;
par->dc_regs = ioremap(addr + 0x800000, 0x1000);
par->cmap_regs_phys = addr + 0x840000;
diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c
index 5bb01533271e..d98c3f5d80df 100644
--- a/drivers/video/fbdev/kyro/fbdev.c
+++ b/drivers/video/fbdev/kyro/fbdev.c
@@ -372,6 +372,11 @@ static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight
/* probably haven't called CreateOverlay yet */
return -EINVAL;
+ if (ulWidth == 0 || ulWidth == 0xffffffff ||
+ ulHeight == 0 || ulHeight == 0xffffffff ||
+ (x < 2 && ulWidth + 2 == 0))
+ return -EINVAL;
+
/* Stop Ramdac Output */
DisableRamdacOutput(deviceInfo.pSTGReg);
@@ -394,6 +399,9 @@ static int kyrofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct kyrofb_info *par = info->par;
+ if (!var->pixclock)
+ return -EINVAL;
+
if (var->bits_per_pixel != 16 && var->bits_per_pixel != 32) {
printk(KERN_WARNING "kyrofb: depth not supported: %u\n", var->bits_per_pixel);
return -EINVAL;
diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile
index e101b873f361..dfbc604dafa5 100644
--- a/drivers/video/fbdev/msm/Makefile
+++ b/drivers/video/fbdev/msm/Makefile
@@ -64,3 +64,5 @@ obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o mdss_util.o
obj-$(CONFIG_COMPAT) += mdss_compat_utils.o
+
+obj-$(CONFIG_FB_MSM_MDSS) += mdss_livedisplay.o
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index bffbb731dd4a..a201e272acbc 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -34,6 +34,7 @@
#include "mdss_debug.h"
#include "mdss_dsi_phy.h"
#include "mdss_dba_utils.h"
+#include "mdss_livedisplay.h"
#define CMDLINE_DSI_CTL_NUM_STRING_LEN 2
@@ -3112,6 +3113,9 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
rc);
}
break;
+ case MDSS_EVENT_UPDATE_LIVEDISPLAY:
+ rc = mdss_livedisplay_update(ctrl_pdata, (int)(unsigned long) arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index fd269d7baf09..1ab256cd08af 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -26,6 +26,7 @@
#include "mdss_dsi.h"
#include "mdss_dba_utils.h"
#include "mdss_debug.h"
+#include "mdss_livedisplay.h"
#define DT_CMD_HDR 6
#define DEFAULT_MDP_TRANSFER_TIME 14000
@@ -181,7 +182,7 @@ static void mdss_dsi_panel_apply_settings(struct mdss_dsi_ctrl_pdata *ctrl,
}
-static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl,
+void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_panel_cmds *pcmds, u32 flags)
{
struct dcs_cmd_req cmdreq;
@@ -959,6 +960,10 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
/* Ensure low persistence mode is set as before */
mdss_dsi_panel_apply_display_setting(pdata, pinfo->persist_mode);
+ if (pdata->event_handler)
+ pdata->event_handler(pdata, MDSS_EVENT_UPDATE_LIVEDISPLAY,
+ (void *)(unsigned long) MODE_UPDATE_ALL);
+
end:
pr_debug("%s:-\n", __func__);
return ret;
@@ -2979,6 +2984,8 @@ static int mdss_panel_parse_dt(struct device_node *np,
pinfo->esc_clk_rate_hz = MDSS_DSI_MAX_ESC_CLK_RATE_HZ;
pr_debug("%s: esc clk %d\n", __func__, pinfo->esc_clk_rate_hz);
+ mdss_livedisplay_parse_dt(np, pinfo);
+
return 0;
error:
diff --git a/drivers/video/fbdev/msm/mdss_dsi_status.c b/drivers/video/fbdev/msm/mdss_dsi_status.c
index 0f24f66dbcc6..64e9739a46f5 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_status.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_status.c
@@ -213,7 +213,8 @@ static int fb_event_callback(struct notifier_block *self,
return 0;
}
-static int param_dsi_status_disable(const char *val, struct kernel_param *kp)
+static int param_dsi_status_disable(const char *val,
+ const struct kernel_param *kp)
{
int ret = 0;
int int_val;
@@ -228,7 +229,7 @@ static int param_dsi_status_disable(const char *val, struct kernel_param *kp)
return ret;
}
-static int param_set_interval(const char *val, struct kernel_param *kp)
+static int param_set_interval(const char *val, const struct kernel_param *kp)
{
int ret = 0;
int int_val;
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index a7f21c3a4f18..64f86084b01d 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -56,6 +56,8 @@
#include "mdss_smmu.h"
#include "mdss_mdp.h"
+#include "mdss_livedisplay.h"
+
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
#define MDSS_FB_NUM 3
#else
@@ -518,12 +520,17 @@ static void __mdss_fb_idle_notify_work(struct work_struct *work)
/* Notify idle-ness here */
pr_debug("Idle timeout %dms expired!\n", mfd->idle_time);
- if (mfd->idle_time)
- sysfs_notify(&mfd->fbi->dev->kobj, NULL, "idle_notify");
+
mfd->idle_state = MDSS_FB_IDLE;
+ /*
+ * idle_notify node events are used to reduce MDP load when idle,
+ * this is not needed for command mode panels.
+ */
+ if (mfd->idle_time && mfd->panel.type != MIPI_CMD_PANEL)
+ sysfs_notify(&mfd->fbi->dev->kobj, NULL, "idle_notify");
+ sysfs_notify(&mfd->fbi->dev->kobj, NULL, "idle_state");
}
-
static ssize_t mdss_fb_get_fps_info(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -584,6 +591,26 @@ static ssize_t mdss_fb_get_idle_notify(struct device *dev,
return ret;
}
+static ssize_t mdss_fb_get_idle_state(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;
+ const char *state_strs[] = {
+ [MDSS_FB_NOT_IDLE] = "active",
+ [MDSS_FB_IDLE_TIMER_RUNNING] = "pending",
+ [MDSS_FB_IDLE] = "idle",
+ };
+ int state = mfd->idle_state;
+ const char *s;
+ if (state < ARRAY_SIZE(state_strs) && state_strs[state])
+ s = state_strs[state];
+ else
+ s = "invalid";
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
static ssize_t mdss_fb_get_panel_info(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -920,6 +947,7 @@ 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(idle_state, S_IRUGO, mdss_fb_get_idle_state, NULL);
static DEVICE_ATTR(msm_fb_panel_info, S_IRUGO, mdss_fb_get_panel_info, NULL);
static DEVICE_ATTR(msm_fb_src_split_info, S_IRUGO, mdss_fb_get_src_split_info,
NULL);
@@ -941,6 +969,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_idle_state.attr,
&dev_attr_msm_fb_panel_info.attr,
&dev_attr_msm_fb_src_split_info.attr,
&dev_attr_msm_fb_thermal_level.attr,
@@ -963,7 +992,7 @@ static int mdss_fb_create_sysfs(struct msm_fb_data_type *mfd)
rc = sysfs_create_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
if (rc)
pr_err("sysfs group creation failed, rc=%d\n", rc);
- return rc;
+ return mdss_livedisplay_create_sysfs(mfd);
}
static void mdss_fb_remove_sysfs(struct msm_fb_data_type *mfd)
@@ -1278,6 +1307,11 @@ static int mdss_fb_probe(struct platform_device *pdev)
mfd->index = fbi_list_index;
mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
+ if (!lcd_backlight_registered) {
+ backlight_led.brightness = mfd->panel_info->brightness_max;
+ backlight_led.max_brightness = mfd->panel_info->brightness_max;
+ }
+
mfd->ext_ad_ctrl = -1;
if (mfd->panel_info && mfd->panel_info->brightness_max > 0)
MDSS_BRIGHT_TO_BL(mfd->bl_level, backlight_led.brightness,
@@ -1344,8 +1378,6 @@ static int mdss_fb_probe(struct platform_device *pdev)
/* android supports only one lcd-backlight/lcd for now */
if (!lcd_backlight_registered) {
- backlight_led.brightness = mfd->panel_info->brightness_max;
- backlight_led.max_brightness = mfd->panel_info->brightness_max;
if (led_classdev_register(&pdev->dev, &backlight_led))
pr_err("led_classdev_register failed\n");
else
@@ -3131,14 +3163,18 @@ static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
ret = __mdss_fb_wait_for_fence_sub(sync_pt_data,
sync_pt_data->temp_fen, fence_cnt);
}
- if (mfd->idle_time && !mod_delayed_work(system_wq,
+ if (mfd->idle_time) {
+ if (!mod_delayed_work(system_wq,
&mfd->idle_notify_work,
msecs_to_jiffies(mfd->idle_time)))
- pr_debug("fb%d: restarted idle work\n",
- mfd->index);
+ pr_debug("fb%d: restarted idle work\n",
+ mfd->index);
+ mfd->idle_state = MDSS_FB_IDLE_TIMER_RUNNING;
+ } else {
+ mfd->idle_state = MDSS_FB_IDLE;
+ }
if (ret == -ETIME)
ret = NOTIFY_BAD;
- mfd->idle_state = MDSS_FB_IDLE_TIMER_RUNNING;
break;
case MDP_NOTIFY_FRAME_FLUSHED:
pr_debug("%s: frame flushed\n", sync_pt_data->fence_name);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_cec.c b/drivers/video/fbdev/msm/mdss_hdmi_cec.c
index 12a9267f3749..5fe3f710c29e 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_cec.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_cec.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2017, 2020 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2017,2020-2021, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -469,8 +469,12 @@ static int hdmi_cec_enable(void *input, bool enable)
}
if (enable) {
- /* 19.2Mhz * 0.00005 us = 950 = 0x3B6 */
- DSS_REG_W(io, HDMI_CEC_REFTIMER, (0x3B6 & 0xFFF) | BIT(16));
+ /*
+ * 19.2Mhz * 0.00005 us = 960 = 0x3C0
+ * CEC Rd/Wr logic is properly working with
+ * finetuned value of 0x3D4 = 51 us.
+ */
+ DSS_REG_W(io, HDMI_CEC_REFTIMER, (0x3D4 & 0xFFF) | BIT(16));
hdmi_hw_version = DSS_REG_R(io, HDMI_VERSION);
if (hdmi_hw_version >= CEC_SUPPORTED_HW_VERSION) {
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index 6f0234500d70..5095f4ae49b5 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -65,6 +65,11 @@
#define EDID_VENDOR_ID_SIZE 4
#define EDID_IEEE_REG_ID 0x0c03
+enum edid_screen_orientation {
+ LANDSCAPE = 1,
+ PORTRAIT = 2,
+};
+
enum edid_sink_mode {
SINK_MODE_DVI,
SINK_MODE_HDMI
@@ -143,6 +148,8 @@ struct hdmi_edid_ctrl {
u8 cea_blks;
/* DC: MSB -> LSB: Y420_48|Y420_36|Y420_30|RGB48|RGB36|RGB30|Y444 */
u8 deep_color;
+ u8 physical_width;
+ u8 physical_height;
u16 physical_address;
u32 video_resolution; /* selected by user */
u32 sink_mode; /* HDMI or DVI */
@@ -167,6 +174,9 @@ struct hdmi_edid_ctrl {
bool y420_cmdb_supports_all;
struct hdmi_edid_y420_cmdb y420_cmdb;
+ enum edid_screen_orientation orientation;
+ enum aspect_ratio aspect_ratio;
+
struct hdmi_edid_sink_data sink_data;
struct hdmi_edid_init_data init_data;
struct hdmi_edid_sink_caps sink_caps;
@@ -254,6 +264,11 @@ int hdmi_edid_reset_parser(void *input)
edid_ctrl->y420_cmdb_supports_all = false;
kfree(edid_ctrl->y420_cmdb.vic_list);
memset(&edid_ctrl->y420_cmdb, 0, sizeof(edid_ctrl->y420_cmdb));
+
+ edid_ctrl->physical_width = 0;
+ edid_ctrl->physical_height = 0;
+ edid_ctrl->orientation = 0;
+ edid_ctrl->aspect_ratio = HDMI_RES_AR_INVALID;
return 0;
}
@@ -449,6 +464,30 @@ static ssize_t hdmi_edid_sysfs_rda_modes(struct device *dev,
static DEVICE_ATTR(edid_modes, S_IRUGO | S_IWUSR, hdmi_edid_sysfs_rda_modes,
hdmi_edid_sysfs_wta_modes);
+static ssize_t hdmi_edid_sysfs_rda_screen_size(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ struct hdmi_edid_ctrl *edid_ctrl = hdmi_edid_get_ctrl(dev);
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d",
+ (edid_ctrl->physical_width * 10));
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, " %d",
+ (edid_ctrl->physical_height * 10));
+
+ DEV_DBG("%s: '%s'\n", __func__, buf);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
+
+ return ret;
+} /* hdmi_edid_sysfs_rda_screen_size */
+static DEVICE_ATTR(edid_screen_size, S_IRUGO, hdmi_edid_sysfs_rda_screen_size,
+ NULL);
+
static ssize_t hdmi_edid_sysfs_rda_res_info_data(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -855,6 +894,7 @@ static DEVICE_ATTR(hdr_data, S_IRUGO, hdmi_edid_sysfs_rda_hdr_data, NULL);
static struct attribute *hdmi_edid_fs_attrs[] = {
&dev_attr_edid_modes.attr,
+ &dev_attr_edid_screen_size.attr,
&dev_attr_pa.attr,
&dev_attr_scan_info.attr,
&dev_attr_edid_3d_modes.attr,
@@ -1515,6 +1555,68 @@ static u32 hdmi_edid_extract_ieee_reg_id(struct hdmi_edid_ctrl *edid_ctrl,
return ((u32)vsd[3] << 16) + ((u32)vsd[2] << 8) + (u32)vsd[1];
} /* hdmi_edid_extract_ieee_reg_id */
+static void hdmi_edid_extract_bdpf(struct hdmi_edid_ctrl *edid_ctrl)
+{
+ u8 *edid_buf = NULL;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ edid_buf = edid_ctrl->edid_buf;
+ if (edid_buf[21] && edid_buf[22]) {
+ edid_ctrl->physical_width = edid_buf[21];
+ edid_ctrl->physical_height = edid_buf[22];
+
+ DEV_DBG("%s: EDID: Horizontal Screen Size = %d cm\n",
+ __func__, edid_ctrl->physical_width);
+ DEV_DBG("%s: EDID: Vertical Screen Size = %d cm\n",
+ __func__, edid_ctrl->physical_height);
+ } else if (edid_buf[21]) {
+ edid_ctrl->orientation = LANDSCAPE;
+ switch (edid_buf[21]) {
+ case 0x4F:
+ edid_ctrl->aspect_ratio = HDMI_RES_AR_16_9;
+ break;
+ case 0x3D:
+ edid_ctrl->aspect_ratio = HDMI_RES_AR_16_10;
+ break;
+ case 0x22:
+ edid_ctrl->aspect_ratio = HDMI_RES_AR_4_3;
+ break;
+ case 0x1A:
+ edid_ctrl->aspect_ratio = HDMI_RES_AR_5_4;
+ break;
+ }
+ DEV_DBG("%s: EDID: Landscape Aspect Ratio = %d\n",
+ __func__, edid_ctrl->aspect_ratio);
+ } else if (edid_buf[22]) {
+ edid_ctrl->orientation = PORTRAIT;
+ switch (edid_buf[22]) {
+ case 0x4F:
+ edid_ctrl->aspect_ratio = HDMI_RES_AR_16_9;
+ break;
+ case 0x3D:
+ edid_ctrl->aspect_ratio = HDMI_RES_AR_16_10;
+ break;
+ case 0x22:
+ edid_ctrl->aspect_ratio = HDMI_RES_AR_4_3;
+ break;
+ case 0x1A:
+ edid_ctrl->aspect_ratio = HDMI_RES_AR_5_4;
+ break;
+ }
+ DEV_DBG("%s: EDID: Portrait Aspect Ratio = %d\n",
+ __func__, edid_ctrl->aspect_ratio);
+ } else {
+ pr_debug("%s: Undefined Screen size/Aspect ratio\n", __func__);
+ edid_ctrl->orientation = 0;
+ edid_ctrl->physical_width = 0;
+ edid_ctrl->physical_height = 0;
+ }
+}
+
static void hdmi_edid_extract_vendor_id(struct hdmi_edid_ctrl *edid_ctrl)
{
char *vendor_id;
@@ -2462,6 +2564,8 @@ int hdmi_edid_parser(void *input)
hdmi_edid_extract_vendor_id(edid_ctrl);
+ hdmi_edid_extract_bdpf(edid_ctrl);
+
/* EDID_CEA_EXTENSION_FLAG[0x7E] - CEC extension byte */
num_of_cea_blocks = edid_buf[EDID_BLOCK_SIZE - 2];
DEV_DBG("%s: No. of CEA/Extended EDID blocks is [%u]\n", __func__,
@@ -2914,6 +3018,30 @@ bool hdmi_edid_is_audio_supported(void *input)
return (edid_ctrl->basic_audio_supp || edid_ctrl->adb_size);
}
+u32 hdmi_edid_get_phys_width(void *input)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid edid_ctrl data\n", __func__);
+ return 0;
+ }
+
+ return (u32)edid_ctrl->physical_width * 10; /* return in mm */
+}
+
+u32 hdmi_edid_get_phys_height(void *input)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid edid_ctrl data\n", __func__);
+ return 0;
+ }
+
+ return (u32)edid_ctrl->physical_height * 10; /* return in mm */
+}
+
void hdmi_edid_deinit(void *input)
{
struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
index d258aa9f95bc..9b3b5fa952b4 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
@@ -94,5 +94,7 @@ void hdmi_edid_set_max_pclk_rate(void *input, u32 max_pclk_khz);
bool hdmi_edid_is_audio_supported(void *input);
u32 hdmi_edid_get_sink_caps_max_tmds_clk(void *input);
u8 hdmi_edid_get_colorimetry(void *input);
+u32 hdmi_edid_get_phys_width(void *input);
+u32 hdmi_edid_get_phys_height(void *input);
#endif /* __HDMI_EDID_H__ */
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index 747c245bf78e..e0fcfec614b5 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -23,6 +23,7 @@
#include <linux/hdcp_qseecom.h>
#include <linux/msm_mdp.h>
#include <linux/msm_ext_display.h>
+#include <linux/hdmi.h>
#define REG_DUMP 0
@@ -3038,6 +3039,96 @@ static void hdmi_tx_phy_reset(struct hdmi_tx_ctrl *hdmi_ctrl)
DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET_PLL);
} /* hdmi_tx_phy_reset */
+static u8 calc_infoframe_checksum(u8 *ptr, size_t size)
+{
+ u8 csum = 0;
+ size_t i;
+
+ /* compute checksum */
+ for (i = 0; i < size; i++)
+ csum += ptr[i];
+
+ return 256 - csum;
+}
+
+static u8 hdmi_panel_set_hdr_checksum(struct mdp_hdr_stream *hdr_meta)
+{
+ u8 *buff;
+ u8 *ptr;
+ u32 length;
+ u32 size;
+ u32 checksum = 0;
+ u32 const type_code = 0x87;
+ u32 const version = 0x01;
+ u32 const descriptor_id = 0x00;
+
+ /* length of metadata is 26 bytes */
+ length = 0x1a;
+ /* add 4 bytes for the header */
+ size = length + HDMI_INFOFRAME_HEADER_SIZE;
+
+ buff = kzalloc(size, GFP_KERNEL);
+
+ if (!buff) {
+ DEV_ERR("invalid buff\n");
+ goto err_alloc;
+ }
+
+ ptr = buff;
+
+ buff[0] = type_code;
+ buff[1] = version;
+ buff[2] = length;
+ buff[3] = 0;
+ /* start infoframe payload */
+ buff += HDMI_INFOFRAME_HEADER_SIZE;
+
+ buff[0] = hdr_meta->eotf;
+ buff[1] = descriptor_id;
+
+ buff[2] = hdr_meta->display_primaries_x[0] & 0xff;
+ buff[3] = hdr_meta->display_primaries_x[0] >> 8;
+
+ buff[4] = hdr_meta->display_primaries_x[1] & 0xff;
+ buff[5] = hdr_meta->display_primaries_x[1] >> 8;
+
+ buff[6] = hdr_meta->display_primaries_x[2] & 0xff;
+ buff[7] = hdr_meta->display_primaries_x[2] >> 8;
+
+ buff[8] = hdr_meta->display_primaries_y[0] & 0xff;
+ buff[9] = hdr_meta->display_primaries_y[0] >> 8;
+
+ buff[10] = hdr_meta->display_primaries_y[1] & 0xff;
+ buff[11] = hdr_meta->display_primaries_y[1] >> 8;
+
+ buff[12] = hdr_meta->display_primaries_y[2] & 0xff;
+ buff[13] = hdr_meta->display_primaries_y[2] >> 8;
+
+ buff[14] = hdr_meta->white_point_x & 0xff;
+ buff[15] = hdr_meta->white_point_x >> 8;
+ buff[16] = hdr_meta->white_point_y & 0xff;
+ buff[17] = hdr_meta->white_point_y >> 8;
+
+ buff[18] = hdr_meta->max_luminance & 0xff;
+ buff[19] = hdr_meta->max_luminance >> 8;
+
+ buff[20] = hdr_meta->min_luminance & 0xff;
+ buff[21] = hdr_meta->min_luminance >> 8;
+
+ buff[22] = hdr_meta->max_content_light_level & 0xff;
+ buff[23] = hdr_meta->max_content_light_level >> 8;
+
+ buff[24] = hdr_meta->max_average_light_level & 0xff;
+ buff[25] = hdr_meta->max_average_light_level >> 8;
+
+ checksum = calc_infoframe_checksum(ptr, size);
+
+ kfree(ptr);
+
+err_alloc:
+ return checksum;
+}
+
static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl)
{
u32 packet_payload = 0;
@@ -3047,8 +3138,10 @@ static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl)
u32 const version = 0x01;
u32 const length = 0x1a;
u32 const descriptor_id = 0x00;
+ u8 checksum = 0;
struct dss_io_data *io = NULL;
+
if (!ctrl) {
pr_err("%s: invalid input\n", __func__);
return;
@@ -3069,7 +3162,18 @@ static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl)
packet_header = type_code | (version << 8) | (length << 16);
DSS_REG_W(io, HDMI_GENERIC0_HDR, packet_header);
- packet_payload = (ctrl->hdr_ctrl.hdr_stream.eotf << 8);
+ /**
+ * Checksum is not a mandatory field for
+ * the HDR infoframe as per CEA-861-3 specification.
+ * However some HDMI sinks still expect a
+ * valid checksum to be included as part of
+ * the infoframe. Hence compute and add
+ * the checksum to improve sink interoperability
+ * for our HDR solution on HDMI.
+ */
+ checksum = hdmi_panel_set_hdr_checksum(&ctrl->hdr_ctrl.hdr_stream);
+
+ packet_payload = ((ctrl->hdr_ctrl.hdr_stream.eotf << 8) | checksum);
if (hdmi_tx_metadata_type_one(ctrl)) {
packet_payload |=
(descriptor_id << 16)
@@ -3432,6 +3536,9 @@ static int hdmi_tx_power_off(struct hdmi_tx_ctrl *hdmi_ctrl)
hdmi_ctrl->panel_power_on = false;
hdmi_ctrl->vic = 0;
+ hdmi_ctrl->use_bt2020 = false;
+ hdmi_ctrl->curr_hdr_state = HDR_DISABLE;
+
if (hdmi_ctrl->hpd_off_pending || hdmi_ctrl->panel_suspend)
hdmi_tx_hpd_off(hdmi_ctrl);
@@ -4125,6 +4232,7 @@ sysfs_err:
static int hdmi_tx_evt_handle_check_param(struct hdmi_tx_ctrl *hdmi_ctrl)
{
struct mdss_panel_info *pinfo = &hdmi_ctrl->panel_data.panel_info;
+ void *data = NULL;
int new_vic = -1;
int rc = 0;
@@ -4136,6 +4244,10 @@ static int hdmi_tx_evt_handle_check_param(struct hdmi_tx_ctrl *hdmi_ctrl)
goto end;
}
+ data = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
+ pinfo->physical_width = hdmi_edid_get_phys_width(data);
+ pinfo->physical_height = hdmi_edid_get_phys_height(data);
+
/*
* return value of 1 lets mdss know that panel
* needs a reconfig due to new resolution and
diff --git a/drivers/video/fbdev/msm/mdss_livedisplay.c b/drivers/video/fbdev/msm/mdss_livedisplay.c
new file mode 100644
index 000000000000..32f010b6b64a
--- /dev/null
+++ b/drivers/video/fbdev/msm/mdss_livedisplay.c
@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) 2015 The CyanogenMod Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "mdss_dsi.h"
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+#include "mdss_mdp_pp.h"
+#include "mdss_livedisplay.h"
+
+/*
+ * LiveDisplay is the display management service in CyanogenMod. It uses
+ * various capabilities of the hardware and software in order to
+ * optimize the experience for ambient conditions and time of day.
+ *
+ * This module is initialized by mdss_fb for each panel, and creates
+ * several new controls in /sys/class/graphics/fbX based on the
+ * configuration in the devicetree.
+ *
+ * cabc: Content Adaptive Backlight Control. Must be configured
+ * in the panel devicetree. Up to three levels.
+ * sre: Sunlight Readability Enhancement. Must be configured in
+ * the panel devicetree. Up to three levels.
+ * aco: Automatic Contrast Optimization. Must be configured in
+ * the panel devicetree. Boolean.
+ *
+ * hbm: High Brightness Mode. Common for OLED panels. Boolean.
+ *
+ * preset: Arbitrary DSI commands, up to 10 may be configured.
+ * Useful for gamma calibration.
+ *
+ * color_enhance: Hardware color enhancement. Must be configured
+ * in the panel devicetree. Boolean.
+ */
+
+extern void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_panel_cmds *pcmds, u32 flags);
+
+static int parse_dsi_cmds(struct mdss_livedisplay_ctx *mlc,
+ struct dsi_panel_cmds *pcmds, const uint8_t *cmd, int blen)
+{
+ int len;
+ char *buf, *bp;
+ struct dsi_ctrl_hdr *dchdr;
+ int i, cnt;
+
+ buf = kzalloc(blen, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, cmd, blen);
+
+ /* scan dcs commands */
+ bp = buf;
+ len = blen;
+ cnt = 0;
+ while (len >= sizeof(*dchdr)) {
+ dchdr = (struct dsi_ctrl_hdr *)bp;
+ dchdr->dlen = ntohs(dchdr->dlen);
+ if (dchdr->dlen > len) {
+ pr_err("%s: dtsi cmd=%x error, len=%d\n",
+ __func__, dchdr->dtype, dchdr->dlen);
+ goto exit_free;
+ }
+ bp += sizeof(*dchdr);
+ len -= sizeof(*dchdr);
+ bp += dchdr->dlen;
+ len -= dchdr->dlen;
+ cnt++;
+ }
+
+ if (len != 0) {
+ pr_err("%s: dcs_cmd=%x len=%d error!\n",
+ __func__, buf[0], blen);
+ goto exit_free;
+ }
+
+ pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc),
+ GFP_KERNEL);
+ if (!pcmds->cmds)
+ goto exit_free;
+
+ pcmds->cmd_cnt = cnt;
+ pcmds->buf = buf;
+ pcmds->blen = blen;
+
+ bp = buf;
+ len = blen;
+ for (i = 0; i < cnt; i++) {
+ dchdr = (struct dsi_ctrl_hdr *)bp;
+ len -= sizeof(*dchdr);
+ bp += sizeof(*dchdr);
+ pcmds->cmds[i].dchdr = *dchdr;
+ pcmds->cmds[i].payload = bp;
+ bp += dchdr->dlen;
+ len -= dchdr->dlen;
+ }
+
+ pcmds->link_state = mlc->link_state;
+
+ pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__,
+ pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
+
+ return 0;
+
+exit_free:
+ kfree(buf);
+ return -ENOMEM;
+}
+
+/*
+ * Update all or a subset of parameters
+ */
+int mdss_livedisplay_update(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+ int types)
+{
+ int ret = 0;
+ struct mdss_panel_info *pinfo = NULL;
+ struct mdss_livedisplay_ctx *mlc = NULL;
+ unsigned int len = 0, dlen = 0;
+ struct dsi_panel_cmds dsi_cmds;
+ uint8_t cabc_value = 0;
+ uint8_t *cmd_buf;
+
+ if (ctrl_pdata == NULL)
+ return -ENODEV;
+
+ pinfo = &(ctrl_pdata->panel_data.panel_info);
+ if (pinfo == NULL)
+ return -ENODEV;
+
+ mlc = pinfo->livedisplay;
+ if (mlc == NULL)
+ return -ENODEV;
+
+ if (!mlc->caps || !mdss_panel_is_power_on_interactive(pinfo->panel_power_state))
+ return 0;
+
+ // First find the length of the command array
+ if ((mlc->caps & MODE_PRESET) && (types & MODE_PRESET))
+ len += mlc->presets_len[mlc->preset];
+
+ if ((mlc->caps & MODE_COLOR_ENHANCE) && (types & MODE_COLOR_ENHANCE))
+ len += mlc->ce_enabled ? mlc->ce_on_cmds_len : mlc->ce_off_cmds_len;
+
+ if ((mlc->caps & MODE_HIGH_BRIGHTNESS) && (types & MODE_HIGH_BRIGHTNESS))
+ len += mlc->hbm_enabled ? mlc->hbm_on_cmds_len : mlc->hbm_off_cmds_len;
+
+ if (is_cabc_cmd(types) && is_cabc_cmd(mlc->caps)) {
+
+ // The CABC command on most modern panels is also responsible for
+ // other features such as SRE and ACO. The register fields are bits
+ // and are OR'd together and sent in a single DSI command.
+ if (mlc->cabc_level == CABC_UI) {
+ if (mlc->unified_cabc_cmds)
+ cabc_value |= mlc->cabc_ui_value;
+ else
+ len += mlc->cabc_ui_cmds_len;
+ } else if (mlc->cabc_level == CABC_IMAGE) {
+ if (mlc->unified_cabc_cmds)
+ cabc_value |= mlc->cabc_image_value;
+ else
+ len += mlc->cabc_image_cmds_len;
+ } else if (mlc->cabc_level == CABC_VIDEO) {
+ if (mlc->unified_cabc_cmds)
+ cabc_value |= mlc->cabc_video_value;
+ else
+ len += mlc->cabc_video_cmds_len;
+ }
+
+ if (mlc->sre_level == SRE_WEAK)
+ cabc_value |= mlc->sre_weak_value;
+ else if (mlc->sre_level == SRE_MEDIUM)
+ cabc_value |= mlc->sre_medium_value;
+ else if (mlc->sre_level == SRE_STRONG)
+ cabc_value |= mlc->sre_strong_value;
+
+ if (mlc->aco_enabled)
+ cabc_value |= mlc->aco_value;
+
+ if (cabc_value || mlc->cabc_level == CABC_OFF)
+ len += mlc->cabc_cmds_len;
+
+ pr_debug("%s cabc=%d sre=%d aco=%d cmd=%d\n", __func__,
+ mlc->cabc_level, mlc->sre_level, mlc->aco_enabled,
+ cabc_value);
+ }
+
+ len += mlc->post_cmds_len;
+
+ if (len == 0)
+ return 0;
+
+ memset(&dsi_cmds, 0, sizeof(struct dsi_panel_cmds));
+ cmd_buf = kzalloc(len + 1, GFP_KERNEL);
+ if (!cmd_buf)
+ return -ENOMEM;
+
+ // Build the command as a single chain, preset first
+ if ((mlc->caps & MODE_PRESET) && (types & MODE_PRESET)) {
+ memcpy(cmd_buf, mlc->presets[mlc->preset], mlc->presets_len[mlc->preset]);
+ dlen += mlc->presets_len[mlc->preset];
+ }
+
+ // Color enhancement
+ if ((mlc->caps & MODE_COLOR_ENHANCE) && (types & MODE_COLOR_ENHANCE)) {
+ if (mlc->ce_enabled) {
+ memcpy(cmd_buf + dlen, mlc->ce_on_cmds, mlc->ce_on_cmds_len);
+ dlen += mlc->ce_on_cmds_len;
+ } else {
+ memcpy(cmd_buf + dlen, mlc->ce_off_cmds, mlc->ce_off_cmds_len);
+ dlen += mlc->ce_off_cmds_len;
+ }
+ }
+
+ // High brightness mode
+ if ((mlc->caps & MODE_HIGH_BRIGHTNESS) && (types & MODE_HIGH_BRIGHTNESS)) {
+ if (mlc->hbm_enabled) {
+ memcpy(cmd_buf + dlen, mlc->hbm_on_cmds, mlc->hbm_on_cmds_len);
+ dlen += mlc->hbm_on_cmds_len;
+ } else {
+ memcpy(cmd_buf + dlen, mlc->hbm_off_cmds, mlc->hbm_off_cmds_len);
+ dlen += mlc->hbm_off_cmds_len;
+ }
+ }
+
+ // CABC/SRE/ACO features
+ if (is_cabc_cmd(types) && mlc->cabc_cmds_len) {
+ if (cabc_value || mlc->cabc_level == CABC_OFF) {
+ memcpy(cmd_buf + dlen, mlc->cabc_cmds, mlc->cabc_cmds_len);
+ dlen += mlc->cabc_cmds_len;
+ // The CABC command parameter is the last value in the sequence
+ cmd_buf[dlen - 1] = cabc_value;
+ }
+
+ if (!mlc->unified_cabc_cmds) {
+ if (mlc->cabc_level == CABC_UI && mlc->cabc_ui_cmds_len) {
+ memcpy(cmd_buf + dlen, mlc->cabc_ui_cmds, mlc->cabc_ui_cmds_len);
+ dlen += mlc->cabc_ui_cmds_len;
+ } else if (mlc->cabc_level == CABC_IMAGE && mlc->cabc_image_cmds_len) {
+ memcpy(cmd_buf + dlen, mlc->cabc_image_cmds, mlc->cabc_image_cmds_len);
+ dlen += mlc->cabc_image_cmds_len;
+ } else if (mlc->cabc_level == CABC_VIDEO && mlc->cabc_video_cmds_len) {
+ memcpy(cmd_buf + dlen, mlc->cabc_video_cmds, mlc->cabc_video_cmds_len);
+ dlen += mlc->cabc_video_cmds_len;
+ }
+ }
+ }
+
+ // And the post_cmd, can be used to turn on the panel
+ if (mlc->post_cmds_len) {
+ memcpy(cmd_buf + dlen, mlc->post_cmds, mlc->post_cmds_len);
+ dlen += mlc->post_cmds_len;
+ }
+
+ // Parse the command and send it
+ ret = parse_dsi_cmds(mlc, &dsi_cmds, (const uint8_t *)cmd_buf, len);
+ if (ret == 0) {
+ mdss_dsi_panel_cmds_send(ctrl_pdata, &dsi_cmds,
+ CMD_REQ_COMMIT | CMD_CLK_CTRL);
+ kfree(dsi_cmds.buf);
+ kfree(dsi_cmds.cmds);
+ } else {
+ pr_err("%s: error parsing DSI command! ret=%d", __func__, ret);
+ }
+
+ kfree(cmd_buf);
+
+ return ret;
+}
+
+int mdss_livedisplay_event(struct msm_fb_data_type *mfd, int types)
+{
+ int rc = 0;
+ struct mdss_panel_data *pdata;
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+ if (!pdata)
+ return -ENODEV;
+
+ do {
+ if (pdata->event_handler)
+ rc = pdata->event_handler(pdata, MDSS_EVENT_UPDATE_LIVEDISPLAY,
+ (void *)(unsigned long) types);
+
+ pdata = pdata->next;
+ } while (!rc && pdata);
+
+ return rc;
+}
+
+static ssize_t mdss_livedisplay_get_cabc(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ return sprintf(buf, "%d\n", mlc->cabc_level);
+}
+
+static ssize_t mdss_livedisplay_set_cabc(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int level = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ sscanf(buf, "%du", &level);
+ if (level >= CABC_OFF && level < CABC_MAX &&
+ level != mlc->cabc_level) {
+ mlc->cabc_level = level;
+ mdss_livedisplay_event(mfd, MODE_CABC);
+ }
+
+ return count;
+}
+
+static ssize_t mdss_livedisplay_get_sre(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ return sprintf(buf, "%d\n", mlc->sre_level);
+}
+
+static ssize_t mdss_livedisplay_set_sre(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int level = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ sscanf(buf, "%du", &level);
+ if (level >= SRE_OFF && level < SRE_MAX &&
+ level != mlc->sre_level) {
+ mlc->sre_level = level;
+ mdss_livedisplay_event(mfd, MODE_SRE);
+ }
+
+ return count;
+}
+
+static ssize_t mdss_livedisplay_get_hbm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ return sprintf(buf, "%d\n", mlc->hbm_enabled);
+}
+
+static ssize_t mdss_livedisplay_set_hbm(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ sscanf(buf, "%du", &value);
+ if ((value == 0 || value == 1)
+ && value != mlc->hbm_enabled) {
+ mlc->hbm_enabled = value;
+ mdss_livedisplay_event(mfd, MODE_HIGH_BRIGHTNESS);
+ }
+
+ return count;
+}
+
+static ssize_t mdss_livedisplay_get_color_enhance(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ return sprintf(buf, "%d\n", mlc->ce_enabled);
+}
+
+static ssize_t mdss_livedisplay_set_color_enhance(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ sscanf(buf, "%du", &value);
+ if ((value == 0 || value == 1)
+ && value != mlc->ce_enabled) {
+ mlc->ce_enabled = value;
+ mdss_livedisplay_event(mfd, MODE_COLOR_ENHANCE);
+ }
+
+ return count;
+}
+
+static ssize_t mdss_livedisplay_get_aco(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ return sprintf(buf, "%d\n", mlc->aco_enabled);
+}
+
+static ssize_t mdss_livedisplay_set_aco(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ sscanf(buf, "%du", &value);
+ if ((value == 0 || value == 1)
+ && value != mlc->aco_enabled) {
+ mlc->aco_enabled = value;
+ mdss_livedisplay_event(mfd, MODE_AUTO_CONTRAST);
+ }
+
+ return count;
+}
+
+static ssize_t mdss_livedisplay_get_preset(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ return sprintf(buf, "%d\n", mlc->preset);
+}
+
+static ssize_t mdss_livedisplay_set_preset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ sscanf(buf, "%du", &value);
+ if (value < 0 || value >= mlc->num_presets)
+ return -EINVAL;
+
+ mlc->preset = value;
+ mdss_livedisplay_event(mfd, MODE_PRESET);
+
+ return count;
+}
+
+static ssize_t mdss_livedisplay_get_num_presets(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ return sprintf(buf, "%d\n", mlc->num_presets);
+}
+
+static DEVICE_ATTR(cabc, S_IRUGO | S_IWUSR | S_IWGRP, mdss_livedisplay_get_cabc, mdss_livedisplay_set_cabc);
+static DEVICE_ATTR(sre, S_IRUGO | S_IWUSR | S_IWGRP, mdss_livedisplay_get_sre, mdss_livedisplay_set_sre);
+static DEVICE_ATTR(color_enhance, S_IRUGO | S_IWUSR | S_IWGRP, mdss_livedisplay_get_color_enhance, mdss_livedisplay_set_color_enhance);
+static DEVICE_ATTR(aco, S_IRUGO | S_IWUSR | S_IWGRP, mdss_livedisplay_get_aco, mdss_livedisplay_set_aco);
+static DEVICE_ATTR(preset, S_IRUGO | S_IWUSR | S_IWGRP, mdss_livedisplay_get_preset, mdss_livedisplay_set_preset);
+static DEVICE_ATTR(num_presets, S_IRUGO, mdss_livedisplay_get_num_presets, NULL);
+static DEVICE_ATTR(hbm, S_IRUGO | S_IWUSR | S_IWGRP, mdss_livedisplay_get_hbm, mdss_livedisplay_set_hbm);
+
+int mdss_livedisplay_parse_dt(struct device_node *np, struct mdss_panel_info *pinfo)
+{
+ int rc = 0, i = 0;
+ struct mdss_livedisplay_ctx *mlc;
+ char preset_name[64];
+ const char *link_state;
+ uint32_t tmp = 0;
+
+ if (pinfo == NULL)
+ return -ENODEV;
+
+ mlc = kzalloc(sizeof(struct mdss_livedisplay_ctx), GFP_KERNEL);
+ mutex_init(&mlc->lock);
+
+ link_state = of_get_property(np, "cm,mdss-livedisplay-command-state", NULL);
+ if (link_state && !strcmp(link_state, "dsi_lp_mode"))
+ mlc->link_state = DSI_LP_MODE;
+ else
+ mlc->link_state = DSI_HS_MODE;
+
+ mlc->cabc_cmds = of_get_property(np,
+ "cm,mdss-livedisplay-cabc-cmd", &mlc->cabc_cmds_len);
+
+ if (mlc->cabc_cmds_len > 0) {
+ rc = of_property_read_u32(np, "cm,mdss-livedisplay-cabc-ui-value", &tmp);
+ if (rc == 0) {
+ // Read unified CABC cmds first
+ mlc->caps |= MODE_CABC;
+ mlc->unified_cabc_cmds = true;
+ mlc->cabc_ui_value = (uint8_t)(tmp & 0xFF);
+ of_property_read_u32(np, "cm,mdss-livedisplay-cabc-image-value", &tmp);
+ mlc->cabc_image_value = (uint8_t)(tmp & 0xFF);
+ of_property_read_u32(np, "cm,mdss-livedisplay-cabc-video-value", &tmp);
+ mlc->cabc_video_value = (uint8_t)(tmp & 0xFF);
+ } else {
+ // If unified CABC cmds don't exist, try independent cmds
+ mlc->cabc_ui_cmds = of_get_property(np,
+ "cm,mdss-livedisplay-cabc-ui-cmd", &mlc->cabc_ui_cmds_len);
+ if (mlc->cabc_ui_cmds_len > 0) {
+ mlc->caps |= MODE_CABC;
+ mlc->cabc_image_cmds = of_get_property(np,
+ "cm,mdss-livedisplay-cabc-image-cmd", &mlc->cabc_image_cmds_len);
+ mlc->cabc_video_cmds = of_get_property(np,
+ "cm,mdss-livedisplay-cabc-video-cmd", &mlc->cabc_video_cmds_len);
+ }
+ }
+ rc = of_property_read_u32(np, "cm,mdss-livedisplay-sre-medium-value", &tmp);
+ if (rc == 0) {
+ mlc->caps |= MODE_SRE;
+ mlc->sre_medium_value = (uint8_t)(tmp & 0xFF);
+ of_property_read_u32(np, "cm,mdss-livedisplay-sre-weak-value", &tmp);
+ mlc->sre_weak_value = (uint8_t)(tmp & 0xFF);
+ of_property_read_u32(np, "cm,mdss-livedisplay-sre-strong-value", &tmp);
+ mlc->sre_strong_value = (uint8_t)(tmp & 0xFF);
+ }
+ rc = of_property_read_u32(np, "cm,mdss-livedisplay-aco-value", &tmp);
+ if (rc == 0) {
+ mlc->caps |= MODE_AUTO_CONTRAST;
+ mlc->aco_value = (uint8_t)(tmp & 0xFF);
+ }
+ }
+
+ mlc->hbm_on_cmds = of_get_property(np,
+ "cm,mdss-livedisplay-hbm-on-cmd", &mlc->hbm_on_cmds_len);
+ if (mlc->hbm_on_cmds_len) {
+ mlc->hbm_off_cmds = of_get_property(np,
+ "cm,mdss-livedisplay-hbm-off-cmd", &mlc->hbm_off_cmds_len);
+ if (mlc->hbm_off_cmds_len)
+ mlc->caps |= MODE_HIGH_BRIGHTNESS;
+ }
+
+ mlc->ce_on_cmds = of_get_property(np,
+ "cm,mdss-livedisplay-color-enhance-on", &mlc->ce_on_cmds_len);
+ if (mlc->ce_on_cmds_len) {
+ mlc->ce_off_cmds = of_get_property(np,
+ "cm,mdss-livedisplay-color-enhance-off", &mlc->ce_off_cmds_len);
+ if (mlc->ce_off_cmds_len)
+ mlc->caps |= MODE_COLOR_ENHANCE;
+ }
+
+ for (i = 0; i < MAX_PRESETS; i++) {
+ memset(preset_name, 0, sizeof(preset_name));
+ snprintf(preset_name, 64, "%s-%d", "cm,mdss-livedisplay-preset", i);
+ mlc->presets[mlc->num_presets] = of_get_property(np, preset_name,
+ &mlc->presets_len[mlc->num_presets]);
+ if (mlc->presets_len[mlc->num_presets] > 0)
+ mlc->num_presets++;
+ }
+
+ if (mlc->num_presets)
+ mlc->caps |= MODE_PRESET;
+
+ mlc->post_cmds = of_get_property(np,
+ "cm,mdss-livedisplay-post-cmd", &mlc->post_cmds_len);
+
+ pinfo->livedisplay = mlc;
+ return 0;
+}
+
+int mdss_livedisplay_create_sysfs(struct msm_fb_data_type *mfd)
+{
+ int rc = 0;
+ struct mdss_livedisplay_ctx *mlc = get_ctx(mfd);
+
+ if (mlc == NULL)
+ return 0;
+
+ if (mlc->caps & MODE_CABC) {
+ rc = sysfs_create_file(&mfd->fbi->dev->kobj, &dev_attr_cabc.attr);
+ if (rc)
+ goto sysfs_err;
+ }
+
+ if (mlc->caps & MODE_SRE) {
+ rc = sysfs_create_file(&mfd->fbi->dev->kobj, &dev_attr_sre.attr);
+ if (rc)
+ goto sysfs_err;
+ }
+
+ if (mlc->caps & MODE_AUTO_CONTRAST) {
+ rc = sysfs_create_file(&mfd->fbi->dev->kobj, &dev_attr_aco.attr);
+ if (rc)
+ goto sysfs_err;
+ }
+
+ if (mlc->caps & MODE_COLOR_ENHANCE) {
+ rc = sysfs_create_file(&mfd->fbi->dev->kobj, &dev_attr_color_enhance.attr);
+ if (rc)
+ goto sysfs_err;
+ }
+
+ if (mlc->caps & MODE_HIGH_BRIGHTNESS) {
+ rc = sysfs_create_file(&mfd->fbi->dev->kobj, &dev_attr_hbm.attr);
+ if (rc)
+ goto sysfs_err;
+ }
+
+ if (mlc->caps & MODE_PRESET) {
+ rc = sysfs_create_file(&mfd->fbi->dev->kobj, &dev_attr_preset.attr);
+ if (rc)
+ goto sysfs_err;
+ rc = sysfs_create_file(&mfd->fbi->dev->kobj, &dev_attr_num_presets.attr);
+ if (rc)
+ goto sysfs_err;
+ }
+
+ mlc->mfd = mfd;
+
+ return rc;
+
+sysfs_err:
+ pr_err("%s: sysfs creation failed, rc=%d", __func__, rc);
+ return rc;
+}
+
diff --git a/drivers/video/fbdev/msm/mdss_livedisplay.h b/drivers/video/fbdev/msm/mdss_livedisplay.h
new file mode 100644
index 000000000000..58b4f9f6a866
--- /dev/null
+++ b/drivers/video/fbdev/msm/mdss_livedisplay.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015 The CyanogenMod Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MDSS_LIVEDISPLAY_H
+#define MDSS_LIVEDISPLAY_H
+
+#include <linux/of.h>
+#include <linux/sysfs.h>
+
+#include "mdss_dsi.h"
+#include "mdss_fb.h"
+
+#define MAX_PRESETS 10
+
+struct mdss_livedisplay_ctx {
+ uint8_t cabc_ui_value;
+ uint8_t cabc_image_value;
+ uint8_t cabc_video_value;
+ uint8_t sre_weak_value;
+ uint8_t sre_medium_value;
+ uint8_t sre_strong_value;
+ uint8_t aco_value;
+
+ const uint8_t *ce_off_cmds;
+ const uint8_t *ce_on_cmds;
+ unsigned int ce_off_cmds_len;
+ unsigned int ce_on_cmds_len;
+
+ const uint8_t *hbm_off_cmds;
+ const uint8_t *hbm_on_cmds;
+ unsigned int hbm_off_cmds_len;
+ unsigned int hbm_on_cmds_len;
+
+ const uint8_t *presets[MAX_PRESETS];
+ unsigned int presets_len[MAX_PRESETS];
+
+ const uint8_t *cabc_cmds;
+ const uint8_t *cabc_ui_cmds;
+ const uint8_t *cabc_image_cmds;
+ const uint8_t *cabc_video_cmds;
+ unsigned int cabc_cmds_len;
+ unsigned int cabc_ui_cmds_len;
+ unsigned int cabc_image_cmds_len;
+ unsigned int cabc_video_cmds_len;
+ bool unified_cabc_cmds;
+
+ const uint8_t *post_cmds;
+ unsigned int post_cmds_len;
+
+ unsigned int preset;
+ unsigned int cabc_level;
+ unsigned int sre_level;
+ bool aco_enabled;
+ bool ce_enabled;
+ bool hbm_enabled;
+
+ unsigned int link_state;
+
+ unsigned int num_presets;
+ unsigned int caps;
+
+ struct msm_fb_data_type *mfd;
+
+ struct mutex lock;
+};
+
+enum {
+ CABC_OFF,
+ CABC_UI,
+ CABC_IMAGE,
+ CABC_VIDEO,
+ CABC_MAX
+};
+
+enum {
+ SRE_OFF,
+ SRE_WEAK,
+ SRE_MEDIUM,
+ SRE_STRONG,
+ SRE_MAX
+};
+
+enum {
+ MODE_CABC = 0x01,
+ MODE_SRE = 0x02,
+ MODE_AUTO_CONTRAST = 0x04,
+ MODE_COLOR_ENHANCE = 0x08,
+ MODE_PRESET = 0x10,
+ MODE_HIGH_BRIGHTNESS = 0x20,
+ MODE_UPDATE_ALL = 0xFF,
+};
+
+int mdss_livedisplay_update(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int types);
+int mdss_livedisplay_parse_dt(struct device_node *np, struct mdss_panel_info *pinfo);
+int mdss_livedisplay_create_sysfs(struct msm_fb_data_type *mfd);
+int mdss_livedisplay_event(struct msm_fb_data_type *mfd, int types);
+
+static inline bool is_cabc_cmd(unsigned int value)
+{
+ return (value & MODE_CABC) || (value & MODE_SRE) || (value & MODE_AUTO_CONTRAST);
+}
+
+static inline struct mdss_livedisplay_ctx* get_ctx(struct msm_fb_data_type *mfd)
+{
+ return mfd->panel_info->livedisplay;
+}
+
+static inline struct mdss_dsi_ctrl_pdata* get_ctrl(struct msm_fb_data_type *mfd)
+{
+ struct mdss_panel_data *pdata = dev_get_platdata(&mfd->pdev->dev);
+ return container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data);
+}
+
+#endif
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 98172233b5aa..84be290a0369 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -4854,7 +4854,7 @@ struct mdss_panel_cfg *mdss_panel_intf_type(int intf_val)
}
EXPORT_SYMBOL(mdss_panel_intf_type);
-struct irq_info *mdss_intr_line()
+struct irq_info *mdss_intr_line(void)
{
return mdss_mdp_hw.irq_info;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 3761fa4af0eb..caa910db508c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -1236,7 +1236,7 @@ static int mdss_mdp_video_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
if (rc == 0) {
pr_warn("vsync wait timeout %d, fallback to poll mode\n",
ctl->num);
- ctx->polling_en++;
+ ctx->polling_en = true;
rc = mdss_mdp_video_pollwait(ctl);
} else {
rc = 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index daeed5d45072..012870048050 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -5254,6 +5254,7 @@ static int __handle_overlay_prepare(struct msm_fb_data_type *mfd,
sorted_ovs = kzalloc(num_ovs * sizeof(*ip_ovs), GFP_KERNEL);
if (!sorted_ovs) {
pr_err("error allocating ovlist mem\n");
+ mutex_unlock(&mdp5_data->ov_lock);
return -ENOMEM;
}
memcpy(sorted_ovs, ip_ovs, num_ovs * sizeof(*ip_ovs));
@@ -5261,6 +5262,7 @@ static int __handle_overlay_prepare(struct msm_fb_data_type *mfd,
if (ret) {
pr_err("src_split_sort failed. ret=%d\n", ret);
kfree(sorted_ovs);
+ mutex_unlock(&mdp5_data->ov_lock);
return ret;
}
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index edc154b2b0c6..f2afd04eaf29 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -4129,7 +4129,8 @@ int mdss_mdp_igc_lut_config(struct msm_fb_data_type *mfd,
if (config->len != IGC_LUT_ENTRIES) {
pr_err("invalid len for IGC table for read %d\n",
config->len);
- return -EINVAL;
+ ret = -EINVAL;
+ goto igc_config_exit;
}
ret = pp_get_dspp_num(disp_num, &dspp_num);
if (ret) {
@@ -4195,7 +4196,8 @@ clock_off:
if (config->len != IGC_LUT_ENTRIES) {
pr_err("invalid len for IGC table for write %d\n",
config->len);
- return -EINVAL;
+ ret = -EINVAL;
+ goto igc_config_exit;
}
if (copy_from_kernel) {
memcpy(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
index b55a6824ffc1..b085bd21bee2 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
@@ -418,8 +418,11 @@ static int mdss_mdp_splash_kickoff(struct msm_fb_data_type *mfd,
}
req = kzalloc(sizeof(struct mdp_overlay), GFP_KERNEL);
- if (!req)
- return -ENOMEM;
+ if (!req) {
+ pr_err("fail allocate memory\n");
+ ret = -ENOMEM;
+ goto end;
+ }
/*
* use single pipe for
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index bc2513296fd8..059bc6ba4a76 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -312,6 +312,7 @@ enum mdss_intf_events {
MDSS_EVENT_AVR_MODE,
MDSS_EVENT_REGISTER_CLAMP_HANDLER,
MDSS_EVENT_DSI_DYNAMIC_BITCLK,
+ MDSS_EVENT_UPDATE_LIVEDISPLAY,
MDSS_EVENT_MAX,
};
@@ -764,6 +765,8 @@ struct mdss_dsi_dual_pu_roi {
bool enabled;
};
+struct mdss_livedisplay_ctx;
+
struct mdss_panel_hdr_properties {
bool hdr_enabled;
@@ -926,6 +929,8 @@ struct mdss_panel_info {
*/
u32 adjust_timer_delay_ms;
+ struct mdss_livedisplay_ctx *livedisplay;
+
/* debugfs structure for the panel */
struct mdss_panel_debugfs_info *debugfs_info;
diff --git a/drivers/video/fbdev/msm/mdss_util.c b/drivers/video/fbdev/msm/mdss_util.c
index 65941601cfdc..d6c462e04dfd 100644
--- a/drivers/video/fbdev/msm/mdss_util.c
+++ b/drivers/video/fbdev/msm/mdss_util.c
@@ -232,7 +232,7 @@ struct mdss_util_intf mdss_util = {
.mdp_probe_done = false
};
-struct mdss_util_intf *mdss_get_util_intf()
+struct mdss_util_intf *mdss_get_util_intf(void)
{
return &mdss_util;
}
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index 922c4440ba82..000beebe0375 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -1321,16 +1321,16 @@ static void mdss_dsi_phy_regulator_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
mdss_dsi_20nm_phy_regulator_enable(ctrl);
break;
default:
- /*
- * For dual dsi case, do not reconfigure dsi phy
- * regulator if the other dsi controller is still
- * active.
- */
- if (!mdss_dsi_is_hw_config_dual(sdata) ||
- (other_ctrl && (!other_ctrl->is_phyreg_enabled
- || other_ctrl->mmss_clamp)))
- mdss_dsi_28nm_phy_regulator_enable(ctrl);
- break;
+ /*
+ * For dual dsi case, do not reconfigure dsi phy
+ * regulator if the other dsi controller is still
+ * active.
+ */
+ if (!mdss_dsi_is_hw_config_dual(sdata) ||
+ (other_ctrl && (!other_ctrl->is_phyreg_enabled
+ || other_ctrl->mmss_clamp)))
+ mdss_dsi_28nm_phy_regulator_enable(ctrl);
+ break;
}
}
ctrl->is_phyreg_enabled = 1;
diff --git a/drivers/video/fbdev/neofb.c b/drivers/video/fbdev/neofb.c
index db023a97d1ea..e243254a5721 100644
--- a/drivers/video/fbdev/neofb.c
+++ b/drivers/video/fbdev/neofb.c
@@ -1820,6 +1820,7 @@ static int neo_scan_monitor(struct fb_info *info)
#else
printk(KERN_ERR
"neofb: Only 640x480, 800x600/480 and 1024x768 panels are currently supported\n");
+ kfree(info->monspecs.modedb);
return -1;
#endif
default:
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c
index 9200a8668b49..a57c3a5f4bf8 100644
--- a/drivers/video/fbdev/omap2/dss/dss.c
+++ b/drivers/video/fbdev/omap2/dss/dss.c
@@ -843,7 +843,7 @@ static const struct dss_features omap34xx_dss_feats = {
};
static const struct dss_features omap3630_dss_feats = {
- .fck_div_max = 32,
+ .fck_div_max = 31,
.dss_fck_multiplier = 1,
.parent_clk_name = "dpll4_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
diff --git a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
index 8b6f6d5fdd68..43186fa8a13c 100644
--- a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
+++ b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
@@ -194,7 +194,7 @@ static int __init omapdss_boot_init(void)
dss = of_find_matching_node(NULL, omapdss_of_match);
if (dss == NULL || !of_device_is_available(dss))
- return 0;
+ goto put_node;
omapdss_walk_device(dss, true);
@@ -221,6 +221,8 @@ static int __init omapdss_boot_init(void)
kfree(n);
}
+put_node:
+ of_node_put(dss);
return 0;
}
diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c
index 750a384bf191..1a015a6b682e 100644
--- a/drivers/video/fbdev/pvr2fb.c
+++ b/drivers/video/fbdev/pvr2fb.c
@@ -1029,6 +1029,8 @@ static int __init pvr2fb_setup(char *options)
if (!options || !*options)
return 0;
+ cable_arg[0] = output_arg[0] = 0;
+
while ((this_opt = strsep(&options, ","))) {
if (!*this_opt)
continue;
diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c
index f1ad2747064b..6e5e29fe13db 100644
--- a/drivers/video/fbdev/riva/fbdev.c
+++ b/drivers/video/fbdev/riva/fbdev.c
@@ -1088,6 +1088,9 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
int mode_valid = 0;
NVTRACE_ENTER();
+ if (!var->pixclock)
+ return -EINVAL;
+
switch (var->bits_per_pixel) {
case 1 ... 8:
var->red.offset = var->green.offset = var->blue.offset = 0;
diff --git a/drivers/video/fbdev/sis/init.c b/drivers/video/fbdev/sis/init.c
index dfe3eb769638..fde27feae5d0 100644
--- a/drivers/video/fbdev/sis/init.c
+++ b/drivers/video/fbdev/sis/init.c
@@ -2428,6 +2428,11 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
i = 0;
+ if (SiS_Pr->ChipType == SIS_730)
+ queuedata = &FQBQData730[0];
+ else
+ queuedata = &FQBQData[0];
+
if(ModeNo > 0x13) {
/* Get VCLK */
@@ -2445,12 +2450,6 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* Get half colordepth */
colorth = colortharray[(SiS_Pr->SiS_ModeType - ModeEGA)];
- if(SiS_Pr->ChipType == SIS_730) {
- queuedata = &FQBQData730[0];
- } else {
- queuedata = &FQBQData[0];
- }
-
do {
templ = SiS_CalcDelay2(SiS_Pr, queuedata[i]) * VCLK * colorth;
diff --git a/drivers/video/fbdev/sis/init301.c b/drivers/video/fbdev/sis/init301.c
index 20f7234e809e..c43b951cfb25 100644
--- a/drivers/video/fbdev/sis/init301.c
+++ b/drivers/video/fbdev/sis/init301.c
@@ -522,9 +522,7 @@ SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime)
SiS_DDC2Delay(SiS_Pr, 0x4000);
}
- } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* ||
- (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
- (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) { /* 315 series, LVDS; Special */
+ } else if (SiS_Pr->SiS_IF_DEF_LVDS == 1) { /* 315 series, LVDS; Special */
if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c
index 589ac7e75413..c8ee58e0ae3e 100644
--- a/drivers/video/fbdev/sm712fb.c
+++ b/drivers/video/fbdev/sm712fb.c
@@ -1428,6 +1428,8 @@ static int smtc_map_smem(struct smtcfb_info *sfb,
static void smtc_unmap_smem(struct smtcfb_info *sfb)
{
if (sfb && sfb->fb->screen_base) {
+ if (sfb->chip_id == 0x720)
+ sfb->fb->screen_base -= 0x00200000;
iounmap(sfb->fb->screen_base);
sfb->fb->screen_base = NULL;
}
diff --git a/drivers/video/fbdev/vga16fb.c b/drivers/video/fbdev/vga16fb.c
index 283d335a759f..06cee2a40a9b 100644
--- a/drivers/video/fbdev/vga16fb.c
+++ b/drivers/video/fbdev/vga16fb.c
@@ -243,7 +243,7 @@ static void vga16fb_update_fix(struct fb_info *info)
}
static void vga16fb_clock_chip(struct vga16fb_par *par,
- unsigned int pixclock,
+ unsigned int *pixclock,
const struct fb_info *info,
int mul, int div)
{
@@ -259,14 +259,14 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
{ 0 /* bad */, 0x00, 0x00}};
int err;
- pixclock = (pixclock * mul) / div;
+ *pixclock = (*pixclock * mul) / div;
best = vgaclocks;
- err = pixclock - best->pixclock;
+ err = *pixclock - best->pixclock;
if (err < 0) err = -err;
for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
int tmp;
- tmp = pixclock - ptr->pixclock;
+ tmp = *pixclock - ptr->pixclock;
if (tmp < 0) tmp = -tmp;
if (tmp < err) {
err = tmp;
@@ -275,7 +275,7 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
}
par->misc |= best->misc;
par->clkdiv = best->seq_clock_mode;
- pixclock = (best->pixclock * div) / mul;
+ *pixclock = (best->pixclock * div) / mul;
}
#define FAIL(X) return -EINVAL
@@ -497,10 +497,10 @@ static int vga16fb_check_var(struct fb_var_screeninfo *var,
if (mode & MODE_8BPP)
/* pixel clock == vga clock / 2 */
- vga16fb_clock_chip(par, var->pixclock, info, 1, 2);
+ vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
else
/* pixel clock == vga clock */
- vga16fb_clock_chip(par, var->pixclock, info, 1, 1);
+ vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
var->red.offset = var->green.offset = var->blue.offset =
var->transp.offset = 0;
@@ -1122,7 +1122,7 @@ static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *i
char oldop = setop(0);
char oldsr = setsr(0);
char oldmask = selectmask();
- const char *cdat = image->data;
+ const unsigned char *cdat = image->data;
u32 dx = image->dx;
char __iomem *where;
int y;
diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c
index 10951c82f6ed..7bd4c27cfb14 100644
--- a/drivers/video/fbdev/w100fb.c
+++ b/drivers/video/fbdev/w100fb.c
@@ -583,6 +583,7 @@ static void w100fb_restore_vidmem(struct w100fb_par *par)
memsize=par->mach->mem->size;
memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
vfree(par->saved_extmem);
+ par->saved_extmem = NULL;
}
if (par->saved_intmem) {
memsize=MEM_INT_SIZE;
@@ -591,6 +592,7 @@ static void w100fb_restore_vidmem(struct w100fb_par *par)
else
memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
vfree(par->saved_intmem);
+ par->saved_intmem = NULL;
}
}