Project import generated by Copybara.

GitOrigin-RevId: 0acb173e07e155358594d3ce7b5f19e91bb9fec3
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 813a264..cac3e35 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -630,6 +630,12 @@ struct backlight_device *of_find_backlight(struct device *dev)
 			of_node_put(np);
 			if (!bd)
 				return ERR_PTR(-EPROBE_DEFER);
+			/*
+			 * Note: gpio_backlight uses brightness as
+			 * power state during probe
+			 */
+			if (!bd->props.brightness)
+				bd->props.brightness = bd->props.max_brightness;
 		}
 	}
 
diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c
index 8096202..2d8e819 100644
--- a/drivers/video/backlight/lm3630a_bl.c
+++ b/drivers/video/backlight/lm3630a_bl.c
@@ -188,7 +188,7 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl)
 	if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
 		lm3630a_pwm_ctrl(pchip, bl->props.brightness,
 				 bl->props.max_brightness);
-		return 0;
+		return bl->props.brightness;
 	}
 
 	/* disable sleep */
@@ -208,8 +208,8 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl)
 	return 0;
 
 out_i2c_err:
-	dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret));
-	return ret;
+	dev_err(pchip->dev, "i2c failed to access\n");
+	return bl->props.brightness;
 }
 
 static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
@@ -265,7 +265,7 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl)
 	if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
 		lm3630a_pwm_ctrl(pchip, bl->props.brightness,
 				 bl->props.max_brightness);
-		return 0;
+		return bl->props.brightness;
 	}
 
 	/* disable sleep */
@@ -285,8 +285,8 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl)
 	return 0;
 
 out_i2c_err:
-	dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret));
-	return ret;
+	dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
+	return bl->props.brightness;
 }
 
 static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
@@ -480,10 +480,8 @@ static int lm3630a_parse_node(struct lm3630a_chip *pchip,
 
 	device_for_each_child_node(pchip->dev, node) {
 		ret = lm3630a_parse_bank(pdata, node, &seen_led_sources);
-		if (ret) {
-			fwnode_handle_put(node);
+		if (ret)
 			return ret;
-		}
 	}
 
 	return ret;
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 118492b..746eebc 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -415,33 +415,6 @@ static bool pwm_backlight_is_linear(struct platform_pwm_backlight_data *data)
 static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
 {
 	struct device_node *node = pb->dev->of_node;
-	bool active = true;
-
-	/*
-	 * If the enable GPIO is present, observable (either as input
-	 * or output) and off then the backlight is not currently active.
-	 * */
-	if (pb->enable_gpio && gpiod_get_value_cansleep(pb->enable_gpio) == 0)
-		active = false;
-
-	if (!regulator_is_enabled(pb->power_supply))
-		active = false;
-
-	if (!pwm_is_enabled(pb->pwm))
-		active = false;
-
-	/*
-	 * Synchronize the enable_gpio with the observed state of the
-	 * hardware.
-	 */
-	if (pb->enable_gpio)
-		gpiod_direction_output(pb->enable_gpio, active);
-
-	/*
-	 * Do not change pb->enabled here! pb->enabled essentially
-	 * tells us if we own one of the regulator's use counts and
-	 * right now we do not.
-	 */
 
 	/* Not booted with device tree or no phandle link to the node */
 	if (!node || !node->phandle)
@@ -453,7 +426,20 @@ static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
 	 * assume that another driver will enable the backlight at the
 	 * appropriate time. Therefore, if it is disabled, keep it so.
 	 */
-	return active ? FB_BLANK_UNBLANK: FB_BLANK_POWERDOWN;
+
+	/* if the enable GPIO is disabled, do not enable the backlight */
+	if (pb->enable_gpio && gpiod_get_value_cansleep(pb->enable_gpio) == 0)
+		return FB_BLANK_POWERDOWN;
+
+	/* The regulator is disabled, do not enable the backlight */
+	if (!regulator_is_enabled(pb->power_supply))
+		return FB_BLANK_POWERDOWN;
+
+	/* The PWM is disabled, keep it like this */
+	if (!pwm_is_enabled(pb->pwm))
+		return FB_BLANK_POWERDOWN;
+
+	return FB_BLANK_UNBLANK;
 }
 
 static int pwm_backlight_probe(struct platform_device *pdev)
@@ -522,6 +508,18 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 		pb->enable_gpio = gpio_to_desc(data->enable_gpio);
 	}
 
+	/*
+	 * If the GPIO is not known to be already configured as output, that
+	 * is, if gpiod_get_direction returns either 1 or -EINVAL, change the
+	 * direction to output and set the GPIO as active.
+	 * Do not force the GPIO to active when it was already output as it
+	 * could cause backlight flickering or we would enable the backlight too
+	 * early. Leave the decision of the initial backlight state for later.
+	 */
+	if (pb->enable_gpio &&
+	    gpiod_get_direction(pb->enable_gpio) != 0)
+		gpiod_direction_output(pb->enable_gpio, 1);
+
 	pb->power_supply = devm_regulator_get(&pdev->dev, "power");
 	if (IS_ERR(pb->power_supply)) {
 		ret = PTR_ERR(pb->power_supply);
@@ -618,8 +616,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 		pb->scale = data->max_brightness;
 	}
 
-	pb->lth_brightness = data->lth_brightness * (div_u64(state.period,
-				pb->scale));
+	pb->lth_brightness = data->lth_brightness * (state.period / pb->scale);
 
 	props.type = BACKLIGHT_RAW;
 	props.max_brightness = data->max_brightness;
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 559a730..79c9bd8 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -291,13 +291,13 @@ static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos,
 static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens,
 			    u8 blink, u8 underline, u8 reverse, u8 italic)
 {
-	u8 fg = color & 7;
-	u8 bg = (color & 0x70) >> 4;
+    u8 attr = ((color & 0x70) >> 1) | ((color & 7));
 
-	if (reverse)
-		return (fg << 3) | bg;
-	else
-		return (bg << 3) | fg;
+    if (reverse) {
+	color = ((color >> 3) & 0x7) | ((color & 0x7) << 3);
+    }
+
+    return attr;
 }
 
 static void sticon_invert_region(struct vc_data *conp, u16 *p, int count)
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 23f15f4..55507df 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -370,17 +370,11 @@ static void vgacon_init(struct vc_data *c, int init)
 	struct uni_pagedir *p;
 
 	/*
-	 * We cannot be loaded as a module, therefore init will be 1
-	 * if we are the default console, however if we are a fallback
-	 * console, for example if fbcon has failed registration, then
-	 * init will be 0, so we need to make sure our boot parameters
-	 * have been copied to the console structure for vgacon_resize
-	 * ultimately called by vc_resize.  Any subsequent calls to
-	 * vgacon_init init will have init set to 0 too.
+	 * We cannot be loaded as a module, therefore init is always 1,
+	 * but vgacon_init can be called more than once, and init will
+	 * not be 1.
 	 */
 	c->vc_can_do_color = vga_can_do_color;
-	c->vc_scan_lines = vga_scan_lines;
-	c->vc_font.height = c->vc_cell_height = vga_video_font_height;
 
 	/* set dimensions manually if init != 0 since vc_resize() will fail */
 	if (init) {
@@ -389,6 +383,8 @@ static void vgacon_init(struct vc_data *c, int init)
 	} else
 		vc_resize(c, vga_video_num_columns, vga_video_num_lines);
 
+	c->vc_scan_lines = vga_scan_lines;
+	c->vc_font.height = vga_video_font_height;
 	c->vc_complement_mask = 0x7700;
 	if (vga_512_chars)
 		c->vc_hi_font_mask = 0x0800;
@@ -521,32 +517,32 @@ static void vgacon_cursor(struct vc_data *c, int mode)
 		switch (c->vc_cursor_type & 0x0f) {
 		case CUR_UNDERLINE:
 			vgacon_set_cursor_size(c->vc_x,
-					       c->vc_cell_height -
-					       (c->vc_cell_height <
+					       c->vc_font.height -
+					       (c->vc_font.height <
 						10 ? 2 : 3),
-					       c->vc_cell_height -
-					       (c->vc_cell_height <
+					       c->vc_font.height -
+					       (c->vc_font.height <
 						10 ? 1 : 2));
 			break;
 		case CUR_TWO_THIRDS:
 			vgacon_set_cursor_size(c->vc_x,
-					       c->vc_cell_height / 3,
-					       c->vc_cell_height -
-					       (c->vc_cell_height <
+					       c->vc_font.height / 3,
+					       c->vc_font.height -
+					       (c->vc_font.height <
 						10 ? 1 : 2));
 			break;
 		case CUR_LOWER_THIRD:
 			vgacon_set_cursor_size(c->vc_x,
-					       (c->vc_cell_height * 2) / 3,
-					       c->vc_cell_height -
-					       (c->vc_cell_height <
+					       (c->vc_font.height * 2) / 3,
+					       c->vc_font.height -
+					       (c->vc_font.height <
 						10 ? 1 : 2));
 			break;
 		case CUR_LOWER_HALF:
 			vgacon_set_cursor_size(c->vc_x,
-					       c->vc_cell_height / 2,
-					       c->vc_cell_height -
-					       (c->vc_cell_height <
+					       c->vc_font.height / 2,
+					       c->vc_font.height -
+					       (c->vc_font.height <
 						10 ? 1 : 2));
 			break;
 		case CUR_NONE:
@@ -557,7 +553,7 @@ static void vgacon_cursor(struct vc_data *c, int mode)
 			break;
 		default:
 			vgacon_set_cursor_size(c->vc_x, 1,
-					       c->vc_cell_height);
+					       c->vc_font.height);
 			break;
 		}
 		break;
@@ -568,13 +564,13 @@ static int vgacon_doresize(struct vc_data *c,
 		unsigned int width, unsigned int height)
 {
 	unsigned long flags;
-	unsigned int scanlines = height * c->vc_cell_height;
+	unsigned int scanlines = height * c->vc_font.height;
 	u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
 
 	raw_spin_lock_irqsave(&vga_lock, flags);
 
 	vgacon_xres = width * VGA_FONTWIDTH;
-	vgacon_yres = height * c->vc_cell_height;
+	vgacon_yres = height * c->vc_font.height;
 	if (vga_video_type >= VIDEO_TYPE_VGAC) {
 		outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
 		max_scan = inb_p(vga_video_port_val);
@@ -629,9 +625,9 @@ static int vgacon_doresize(struct vc_data *c,
 static int vgacon_switch(struct vc_data *c)
 {
 	int x = c->vc_cols * VGA_FONTWIDTH;
-	int y = c->vc_rows * c->vc_cell_height;
+	int y = c->vc_rows * c->vc_font.height;
 	int rows = screen_info.orig_video_lines * vga_default_font_height/
-		c->vc_cell_height;
+		c->vc_font.height;
 	/*
 	 * We need to save screen size here as it's the only way
 	 * we can spot the screen has been resized and we need to
@@ -1062,7 +1058,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
 				cursor_size_lastto = 0;
 				c->vc_sw->con_cursor(c, CM_DRAW);
 			}
-			c->vc_font.height = c->vc_cell_height = fontheight;
+			c->vc_font.height = fontheight;
 			vc_resize(c, 0, rows);	/* Adjust console size */
 		}
 	}
@@ -1110,20 +1106,12 @@ static int vgacon_resize(struct vc_data *c, unsigned int width,
 	if ((width << 1) * height > vga_vram_size)
 		return -EINVAL;
 
-	if (user) {
-		/*
-		 * Ho ho!  Someone (svgatextmode, eh?) may have reprogrammed
-		 * the video mode!  Set the new defaults then and go away.
-		 */
-		screen_info.orig_video_cols = width;
-		screen_info.orig_video_lines = height;
-		vga_default_font_height = c->vc_cell_height;
-		return 0;
-	}
 	if (width % 2 || width > screen_info.orig_video_cols ||
 	    height > (screen_info.orig_video_lines * vga_default_font_height)/
-	    c->vc_cell_height)
-		return -EINVAL;
+	    c->vc_font.height)
+		/* let svgatextmode tinker with video timings and
+		   return success */
+		return (user) ? 0 : -EINVAL;
 
 	if (con_is_visible(c) && !vga_is_gfx) /* who knows */
 		vgacon_doresize(c, width, height);
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index a7e5f12..f0f1702 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1269,7 +1269,6 @@
 	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.
@@ -1280,6 +1279,7 @@
 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
@@ -2266,3 +2266,4 @@
 source "drivers/video/fbdev/omap/Kconfig"
 source "drivers/video/fbdev/omap2/Kconfig"
 source "drivers/video/fbdev/mmp/Kconfig"
+source "drivers/video/fbdev/qti/Kconfig"
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index aa63527..e338e16 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -120,6 +120,7 @@
 obj-$(CONFIG_FB_HYPERV)		  += hyperv_fb.o
 obj-$(CONFIG_FB_OPENCORES)	  += ocfb.o
 obj-$(CONFIG_FB_SM712)		  += sm712fb.o
+obj-y				  += qti/
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c
index 3b7a7c7..7de43be 100644
--- a/drivers/video/fbdev/amba-clcd.c
+++ b/drivers/video/fbdev/amba-clcd.c
@@ -774,15 +774,12 @@ static int clcdfb_of_vram_setup(struct clcd_fb *fb)
 		return -ENODEV;
 
 	fb->fb.screen_base = of_iomap(memory, 0);
-	if (!fb->fb.screen_base) {
-		of_node_put(memory);
+	if (!fb->fb.screen_base)
 		return -ENOMEM;
-	}
 
 	fb->fb.fix.smem_start = of_translate_address(memory,
 			of_get_address(memory, 0, &size, NULL));
 	fb->fb.fix.smem_len = size;
-	of_node_put(memory);
 
 	return 0;
 }
diff --git a/drivers/video/fbdev/asiliantfb.c b/drivers/video/fbdev/asiliantfb.c
index c1d6e63..ea31054 100644
--- a/drivers/video/fbdev/asiliantfb.c
+++ b/drivers/video/fbdev/asiliantfb.c
@@ -227,9 +227,6 @@ 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/atafb.c b/drivers/video/fbdev/atafb.c
index c1ee817..51f5d1c 100644
--- a/drivers/video/fbdev/atafb.c
+++ b/drivers/video/fbdev/atafb.c
@@ -1692,9 +1692,9 @@ static int falcon_setcolreg(unsigned int regno, unsigned int red,
 			   ((blue & 0xfc00) >> 8));
 	if (regno < 16) {
 		shifter_tt.color_reg[regno] =
-			((((red & 0xe000) >> 13)   | ((red & 0x1000) >> 12)) << 8)   |
-			((((green & 0xe000) >> 13) | ((green & 0x1000) >> 12)) << 4) |
-			   ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12);
+			(((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) |
+			(((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) |
+			((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12);
 		((u32 *)info->pseudo_palette)[regno] = ((red & 0xf800) |
 						       ((green & 0xfc00) >> 5) |
 						       ((blue & 0xf800) >> 11));
@@ -1980,9 +1980,9 @@ static int stste_setcolreg(unsigned int regno, unsigned int red,
 	green >>= 12;
 	if (ATARIHW_PRESENT(EXTD_SHIFTER))
 		shifter_tt.color_reg[regno] =
-			((((red & 0xe)   >> 1) | ((red & 1)   << 3)) << 8) |
-			((((green & 0xe) >> 1) | ((green & 1) << 3)) << 4) |
-			  ((blue & 0xe)  >> 1) | ((blue & 1)  << 3);
+			(((red & 0xe) >> 1) | ((red & 1) << 3) << 8) |
+			(((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
+			((blue & 0xe) >> 1) | ((blue & 1) << 3);
 	else
 		shifter_tt.color_reg[regno] =
 			((red & 0xe) << 7) |
diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c
index b919198..cf2bfff 100644
--- a/drivers/video/fbdev/atmel_lcdfb.c
+++ b/drivers/video/fbdev/atmel_lcdfb.c
@@ -1062,16 +1062,15 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
 
 	INIT_LIST_HEAD(&info->modelist);
 
-	if (!pdev->dev.of_node) {
+	if (pdev->dev.of_node) {
+		ret = atmel_lcdfb_of_init(sinfo);
+		if (ret)
+			goto free_info;
+	} else {
 		dev_err(dev, "cannot get default configuration\n");
 		goto free_info;
 	}
 
-	ret = atmel_lcdfb_of_init(sinfo);
-	if (ret)
-		goto free_info;
-
-	ret = -ENODEV;
 	if (!sinfo->config)
 		goto free_info;
 
diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c
index 80fdd3e..f4dc320 100644
--- a/drivers/video/fbdev/chipsfb.c
+++ b/drivers/video/fbdev/chipsfb.c
@@ -331,7 +331,7 @@ static const struct fb_var_screeninfo chipsfb_var = {
 
 static void init_chips(struct fb_info *p, unsigned long addr)
 {
-	fb_memset(p->screen_base, 0, 0x100000);
+	memset(p->screen_base, 0, 0x100000);
 
 	p->fix = chipsfb_fix;
 	p->fix.smem_start = addr;
diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c
index 1b0a58f..e4ce566 100644
--- a/drivers/video/fbdev/cirrusfb.c
+++ b/drivers/video/fbdev/cirrusfb.c
@@ -470,7 +470,7 @@ static int cirrusfb_check_mclk(struct fb_info *info, long freq)
 	return 0;
 }
 
-static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var,
+static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var,
 				   struct fb_info *info)
 {
 	long freq;
@@ -479,7 +479,9 @@ static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var,
 	unsigned maxclockidx = var->bits_per_pixel >> 3;
 
 	/* convert from ps to kHz */
-	freq = PICOS2KHZ(var->pixclock ? : 1);
+	freq = PICOS2KHZ(var->pixclock);
+
+	dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq);
 
 	maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
 	cinfo->multiplexing = 0;
@@ -487,13 +489,11 @@ static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var,
 	/* If the frequency is greater than we can support, we might be able
 	 * to use multiplexing for the video mode */
 	if (freq > maxclock) {
-		var->pixclock = KHZ2PICOS(maxclock);
-
-		while ((freq = PICOS2KHZ(var->pixclock)) > maxclock)
-			var->pixclock++;
+		dev_err(info->device,
+			"Frequency greater than maxclock (%ld kHz)\n",
+			maxclock);
+		return -EINVAL;
 	}
-	dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq);
-
 	/*
 	 * Additional constraint: 8bpp uses DAC clock doubling to allow maximum
 	 * pixel clock
diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c
index 82c20c6..4766258 100644
--- a/drivers/video/fbdev/core/fb_defio.c
+++ b/drivers/video/fbdev/core/fb_defio.c
@@ -168,6 +168,10 @@ int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
 	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 	if (!(info->flags & FBINFO_VIRTFB))
 		vma->vm_flags |= VM_IO;
+
+	if (info->flags & FBINFO_DMAFB)
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
 	vma->vm_private_data = info;
 	return 0;
 }
diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c
index e8a17fb..e5ae33c 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 = kzalloc(size, flags);
+		cmap->red = kmalloc(size, flags);
 		if (!cmap->red)
 			goto fail;
-		cmap->green = kzalloc(size, flags);
+		cmap->green = kmalloc(size, flags);
 		if (!cmap->green)
 			goto fail;
-		cmap->blue = kzalloc(size, flags);
+		cmap->blue = kmalloc(size, flags);
 		if (!cmap->blue)
 			goto fail;
 		if (transp) {
-			cmap->transp = kzalloc(size, flags);
+			cmap->transp = kmalloc(size, flags);
 			if (!cmap->transp)
 				goto fail;
 		} else {
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 8721b75..4cf71ee 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1339,9 +1339,6 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
 
 	ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
 
-	if (!ops->cursor)
-		return;
-
 	ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
 		    get_color(vc, info, c, 0));
 }
@@ -2058,7 +2055,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
 			return -EINVAL;
 
 		DPRINTK("resize now %ix%i\n", var.xres, var.yres);
-		if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) {
+		if (con_is_visible(vc)) {
 			var.activate = FB_ACTIVATE_NOW |
 				FB_ACTIVATE_FORCE;
 			fb_set_var(info, &var);
@@ -2490,11 +2487,6 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
 	if (charcount != 256 && charcount != 512)
 		return -EINVAL;
 
-	/* font bigger than screen resolution ? */
-	if (w > FBCON_SWAP(info->var.rotate, info->var.xres, info->var.yres) ||
-	    h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres))
-		return -EINVAL;
-
 	/* Make sure drawing engine can handle the font */
 	if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
 	    !(info->pixmap.blit_y & (1 << (font->height - 1))))
@@ -2761,34 +2753,6 @@ void fbcon_update_vcs(struct fb_info *info, bool all)
 }
 EXPORT_SYMBOL(fbcon_update_vcs);
 
-/* let fbcon check if it supports a new screen resolution */
-int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var)
-{
-	struct fbcon_ops *ops = info->fbcon_par;
-	struct vc_data *vc;
-	unsigned int i;
-
-	WARN_CONSOLE_UNLOCKED();
-
-	if (!ops)
-		return 0;
-
-	/* prevent setting a screen size which is smaller than font size */
-	for (i = first_fb_vc; i <= last_fb_vc; i++) {
-		vc = vc_cons[i].d;
-		if (!vc || vc->vc_mode != KD_TEXT ||
-			   registered_fb[con2fb_map[i]] != info)
-			continue;
-
-		if (vc->vc_font.width  > FBCON_SWAP(var->rotate, var->xres, var->yres) ||
-		    vc->vc_font.height > FBCON_SWAP(var->rotate, var->yres, var->xres))
-			return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(fbcon_modechange_possible);
-
 int fbcon_mode_deleted(struct fb_info *info,
 		       struct fb_videomode *mode)
 {
@@ -3319,9 +3283,6 @@ static void fbcon_register_existing_fbs(struct work_struct *work)
 
 	console_lock();
 
-	deferred_takeover = false;
-	logo_shown = FBCON_LOGO_DONTSHOW;
-
 	for_each_registered_fb(i)
 		fbcon_fb_registered(registered_fb[i]);
 
@@ -3339,6 +3300,8 @@ static int fbcon_output_notifier(struct notifier_block *nb,
 	pr_info("fbcon: Taking over console\n");
 
 	dummycon_unregister_output_notifier(&fbcon_output_nb);
+	deferred_takeover = false;
+	logo_shown = FBCON_LOGO_DONTSHOW;
 
 	/* We may get called in atomic context */
 	schedule_work(&fbcon_deferred_takeover_work);
diff --git a/drivers/video/fbdev/core/fbcvt.c b/drivers/video/fbdev/core/fbcvt.c
index 6484346..55d2bd0 100644
--- a/drivers/video/fbdev/core/fbcvt.c
+++ b/drivers/video/fbdev/core/fbcvt.c
@@ -214,11 +214,9 @@ static u32 fb_cvt_aspect_ratio(struct fb_cvt_data *cvt)
 static void fb_cvt_print_name(struct fb_cvt_data *cvt)
 {
 	u32 pixcount, pixcount_mod;
-	int size = 256;
-	int off = 0;
-	u8 *buf;
+	int cnt = 255, offset = 0, read = 0;
+	u8 *buf = kzalloc(256, GFP_KERNEL);
 
-	buf = kzalloc(size, GFP_KERNEL);
 	if (!buf)
 		return;
 
@@ -226,30 +224,43 @@ static void fb_cvt_print_name(struct fb_cvt_data *cvt)
 	pixcount_mod = (cvt->xres * (cvt->yres/cvt->interlace)) % 1000000;
 	pixcount_mod /= 1000;
 
-	off += scnprintf(buf + off, size - off, "fbcvt: %dx%d@%d: CVT Name - ",
-			    cvt->xres, cvt->yres, cvt->refresh);
+	read = snprintf(buf+offset, cnt, "fbcvt: %dx%d@%d: CVT Name - ",
+			cvt->xres, cvt->yres, cvt->refresh);
+	offset += read;
+	cnt -= read;
 
-	if (cvt->status) {
-		off += scnprintf(buf + off, size - off,
-				 "Not a CVT standard - %d.%03d Mega Pixel Image\n",
-				 pixcount, pixcount_mod);
-	} else {
-		if (pixcount)
-			off += scnprintf(buf + off, size - off, "%d", pixcount);
+	if (cvt->status)
+		snprintf(buf+offset, cnt, "Not a CVT standard - %d.%03d Mega "
+			 "Pixel Image\n", pixcount, pixcount_mod);
+	else {
+		if (pixcount) {
+			read = snprintf(buf+offset, cnt, "%d", pixcount);
+			cnt -= read;
+			offset += read;
+		}
 
-		off += scnprintf(buf + off, size - off, ".%03dM", pixcount_mod);
+		read = snprintf(buf+offset, cnt, ".%03dM", pixcount_mod);
+		cnt -= read;
+		offset += read;
 
 		if (cvt->aspect_ratio == 0)
-			off += scnprintf(buf + off, size - off, "3");
+			read = snprintf(buf+offset, cnt, "3");
 		else if (cvt->aspect_ratio == 3)
-			off += scnprintf(buf + off, size - off, "4");
+			read = snprintf(buf+offset, cnt, "4");
 		else if (cvt->aspect_ratio == 1 || cvt->aspect_ratio == 4)
-			off += scnprintf(buf + off, size - off, "9");
+			read = snprintf(buf+offset, cnt, "9");
 		else if (cvt->aspect_ratio == 2)
-			off += scnprintf(buf + off, size - off, "A");
+			read = snprintf(buf+offset, cnt, "A");
+		else
+			read = 0;
+		cnt -= read;
+		offset += read;
 
-		if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK)
-			off += scnprintf(buf + off, size - off, "-R");
+		if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) {
+			read = snprintf(buf+offset, cnt, "-R");
+			cnt -= read;
+			offset += read;
+		}
 	}
 
 	printk(KERN_INFO "%s\n", buf);
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 06150a8..bf76dad 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -512,7 +512,7 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
 
 		while (n && (n * (logo->width + 8) - 8 > xres))
 			--n;
-		image.dx = (xres - (n * (logo->width + 8) - 8)) / 2;
+		image.dx = (xres - n * (logo->width + 8) - 8) / 2;
 		image.dy = y ?: (yres - logo->height) / 2;
 	} else {
 		image.dx = 0;
@@ -957,7 +957,6 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
 	struct fb_var_screeninfo old_var;
 	struct fb_videomode mode;
 	struct fb_event event;
-	u32 unused;
 
 	if (var->activate & FB_ACTIVATE_INV_MODE) {
 		struct fb_videomode mode1, mode2;
@@ -966,11 +965,13 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
 		fb_var_to_videomode(&mode2, &info->var);
 		/* make sure we don't delete the videomode of current var */
 		ret = fb_mode_is_equal(&mode1, &mode2);
-		if (!ret) {
-			ret = fbcon_mode_deleted(info, &mode1);
-			if (!ret)
-				fb_delete_videomode(&mode1, &info->modelist);
-		}
+
+		if (!ret)
+			fbcon_mode_deleted(info, &mode1);
+
+		if (!ret)
+			fb_delete_videomode(&mode1, &info->modelist);
+
 
 		return ret ? -EINVAL : 0;
 	}
@@ -1004,26 +1005,11 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
 	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)
 		return ret;
 
-	/* verify that virtual resolution >= physical resolution */
-	if (var->xres_virtual < var->xres ||
-	    var->yres_virtual < var->yres) {
-		pr_warn("WARNING: fbcon: Driver '%s' missed to adjust virtual screen size (%ux%u vs. %ux%u)\n",
-			info->fix.id,
-			var->xres_virtual, var->yres_virtual,
-			var->xres, var->yres);
-		return -EINVAL;
-	}
-
 	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
 		return 0;
 
@@ -1114,9 +1100,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			return -EFAULT;
 		console_lock();
 		lock_fb_info(info);
-		ret = fbcon_modechange_possible(info, &var);
-		if (!ret)
-			ret = fb_set_var(info, &var);
+		ret = fb_set_var(info, &var);
 		if (!ret)
 			fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
 		unlock_fb_info(info);
@@ -1176,17 +1160,13 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
 		console_unlock();
 		break;
 	default:
-		#ifndef CONFIG_AMLOGIC_MODIFY
 		lock_fb_info(info);
-		#endif
 		fb = info->fbops;
 		if (fb->fb_ioctl)
 			ret = fb->fb_ioctl(info, cmd, arg);
 		else
 			ret = -ENOTTY;
-		#ifndef CONFIG_AMLOGIC_MODIFY
 		unlock_fb_info(info);
-		#endif
 	}
 	return ret;
 }
diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c
index 6fdc6ab..b9f6a82 100644
--- a/drivers/video/fbdev/gbefb.c
+++ b/drivers/video/fbdev/gbefb.c
@@ -1269,7 +1269,7 @@ static struct platform_device *gbefb_device;
 static int __init gbefb_init(void)
 {
 	int ret = platform_driver_register(&gbefb_driver);
-	if (IS_ENABLED(CONFIG_SGI_IP32) && !ret) {
+	if (!ret) {
 		gbefb_device = platform_device_alloc("gbefb", 0);
 		if (gbefb_device) {
 			ret = platform_device_add(gbefb_device);
diff --git a/drivers/video/fbdev/hgafb.c b/drivers/video/fbdev/hgafb.c
index 03c0b1b..59e1cae 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)
-		return -ENOMEM;
+		goto error;
 
 	if (request_region(0x3b0, 12, "hgafb"))
 		release_io_ports = 1;
@@ -346,18 +346,13 @@ static int hga_card_detect(void)
 			hga_type_name = "Hercules";
 			break;
 	}
-	return 0;
+	return 1;
 error:
 	if (release_io_ports)
 		release_region(0x3b0, 12);
 	if (release_io_port)
 		release_region(0x3bf, 1);
-
-	iounmap(hga_vram);
-
-	pr_err("hgafb: HGA card not detected.\n");
-
-	return -EINVAL;
+	return 0;
 }
 
 /**
@@ -555,11 +550,13 @@ static struct fb_ops hgafb_ops = {
 static int hgafb_probe(struct platform_device *pdev)
 {
 	struct fb_info *info;
-	int ret;
 
-	ret = hga_card_detect();
-	if (ret)
-		return ret;
+	if (! hga_card_detect()) {
+		printk(KERN_INFO "hgafb: HGA card not detected.\n");
+		if (hga_vram)
+			iounmap(hga_vram);
+		return -EINVAL;
+	}
 
 	printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n",
 		hga_type_name, hga_vram_len/1024);
diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c
index 5f610d4..58b01c7 100644
--- a/drivers/video/fbdev/imsttfb.c
+++ b/drivers/video/fbdev/imsttfb.c
@@ -1512,6 +1512,11 @@ 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/imxfb.c b/drivers/video/fbdev/imxfb.c
index ffde310..b3286d1 100644
--- a/drivers/video/fbdev/imxfb.c
+++ b/drivers/video/fbdev/imxfb.c
@@ -977,7 +977,7 @@ static int imxfb_probe(struct platform_device *pdev)
 	info->screen_buffer = dma_alloc_wc(&pdev->dev, fbi->map_size,
 					   &fbi->map_dma, GFP_KERNEL);
 	if (!info->screen_buffer) {
-		dev_err(&pdev->dev, "Failed to allocate video RAM\n");
+		dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
 		ret = -ENOMEM;
 		goto failed_map;
 	}
diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c
index 74bf26b..a7bd9f2 100644
--- a/drivers/video/fbdev/kyro/fbdev.c
+++ b/drivers/video/fbdev/kyro/fbdev.c
@@ -372,11 +372,6 @@ 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);
 
@@ -399,9 +394,6 @@ 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/nvidia/nv_i2c.c b/drivers/video/fbdev/nvidia/nv_i2c.c
index 0b48965..d7994a1 100644
--- a/drivers/video/fbdev/nvidia/nv_i2c.c
+++ b/drivers/video/fbdev/nvidia/nv_i2c.c
@@ -86,7 +86,7 @@ static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name,
 {
 	int rc;
 
-	strscpy(chan->adapter.name, name, sizeof(chan->adapter.name));
+	strcpy(chan->adapter.name, name);
 	chan->adapter.owner = THIS_MODULE;
 	chan->adapter.class = i2c_class;
 	chan->adapter.algo_data = &chan->algo;
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c
index 777f6d6..b4a1aef 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c
@@ -251,7 +251,6 @@ static int dvic_probe_of(struct platform_device *pdev)
 	adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0);
 	if (adapter_node) {
 		adapter = of_get_i2c_adapter_by_node(adapter_node);
-		of_node_put(adapter_node);
 		if (adapter == NULL) {
 			dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n");
 			omap_dss_put_device(ddata->in);
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
index a2c7c5c..4b0793a 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
@@ -409,7 +409,7 @@ static ssize_t dsicm_num_errors_show(struct device *dev,
 	if (r)
 		return r;
 
-	return sysfs_emit(buf, "%d\n", errors);
+	return snprintf(buf, PAGE_SIZE, "%d\n", errors);
 }
 
 static ssize_t dsicm_hw_revision_show(struct device *dev,
@@ -439,7 +439,7 @@ static ssize_t dsicm_hw_revision_show(struct device *dev,
 	if (r)
 		return r;
 
-	return sysfs_emit(buf, "%02x.%02x.%02x\n", id1, id2, id3);
+	return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
 }
 
 static ssize_t dsicm_store_ulps(struct device *dev,
@@ -487,7 +487,7 @@ static ssize_t dsicm_show_ulps(struct device *dev,
 	t = ddata->ulps_enabled;
 	mutex_unlock(&ddata->lock);
 
-	return sysfs_emit(buf, "%u\n", t);
+	return snprintf(buf, PAGE_SIZE, "%u\n", t);
 }
 
 static ssize_t dsicm_store_ulps_timeout(struct device *dev,
@@ -532,7 +532,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *dev,
 	t = ddata->ulps_timeout;
 	mutex_unlock(&ddata->lock);
 
-	return sysfs_emit(buf, "%u\n", t);
+	return snprintf(buf, PAGE_SIZE, "%u\n", t);
 }
 
 static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL);
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c
index 0cbc5b9..1293515 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c
@@ -476,7 +476,7 @@ static ssize_t show_cabc_available_modes(struct device *dev,
 	int i;
 
 	if (!ddata->has_cabc)
-		return sysfs_emit(buf, "%s\n", cabc_modes[0]);
+		return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
 
 	for (i = 0, len = 0;
 	     len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c
index 9f6ef9e..bb85b21 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c
@@ -169,7 +169,7 @@ static ssize_t tpo_td043_vmirror_show(struct device *dev,
 {
 	struct panel_drv_data *ddata = dev_get_drvdata(dev);
 
-	return sysfs_emit(buf, "%d\n", ddata->vmirror);
+	return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror);
 }
 
 static ssize_t tpo_td043_vmirror_store(struct device *dev,
@@ -199,7 +199,7 @@ static ssize_t tpo_td043_mode_show(struct device *dev,
 {
 	struct panel_drv_data *ddata = dev_get_drvdata(dev);
 
-	return sysfs_emit(buf, "%d\n", ddata->mode);
+	return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode);
 }
 
 static ssize_t tpo_td043_mode_store(struct device *dev,
diff --git a/drivers/video/fbdev/pxa3xx-gcu.c b/drivers/video/fbdev/pxa3xx-gcu.c
index 7c4694d..74ffb44 100644
--- a/drivers/video/fbdev/pxa3xx-gcu.c
+++ b/drivers/video/fbdev/pxa3xx-gcu.c
@@ -651,7 +651,6 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev)
 	for (i = 0; i < 8; i++) {
 		ret = pxa3xx_gcu_add_buffer(dev, priv);
 		if (ret) {
-			pxa3xx_gcu_free_buffers(dev, priv);
 			dev_err(dev, "failed to allocate DMA memory\n");
 			goto err_disable_clk;
 		}
@@ -668,15 +667,15 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev)
 			SHARED_SIZE, irq);
 	return 0;
 
-err_disable_clk:
-	clk_disable_unprepare(priv->clk);
+err_free_dma:
+	dma_free_coherent(dev, SHARED_SIZE,
+			priv->shared, priv->shared_phys);
 
 err_misc_deregister:
 	misc_deregister(&priv->misc_dev);
 
-err_free_dma:
-	dma_free_coherent(dev, SHARED_SIZE,
-			  priv->shared, priv->shared_phys);
+err_disable_clk:
+	clk_disable_unprepare(priv->clk);
 
 	return ret;
 }
@@ -689,7 +688,6 @@ static int pxa3xx_gcu_remove(struct platform_device *pdev)
 	pxa3xx_gcu_wait_idle(priv);
 	misc_deregister(&priv->misc_dev);
 	dma_free_coherent(dev, SHARED_SIZE, priv->shared, priv->shared_phys);
-	clk_disable_unprepare(priv->clk);
 	pxa3xx_gcu_free_buffers(dev, priv);
 
 	return 0;
diff --git a/drivers/video/fbdev/qti/Kconfig b/drivers/video/fbdev/qti/Kconfig
new file mode 100644
index 0000000..a683816
--- /dev/null
+++ b/drivers/video/fbdev/qti/Kconfig
@@ -0,0 +1,24 @@
+config FB_QTI_QPIC
+	tristate "QPIC Framebuffer support"
+	depends on FB && ARCH_QCOM
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SYS_FOPS
+	select FB_DEFERRED_IO
+	---help---
+	  Support for QTI QPIC framebuffer.
+	  QPIC is a wrapper module provides support for LCD controller
+	  connected with parallel interfaces pins. This option provides
+	  the support for QPIC framebuffer which can be used for display
+	  operations for QPIC LCD.
+
+config FB_QTI_QPIC_ER_SSD1963_PANEL
+	tristate "Qpic MIPI ER ssd1963 Panel"
+	depends on FB_QTI_QPIC
+	---help---
+	  Support for MIPI ER ssd1963  (800x480) panel
+	  EAST Rising TECHNOLOGY ssd1963
+	  with on-chip full display RAM
+	  use 9-bit parallel interface
+
diff --git a/drivers/video/fbdev/qti/Makefile b/drivers/video/fbdev/qti/Makefile
new file mode 100644
index 0000000..8ba73e9
--- /dev/null
+++ b/drivers/video/fbdev/qti/Makefile
@@ -0,0 +1,7 @@
+ccflags-y += -I$(src)
+ccflags-y += -I$(srctree)/arch/arm/mach-qcom/include
+ccflags-y += -I$(srctree)/arch/arm/mach-qcom
+
+mdss-qpic-objs := mdss_qpic.o mdss_fb.o mdss_qpic_panel.o
+obj-$(CONFIG_FB_QTI_QPIC) += mdss-qpic.o
+obj-$(CONFIG_FB_QTI_QPIC_ER_SSD1963_PANEL) += qpic_panel_er_ssd1963.o
diff --git a/drivers/video/fbdev/qti/mdss_fb.c b/drivers/video/fbdev/qti/mdss_fb.c
new file mode 100644
index 0000000..3721e07
--- /dev/null
+++ b/drivers/video/fbdev/qti/mdss_fb.c
@@ -0,0 +1,1142 @@
+/*
+ * Core MDSS framebuffer driver.
+ *
+ * Copyright (C) 2007 Google Incorporated
+ * Copyright (c) 2008-2014, 2020 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "mdss_fb.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MDSS_FB_NUM 3
+#else
+#define MDSS_FB_NUM 2
+#endif
+
+#ifndef EXPORT_COMPAT
+#define EXPORT_COMPAT(x)
+#endif
+
+#define MAX_FBI_LIST 32
+
+#define BLANK_FLAG_LP	FB_BLANK_VSYNC_SUSPEND
+#define BLANK_FLAG_ULP	FB_BLANK_NORMAL
+
+#define DEFERRED_IO_REFRESH_RATE	25
+#define DEFERRED_IO_DELAY		(HZ / DEFERRED_IO_REFRESH_RATE)
+
+enum {
+	MDP_RGB_565,      /* RGB 565 planer */
+	MDP_XRGB_8888,    /* RGB 888 padded */
+	MDP_ARGB_8888,    /* ARGB 888 */
+	MDP_RGB_888,      /* RGB 888 planer */
+	MDP_RGBA_8888,    /* ARGB 888 */
+	MDP_BGRA_8888,	  /* ABGR 888 */
+	MDP_BGR_565,      /* BGR 565 planer */
+};
+
+static struct fb_info *fbi_list[MAX_FBI_LIST];
+static int fbi_list_index;
+
+static u32 mdss_fb_pseudo_palette[16] = {
+	0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+};
+
+static struct msm_mdp_interface *mdp_instance;
+static struct fb_deferred_io mdss_fb_defio;
+
+static int mdss_fb_register(struct msm_fb_data_type *mfd);
+static int mdss_fb_open(struct fb_info *info, int user);
+static int mdss_fb_release(struct fb_info *info, int user);
+static int mdss_fb_release_all(struct fb_info *info, bool release_all);
+static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info);
+static int mdss_fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info);
+static int mdss_fb_set_par(struct fb_info *info);
+static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
+			     int op_enable);
+static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd);
+
+static void mdss_fb_shutdown(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+	lock_fb_info(mfd->fbi);
+	mdss_fb_release_all(mfd->fbi, true);
+	unlock_fb_info(mfd->fbi);
+}
+
+static int mdss_fb_probe(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd = NULL;
+	struct mdss_panel_data *pdata;
+	struct fb_info *fbi;
+	int rc;
+
+	if (fbi_list_index >= MAX_FBI_LIST)
+		return -ENOMEM;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata)
+		return -EPROBE_DEFER;
+
+	/*
+	 * alloc framebuffer info + par data
+	 */
+	fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
+	if (fbi == NULL) {
+		pr_err("can't allocate framebuffer info data!\n");
+		return -ENOMEM;
+	}
+
+	mfd = (struct msm_fb_data_type *)fbi->par;
+	mfd->key = MFD_KEY;
+	mfd->fbi = fbi;
+	mfd->panel_info = &pdata->panel_info;
+	mfd->panel.type = pdata->panel_info.type;
+	mfd->panel.id = mfd->index;
+	mfd->fb_page = MDSS_FB_NUM;
+	mfd->index = fbi_list_index;
+
+	mfd->fb_imgType = MDP_RGBA_8888;
+
+	mfd->fbi->fbdefio = &mdss_fb_defio;
+	mfd->pdev = pdev;
+
+	mfd->mdp = *mdp_instance;
+
+	fbi_list[fbi_list_index++] = fbi;
+
+	platform_set_drvdata(pdev, mfd);
+
+	rc = mdss_fb_register(mfd);
+	if (rc)
+		return rc;
+
+	if (mfd->mdp.init_fnc) {
+		rc = mfd->mdp.init_fnc(mfd);
+		if (rc) {
+			pr_err("init_fnc failed\n");
+			return rc;
+		}
+	}
+
+	rc = pm_runtime_set_active(mfd->fbi->dev);
+	if (rc < 0)
+		pr_err("pm_runtime: fail to set active.\n");
+	pm_runtime_enable(mfd->fbi->dev);
+
+	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;
+
+	pm_runtime_disable(mfd->fbi->dev);
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	if (mdss_fb_suspend_sub(mfd))
+		pr_err("msm_fb_remove: can't stop the device %d\n",
+			    mfd->index);
+
+	fb_deferred_io_cleanup(mfd->fbi);
+	/* remove /dev/fb* */
+	unregister_framebuffer(mfd->fbi);
+
+	return 0;
+}
+
+static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	pr_debug("mdss_fb suspend index=%d\n", mfd->index);
+
+	mfd->suspend.op_enable = mfd->op_enable;
+	mfd->suspend.panel_power_state = mfd->panel_power_state;
+
+	if (mfd->op_enable) {
+		/*
+		 * Ideally, display should have either been blanked by now, or
+		 * should have transitioned to a low power state. If not, then
+		 * as a fall back option, enter ulp state to leave the display
+		 * on, but turn off all interface clocks.
+		 */
+		if (mdss_fb_is_power_on(mfd)) {
+			ret = mdss_fb_blank_sub(BLANK_FLAG_ULP, mfd->fbi,
+					mfd->suspend.op_enable);
+			if (ret) {
+				pr_err("can't turn off display!\n");
+				return ret;
+			}
+		}
+		mfd->op_enable = false;
+		fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED);
+	}
+
+	return 0;
+}
+
+static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	pr_debug("mdss_fb resume index=%d\n", mfd->index);
+
+	/* resume state var recover */
+	mfd->op_enable = mfd->suspend.op_enable;
+
+	/*
+	 * If the fb was explicitly blanked or transitioned to ulp during
+	 * suspend, then undo it during resume with the appropriate unblank
+	 * flag. If fb was in ulp state when entering suspend, then nothing
+	 * needs to be done.
+	 */
+	if (mdss_panel_is_power_on(mfd->suspend.panel_power_state) &&
+		!mdss_panel_is_power_on_ulp(mfd->suspend.panel_power_state)) {
+		int unblank_flag = mdss_panel_is_power_on_interactive(
+			mfd->suspend.panel_power_state) ? FB_BLANK_UNBLANK :
+			BLANK_FLAG_LP;
+
+		ret = mdss_fb_blank_sub(unblank_flag, mfd->fbi, mfd->op_enable);
+		if (ret)
+			pr_warn("can't turn on display!\n");
+		else
+			fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
+	}
+
+	return ret;
+}
+
+#if defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP)
+static int mdss_fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+	if (!mfd)
+		return -ENODEV;
+
+	dev_dbg(&pdev->dev, "display suspend\n");
+
+	return mdss_fb_suspend_sub(mfd);
+}
+
+static int mdss_fb_resume(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+	if (!mfd)
+		return -ENODEV;
+
+	dev_dbg(&pdev->dev, "display resume\n");
+
+	return mdss_fb_resume_sub(mfd);
+}
+#else
+#define mdss_fb_suspend NULL
+#define mdss_fb_resume NULL
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int mdss_fb_pm_suspend(struct device *dev)
+{
+	struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+
+	if (!mfd)
+		return -ENODEV;
+
+	dev_dbg(dev, "display pm suspend\n");
+
+	return mdss_fb_suspend_sub(mfd);
+}
+
+static int mdss_fb_pm_resume(struct device *dev)
+{
+	struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+	if (!mfd)
+		return -ENODEV;
+
+	dev_dbg(dev, "display pm resume\n");
+
+	/*
+	 * It is possible that the runtime status of the fb device may
+	 * have been active when the system was suspended. Reset the runtime
+	 * status to suspended state after a complete system resume.
+	 */
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_enable(dev);
+
+	return mdss_fb_resume_sub(mfd);
+}
+#endif
+
+static const struct dev_pm_ops mdss_fb_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mdss_fb_pm_suspend, mdss_fb_pm_resume)
+};
+
+static const struct of_device_id mdss_fb_dt_match[] = {
+	{ .compatible = "qti,mdss-fb",},
+	{}
+};
+EXPORT_COMPAT("qti,mdss-fb");
+
+static struct platform_driver mdss_fb_driver = {
+	.probe = mdss_fb_probe,
+	.remove = mdss_fb_remove,
+	.suspend = mdss_fb_suspend,
+	.resume = mdss_fb_resume,
+	.shutdown = mdss_fb_shutdown,
+	.driver = {
+		.name = "mdss_fb",
+		.of_match_table = mdss_fb_dt_match,
+		.pm = &mdss_fb_pm_ops,
+	},
+};
+
+static int mdss_fb_blank_blank(struct msm_fb_data_type *mfd,
+	int req_power_state)
+{
+	int ret = 0;
+	int cur_power_state;
+
+	if (!mfd)
+		return -EINVAL;
+
+	if (!mdss_fb_is_power_on(mfd) || !mfd->mdp.off_fnc)
+		return 0;
+
+	cur_power_state = mfd->panel_power_state;
+
+	pr_debug("Transitioning from %d --> %d\n", cur_power_state,
+		req_power_state);
+
+	if (cur_power_state == req_power_state) {
+		pr_debug("No change in power state\n");
+		return 0;
+	}
+
+	mfd->op_enable = false;
+	mfd->panel_power_state = req_power_state;
+
+	ret = mfd->mdp.off_fnc(mfd);
+	if (ret)
+		mfd->panel_power_state = cur_power_state;
+	mfd->op_enable = true;
+
+	return ret;
+}
+
+static int mdss_fb_blank_unblank(struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+	int cur_power_state;
+
+	if (!mfd)
+		return -EINVAL;
+
+	cur_power_state = mfd->panel_power_state;
+	pr_debug("Transitioning from %d --> %d\n", cur_power_state,
+		MDSS_PANEL_POWER_ON);
+
+	if (mdss_panel_is_power_on_interactive(cur_power_state)) {
+		pr_debug("No change in power state\n");
+		return 0;
+	}
+
+	if (mfd->mdp.on_fnc) {
+		ret = mfd->mdp.on_fnc(mfd);
+		if (ret)
+			goto error;
+
+		mfd->panel_power_state = MDSS_PANEL_POWER_ON;
+		mfd->panel_info->panel_dead = false;
+
+	}
+
+error:
+	return ret;
+}
+
+static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
+			     int op_enable)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int ret = 0;
+	int cur_power_state, req_power_state = MDSS_PANEL_POWER_OFF;
+
+	if (!mfd || !op_enable)
+		return -EPERM;
+
+	pr_debug("%pS mode:%d\n", __builtin_return_address(0),
+		blank_mode);
+
+	cur_power_state = mfd->panel_power_state;
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		pr_debug("unblank called. cur pwr state=%d\n", cur_power_state);
+		ret = mdss_fb_blank_unblank(mfd);
+		break;
+	case BLANK_FLAG_ULP:
+		req_power_state = MDSS_PANEL_POWER_LP2;
+		pr_debug("ultra low power mode requested\n");
+		if (mdss_fb_is_power_off(mfd)) {
+			pr_debug("Unsupp transition: off --> ulp\n");
+			return 0;
+		}
+
+		ret = mdss_fb_blank_blank(mfd, req_power_state);
+		break;
+	case BLANK_FLAG_LP:
+		req_power_state = MDSS_PANEL_POWER_LP1;
+		pr_debug(" power mode requested\n");
+
+		/*
+		 * If low power mode is requested when panel is already off,
+		 * then first unblank the panel before entering low power mode
+		 */
+		if (mdss_fb_is_power_off(mfd) && mfd->mdp.on_fnc) {
+			pr_debug("off --> lp. switch to on first\n");
+			ret = mdss_fb_blank_unblank(mfd);
+			if (ret)
+				break;
+		}
+
+		ret = mdss_fb_blank_blank(mfd, req_power_state);
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+	default:
+		req_power_state = MDSS_PANEL_POWER_OFF;
+		pr_debug("blank powerdown called\n");
+		ret = mdss_fb_blank_blank(mfd, req_power_state);
+		break;
+	}
+
+	return ret;
+}
+
+static void mdss_fb_deferred_io(struct fb_info *info,
+				struct list_head *pagelist)
+{
+	mdss_fb_pan_display(&info->var, info);
+}
+
+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;
+
+	if (mfd->op_enable == 0) {
+		if (blank_mode == FB_BLANK_UNBLANK)
+			mfd->suspend.panel_power_state = MDSS_PANEL_POWER_ON;
+		else if (blank_mode == BLANK_FLAG_ULP)
+			mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP2;
+		else if (blank_mode == BLANK_FLAG_LP)
+			mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP1;
+		else
+			mfd->suspend.panel_power_state = MDSS_PANEL_POWER_OFF;
+		return 0;
+	}
+	pr_debug("mode: %d\n", blank_mode);
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+
+	if (pdata->panel_info.is_lpm_mode &&
+			blank_mode == FB_BLANK_UNBLANK) {
+		pr_debug("panel is in lpm mode\n");
+		mfd->mdp.configure_panel(mfd, 0);
+		pdata->panel_info.is_lpm_mode = false;
+	}
+
+	return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
+}
+
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+
+	return dma_mmap_coherent(info->dev, vma,
+				     info->screen_base,
+				     info->fix.smem_start,
+				     info->fix.smem_len);
+}
+
+static struct fb_ops mdss_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = mdss_fb_open,
+	.fb_release = mdss_fb_release,
+	.fb_check_var = mdss_fb_check_var,	/* vinfo check */
+	.fb_set_par = mdss_fb_set_par,	/* set the video mode */
+	.fb_blank = mdss_fb_blank,	/* blank display */
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_mmap = mdss_fb_mmap,
+};
+
+static struct fb_deferred_io mdss_fb_defio = {
+	.delay		= DEFERRED_IO_DELAY,
+	.deferred_io	= mdss_fb_deferred_io,
+};
+
+static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
+{
+
+	if (mfd->mdp.fb_mem_alloc_fnc) {
+		return mfd->mdp.fb_mem_alloc_fnc(mfd);
+	} else {
+		pr_err("no fb memory allocator function defined\n");
+		return -ENOMEM;
+	}
+}
+
+static int mdss_fb_register(struct msm_fb_data_type *mfd)
+{
+	int ret = -ENODEV;
+	int bpp;
+	struct mdss_panel_info *panel_info = mfd->panel_info;
+	struct fb_info *fbi = mfd->fbi;
+	struct fb_fix_screeninfo *fix;
+	struct fb_var_screeninfo *var;
+	int *id;
+
+	/*
+	 * fb info initialization
+	 */
+	fix = &fbi->fix;
+	var = &fbi->var;
+
+	fix->type_aux = 0;	/* if type == FB_TYPE_INTERLEAVED_PLANES */
+	fix->visual = FB_VISUAL_TRUECOLOR;	/* True Color */
+	fix->ywrapstep = 0;	/* No support */
+	fix->mmio_start = 0;	/* No MMIO Address */
+	fix->mmio_len = 0;	/* No MMIO Address */
+	fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */
+
+	var->xoffset = 0,	/* Offset from virtual to visible */
+	var->yoffset = 0,	/* resolution */
+	var->grayscale = 0,	/* No graylevels */
+	var->nonstd = 0,	/* standard pixel format */
+	var->activate = FB_ACTIVATE_VBL,	/* activate it at vsync */
+	var->height = -1,	/* height of picture in mm */
+	var->width = -1,	/* width of picture in mm */
+	var->accel_flags = 0,	/* acceleration flags */
+	var->sync = 0,	/* see FB_SYNC_* */
+	var->rotate = 0,	/* angle we rotate counter clockwise */
+	mfd->op_enable = false;
+
+	switch (mfd->fb_imgType) {
+	case MDP_RGB_565:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 11;
+		var->blue.length = 5;
+		var->green.length = 6;
+		var->red.length = 5;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		bpp = 2;
+		break;
+
+	case MDP_RGB_888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 0;
+		var->green.offset = 8;
+		var->red.offset = 16;
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		bpp = 3;
+		break;
+
+	case MDP_ARGB_8888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 24;
+		var->green.offset = 16;
+		var->red.offset = 8;
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 8;
+		bpp = 4;
+		break;
+
+	case MDP_RGBA_8888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 16;
+		var->green.offset = 8;
+		var->red.offset = 0;
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		bpp = 4;
+		break;
+
+	default:
+		pr_err("msm_fb_init: fb %d unkown image type!\n",
+			    mfd->index);
+		return ret;
+	}
+
+	var->xres = panel_info->xres;
+
+	fix->type = panel_info->is_3d_panel;
+	if (mfd->mdp.fb_stride)
+		fix->line_length = mfd->mdp.fb_stride(mfd->index, var->xres,
+							bpp);
+	else
+		fix->line_length = var->xres * bpp;
+
+	var->yres = panel_info->yres;
+	if (panel_info->physical_width)
+		var->width = panel_info->physical_width;
+	if (panel_info->physical_height)
+		var->height = panel_info->physical_height;
+	var->xres_virtual = var->xres;
+	var->yres_virtual = panel_info->yres * mfd->fb_page;
+	var->bits_per_pixel = bpp * 8;	/* FrameBuffer color depth */
+	var->upper_margin = panel_info->lcdc.v_back_porch;
+	var->lower_margin = panel_info->lcdc.v_front_porch;
+	var->vsync_len = panel_info->lcdc.v_pulse_width;
+	var->left_margin = panel_info->lcdc.h_back_porch;
+	var->right_margin = panel_info->lcdc.h_front_porch;
+	var->hsync_len = panel_info->lcdc.h_pulse_width;
+	var->pixclock = panel_info->clk_rate / 1000;
+
+	/*
+	 * 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);
+
+	fbi->fbops = &mdss_fb_ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT | FBINFO_DMAFB;
+	fbi->pseudo_palette = mdss_fb_pseudo_palette;
+
+	mfd->ref_cnt = 0;
+	mfd->panel_power_state = MDSS_PANEL_POWER_OFF;
+
+	if (mdss_fb_alloc_fbmem(mfd))
+		pr_warn("unable to allocate fb memory in fb register\n");
+
+	mfd->op_enable = true;
+
+	fb_deferred_io_init(mfd->fbi);
+	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+	if (ret)
+		pr_err("fb_alloc_cmap() failed!\n");
+
+	if (register_framebuffer(fbi) < 0) {
+		fb_dealloc_cmap(&fbi->cmap);
+
+		mfd->op_enable = false;
+		return -EPERM;
+	}
+
+	pr_info("FrameBuffer[%d] %dx%d registered successfully!\n", mfd->index,
+					fbi->var.xres, fbi->var.yres);
+
+	return 0;
+}
+
+static int mdss_fb_open(struct fb_info *info, int user)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int result;
+
+
+	result = pm_runtime_get_sync(info->dev);
+
+	if (result < 0) {
+		pr_err("pm_runtime: fail to wake up\n");
+		goto pm_error;
+	}
+
+	if (!mfd->ref_cnt) {
+		result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
+					   mfd->op_enable);
+		if (result) {
+			pr_err("can't turn on fb%d! rc=%d\n", mfd->index,
+				result);
+			goto blank_error;
+		}
+	}
+
+	mfd->ref_cnt++;
+
+	return 0;
+
+blank_error:
+	pm_runtime_put(info->dev);
+
+pm_error:
+	return result;
+}
+
+static int mdss_fb_release_all(struct fb_info *info, bool release_all)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int ret = 0;
+	bool release_needed = false;
+
+	if (!mfd->ref_cnt) {
+		pr_info("try to close unopened fb %d!\n", mfd->index);
+		return -EINVAL;
+	}
+
+	pr_debug("release_all = %s\n", release_all ? "true" : "false");
+
+	mfd->ref_cnt--;
+
+	if (!mfd->ref_cnt || release_all) {
+		/* resources (if any) will be released during blank */
+		if (mfd->mdp.release_fnc)
+			mfd->mdp.release_fnc(mfd, true);
+
+		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
+			mfd->op_enable);
+		if (ret) {
+			pr_err("can't turn off fb%d!\n", ret);
+			return ret;
+		}
+	} else if (release_needed) {
+		if (mfd->mdp.release_fnc) {
+			ret = mfd->mdp.release_fnc(mfd, false);
+
+			/* display commit is needed to release resources */
+			if (ret)
+				mdss_fb_pan_display(&mfd->fbi->var, mfd->fbi);
+		}
+	}
+
+	return ret;
+}
+
+static int mdss_fb_release(struct fb_info *info, int user)
+{
+	return mdss_fb_release_all(info, false);
+}
+
+static int mdss_fb_pan_display_sub(struct fb_var_screeninfo *var,
+			       struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	if (!mfd->op_enable)
+		return -EPERM;
+
+	if (var->xoffset > (info->var.xres_virtual - info->var.xres))
+		return -EINVAL;
+
+	if (var->yoffset > (info->var.yres_virtual - info->var.yres))
+		return -EINVAL;
+
+	if (info->fix.xpanstep)
+		info->var.xoffset =
+		(var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
+
+	if (info->fix.ypanstep)
+		info->var.yoffset =
+		(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
+
+	if (mfd->mdp.dma_fnc)
+		mfd->mdp.dma_fnc(mfd);
+	else
+		pr_warn("dma function not set for panel type=%d\n",
+				mfd->panel.type);
+
+	return 0;
+}
+
+static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	return mdss_fb_pan_display_sub(var, info);
+}
+
+static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var,
+	struct mdss_panel_info *pinfo)
+{
+	pinfo->xres = var->xres;
+	pinfo->yres = var->yres;
+	pinfo->lcdc.v_front_porch = var->lower_margin;
+	pinfo->lcdc.v_back_porch = var->upper_margin;
+	pinfo->lcdc.v_pulse_width = var->vsync_len;
+	pinfo->lcdc.h_front_porch = var->right_margin;
+	pinfo->lcdc.h_back_porch = var->left_margin;
+	pinfo->lcdc.h_pulse_width = var->hsync_len;
+	pinfo->clk_rate = var->pixclock;
+}
+
+static int mdss_fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	if (var->rotate != FB_ROTATE_UR)
+		return -EINVAL;
+	if (var->grayscale != info->var.grayscale)
+		return -EINVAL;
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		if ((var->green.offset != 5) ||
+		    !((var->blue.offset == 11)
+		      || (var->blue.offset == 0)) ||
+		    !((var->red.offset == 11)
+		      || (var->red.offset == 0)) ||
+		    (var->blue.length != 5) ||
+		    (var->green.length != 6) ||
+		    (var->red.length != 5) ||
+		    (var->blue.msb_right != 0) ||
+		    (var->green.msb_right != 0) ||
+		    (var->red.msb_right != 0) ||
+		    (var->transp.offset != 0) ||
+		    (var->transp.length != 0))
+			return -EINVAL;
+		break;
+
+	case 24:
+		if ((var->blue.offset != 0) ||
+		    (var->green.offset != 8) ||
+		    (var->red.offset != 16) ||
+		    (var->blue.length != 8) ||
+		    (var->green.length != 8) ||
+		    (var->red.length != 8) ||
+		    (var->blue.msb_right != 0) ||
+		    (var->green.msb_right != 0) ||
+		    (var->red.msb_right != 0) ||
+		    !(((var->transp.offset == 0) &&
+		       (var->transp.length == 0)) ||
+		      ((var->transp.offset == 24) &&
+		       (var->transp.length == 8))))
+			return -EINVAL;
+		break;
+
+	case 32:
+		/* Check user specified color format BGRA/ARGB/RGBA
+		   and verify the position of the RGB components */
+
+		if (!((var->transp.offset == 24) &&
+			(var->blue.offset == 0) &&
+			(var->green.offset == 8) &&
+			(var->red.offset == 16)) &&
+		    !((var->transp.offset == 24) &&
+			(var->blue.offset == 16) &&
+			(var->green.offset == 8) &&
+			(var->red.offset == 0)))
+				return -EINVAL;
+
+		/* Check the common values for both RGBA and ARGB */
+
+		if ((var->blue.length != 8) ||
+		    (var->green.length != 8) ||
+		    (var->red.length != 8) ||
+		    (var->transp.length != 8) ||
+		    (var->blue.msb_right != 0) ||
+		    (var->green.msb_right != 0) ||
+		    (var->red.msb_right != 0))
+			return -EINVAL;
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
+		return -EINVAL;
+
+	if (info->fix.smem_start) {
+		u32 len = var->xres_virtual * var->yres_virtual *
+			(var->bits_per_pixel / 8);
+		if (len > info->fix.smem_len)
+			return -EINVAL;
+	}
+
+	if ((var->xres == 0) || (var->yres == 0))
+		return -EINVAL;
+
+	if (var->xoffset > (var->xres_virtual - var->xres))
+		return -EINVAL;
+
+	if (var->yoffset > (var->yres_virtual - var->yres))
+		return -EINVAL;
+
+	if (mfd->panel_info) {
+		struct mdss_panel_info panel_info;
+
+		memcpy(&panel_info, mfd->panel_info, sizeof(panel_info));
+		mdss_fb_var_to_panelinfo(var, &panel_info);
+		mfd->panel_reconfig = true;
+	}
+
+	return 0;
+}
+
+static int mdss_fb_set_par(struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	int old_imgType;
+
+	old_imgType = mfd->fb_imgType;
+	switch (var->bits_per_pixel) {
+	case 16:
+		if (var->red.offset == 0)
+			mfd->fb_imgType = MDP_BGR_565;
+		else
+			mfd->fb_imgType	= MDP_RGB_565;
+		break;
+
+	case 24:
+		if ((var->transp.offset == 0) && (var->transp.length == 0))
+			mfd->fb_imgType = MDP_RGB_888;
+		else if ((var->transp.offset == 24) &&
+			 (var->transp.length == 8)) {
+			mfd->fb_imgType = MDP_ARGB_8888;
+			info->var.bits_per_pixel = 32;
+		}
+		break;
+
+	case 32:
+		if ((var->red.offset == 0) &&
+		    (var->green.offset == 8) &&
+		    (var->blue.offset == 16) &&
+		    (var->transp.offset == 24))
+			mfd->fb_imgType = MDP_RGBA_8888;
+		else if ((var->red.offset == 16) &&
+		    (var->green.offset == 8) &&
+		    (var->blue.offset == 0) &&
+		    (var->transp.offset == 24))
+			mfd->fb_imgType = MDP_BGRA_8888;
+		else if ((var->red.offset == 8) &&
+		    (var->green.offset == 16) &&
+		    (var->blue.offset == 24) &&
+		    (var->transp.offset == 0))
+			mfd->fb_imgType = MDP_ARGB_8888;
+		else
+			mfd->fb_imgType = MDP_RGBA_8888;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+
+	if (mfd->mdp.fb_stride)
+		mfd->fbi->fix.line_length = mfd->mdp.fb_stride(mfd->index,
+						var->xres,
+						var->bits_per_pixel / 8);
+	else
+		mfd->fbi->fix.line_length = var->xres * var->bits_per_pixel / 8;
+
+	mfd->fbi->fix.smem_len = PAGE_ALIGN(mfd->fbi->fix.line_length *
+					mfd->fbi->var.yres) * mfd->fb_page;
+
+	if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
+		mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
+		mdss_fb_var_to_panelinfo(var, mfd->panel_info);
+		mdss_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
+		mfd->panel_reconfig = false;
+	}
+
+	return 0;
+}
+
+static int mdss_fb_register_extra_panel(struct platform_device *pdev,
+	struct mdss_panel_data *pdata)
+{
+	struct mdss_panel_data *fb_pdata;
+
+	fb_pdata = dev_get_platdata(&pdev->dev);
+	if (!fb_pdata) {
+		pr_err("framebuffer device %s contains invalid panel data\n",
+				dev_name(&pdev->dev));
+		return -EINVAL;
+	}
+
+	if (fb_pdata->next) {
+		pr_err("split panel already setup for framebuffer device %s\n",
+				dev_name(&pdev->dev));
+		return -EEXIST;
+	}
+
+	fb_pdata->next = pdata;
+
+	return 0;
+}
+
+int mdss_register_panel(struct platform_device *pdev,
+	struct mdss_panel_data *pdata)
+{
+	struct platform_device *fb_pdev, *mdss_pdev;
+	struct device_node *node;
+	int rc = 0;
+	bool master_panel = true;
+
+	if (!pdev || !pdev->dev.of_node) {
+		pr_err("Invalid device node\n");
+		return -ENODEV;
+	}
+
+	if (!mdp_instance) {
+		pr_err("mdss mdp resource not initialized yet\n");
+		return -EPROBE_DEFER;
+	}
+
+	node = of_parse_phandle(pdev->dev.of_node, "qti,mdss-fb-map", 0);
+	if (!node) {
+		pr_err("Unable to find fb node for device: %s\n",
+				pdev->name);
+		return -ENODEV;
+	}
+	mdss_pdev = of_find_device_by_node(node->parent);
+	if (!mdss_pdev) {
+		pr_err("Unable to find mdss for node: %s\n", node->full_name);
+		rc = -ENODEV;
+		goto mdss_notfound;
+	}
+
+	fb_pdev = of_find_device_by_node(node);
+	if (fb_pdev) {
+		rc = mdss_fb_register_extra_panel(fb_pdev, pdata);
+		if (rc == 0)
+			master_panel = false;
+	} else {
+		pr_info("adding framebuffer device %s\n", dev_name(&pdev->dev));
+		fb_pdev = of_platform_device_create(node, NULL,
+				&mdss_pdev->dev);
+		if (fb_pdev)
+			fb_pdev->dev.platform_data = pdata;
+	}
+
+	if (master_panel && mdp_instance->panel_register_done)
+		mdp_instance->panel_register_done(pdata);
+
+mdss_notfound:
+	of_node_put(node);
+	return rc;
+}
+EXPORT_SYMBOL(mdss_register_panel);
+
+int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp)
+{
+	if (mdp_instance) {
+		pr_err("multiple MDP instance registration\n");
+		return -EINVAL;
+	}
+
+	mdp_instance = mdp;
+	return 0;
+}
+EXPORT_SYMBOL(mdss_fb_register_mdp_instance);
+
+int mdss_fb_get_phys_info(dma_addr_t *start, unsigned long *len, int fb_num)
+{
+	struct fb_info *info;
+	struct msm_fb_data_type *mfd;
+
+	if (fb_num >= MAX_FBI_LIST)
+		return -EINVAL;
+
+	info = fbi_list[fb_num];
+	if (!info)
+		return -ENOENT;
+
+	mfd = (struct msm_fb_data_type *)info->par;
+	if (!mfd)
+		return -ENODEV;
+
+	*start = info->fix.smem_start;
+	*len = info->fix.smem_len;
+
+	return 0;
+}
+EXPORT_SYMBOL(mdss_fb_get_phys_info);
+
+int __init mdss_fb_init(void)
+{
+	int rc = -ENODEV;
+
+	if (platform_driver_register(&mdss_fb_driver))
+		return rc;
+
+	return 0;
+}
+
+module_init(mdss_fb_init);
+
diff --git a/drivers/video/fbdev/qti/mdss_fb.h b/drivers/video/fbdev/qti/mdss_fb.h
new file mode 100644
index 0000000..9ae7c42
--- /dev/null
+++ b/drivers/video/fbdev/qti/mdss_fb.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2008-2014, 2020 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
+ * 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_FB_H
+#define MDSS_FB_H
+
+#include <linux/fb.h>
+#include <linux/types.h>
+
+#include "mdss_panel.h"
+
+#define MSM_FB_DEFAULT_PAGE_SIZE 2
+#define MFD_KEY  0x11161126
+#define MSM_FB_MAX_DEV_LIST 32
+
+struct disp_info_type_suspend {
+	int op_enable;
+	int panel_power_state;
+};
+struct msm_fb_data_type;
+
+struct msm_mdp_interface {
+	int (*fb_mem_alloc_fnc)(struct msm_fb_data_type *mfd);
+	int (*init_fnc)(struct msm_fb_data_type *mfd);
+	int (*on_fnc)(struct msm_fb_data_type *mfd);
+	int (*off_fnc)(struct msm_fb_data_type *mfd);
+	/* called to release resources associated to the process */
+	int (*release_fnc)(struct msm_fb_data_type *mfd, bool release_all);
+	int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
+	void (*dma_fnc)(struct msm_fb_data_type *mfd);
+	int (*cursor_update)(struct msm_fb_data_type *mfd,
+				struct fb_cursor *cursor);
+	int (*panel_register_done)(struct mdss_panel_data *pdata);
+	u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
+	int (*configure_panel)(struct msm_fb_data_type *mfd, int mode);
+	void *private1;
+};
+
+struct msm_fb_data_type {
+	u32 key;
+	u32 index;
+	u32 ref_cnt;
+	u32 fb_page;
+
+	struct panel_id panel;
+	struct mdss_panel_info *panel_info;
+
+	u32 dest;
+	struct fb_info *fbi;
+
+	int op_enable;
+	u32 fb_imgType;
+	int panel_reconfig;
+
+	u32 dst_format;
+	int panel_power_state;
+	struct disp_info_type_suspend suspend;
+
+	struct platform_device *pdev;
+
+	struct msm_mdp_interface mdp;
+};
+
+static inline bool mdss_fb_is_power_off(struct msm_fb_data_type *mfd)
+{
+	return mdss_panel_is_power_off(mfd->panel_power_state);
+}
+
+static inline bool mdss_fb_is_power_on_interactive(
+	struct msm_fb_data_type *mfd)
+{
+	return mdss_panel_is_power_on_interactive(mfd->panel_power_state);
+}
+
+static inline bool mdss_fb_is_power_on(struct msm_fb_data_type *mfd)
+{
+	return mdss_panel_is_power_on(mfd->panel_power_state);
+}
+
+static inline bool mdss_fb_is_power_on_lp(struct msm_fb_data_type *mfd)
+{
+	return mdss_panel_is_power_on_lp(mfd->panel_power_state);
+}
+
+int mdss_fb_get_phys_info(dma_addr_t *start, unsigned long *len, int fb_num);
+int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
+int mdss_fb_suspres_panel(struct device *dev, void *data);
+int mdss_fb_do_ioctl(struct fb_info *info, unsigned int cmd,
+		     unsigned long arg);
+int mdss_fb_compat_ioctl(struct fb_info *info, unsigned int cmd,
+			 unsigned long arg);
+#endif /* MDSS_FB_H */
diff --git a/drivers/video/fbdev/qti/mdss_panel.h b/drivers/video/fbdev/qti/mdss_panel.h
new file mode 100644
index 0000000..9a87df5
--- /dev/null
+++ b/drivers/video/fbdev/qti/mdss_panel.h
@@ -0,0 +1,219 @@
+/* Copyright (c) 2008-2014, 2020 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
+ * 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_PANEL_H
+#define MDSS_PANEL_H
+
+#include <linux/platform_device.h>
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/debugfs.h>
+
+/* panel id type */
+struct panel_id {
+	u16 id;
+	u16 type;
+};
+
+#define DEFAULT_FRAME_RATE	60
+#define DEFAULT_ROTATOR_FRAME_RATE 120
+#define MDSS_DSI_RST_SEQ_LEN	10
+#define MDSS_MDP_MAX_FETCH 12
+
+/* panel type list */
+#define NO_PANEL		0xffff	/* No Panel */
+#define EBI2_PANEL		1	/* EBI2 */
+
+/* panel class */
+enum {
+	DISPLAY_LCD = 0,	/* lcd = ebi2/mddi */
+	DISPLAY_LCDC,		/* lcdc */
+	DISPLAY_TV,		/* TV Out */
+	DISPLAY_EXT_MDDI,	/* External MDDI */
+	DISPLAY_WRITEBACK,
+};
+
+enum {
+	DISPLAY_1 = 0,		/* attached as first device */
+	MAX_PHYS_TARGET_NUM,
+};
+
+enum {
+	MDSS_PANEL_POWER_OFF = 0,
+	MDSS_PANEL_POWER_ON,
+	MDSS_PANEL_POWER_LP1,
+	MDSS_PANEL_POWER_LP2,
+};
+
+enum {
+	MDSS_PANEL_BLANK_BLANK = 0,
+	MDSS_PANEL_BLANK_UNBLANK,
+	MDSS_PANEL_BLANK_LOW_POWER,
+};
+
+struct lcd_panel_info {
+	u32 h_back_porch;
+	u32 h_front_porch;
+	u32 h_pulse_width;
+	u32 v_back_porch;
+	u32 v_front_porch;
+	u32 v_pulse_width;
+	u32 border_clr;
+	u32 underflow_clr;
+	u32 hsync_skew;
+	u32 border_top;
+	u32 border_bottom;
+	u32 border_left;
+	u32 border_right;
+	/* Pad width */
+	u32 xres_pad;
+	/* Pad height */
+	u32 yres_pad;
+};
+struct mdss_panel_info {
+	u32 xres;
+	u32 yres;
+	u32 physical_width;
+	u32 physical_height;
+	u32 bpp;
+	u32 type;
+	u32 wait_cycle;
+	u32 pdest;
+	u32 brightness_max;
+	u32 bl_max;
+	u32 bl_min;
+	u32 fb_num;
+	u32 clk_rate;
+	u32 clk_min;
+	u32 clk_max;
+	u32 frame_count;
+	u32 is_3d_panel;
+	u32 out_format;
+	u32 rst_seq[MDSS_DSI_RST_SEQ_LEN];
+	u32 rst_seq_len;
+	u32 vic; /* video identification code */
+	int new_fps;
+	int panel_max_fps;
+	int panel_max_vtotal;
+	u32 mode_gpio_state;
+	u32 xstart_pix_align;
+	u32 width_pix_align;
+	u32 ystart_pix_align;
+	u32 height_pix_align;
+	u32 min_width;
+	u32 min_height;
+	u32 min_fps;
+	u32 max_fps;
+
+	u32 partial_update_enabled;
+	u32 dcs_cmd_by_left;
+	int panel_power_state;
+	int blank_state;
+
+	uint32_t panel_dead;
+	u32 panel_orientation;
+	bool dynamic_switch_pending;
+	bool is_lpm_mode;
+
+	struct lcd_panel_info lcdc;
+};
+
+struct mdss_panel_data {
+	struct mdss_panel_info panel_info;
+	void (*set_backlight) (struct mdss_panel_data *pdata, u32 bl_level);
+	unsigned char *mmss_cc_base;
+
+	/**
+	 * event_handler() - callback handler for MDP core events
+	 * @pdata:	Pointer refering to the panel struct associated to this
+	 *		event. Can be used to retrieve panel info.
+	 * @e:		Event being generated, see enum mdss_intf_events
+	 * @arg:	Optional argument to pass some info from some events.
+	 *
+	 * Used to register handler to be used to propagate different events
+	 * happening in MDP core driver. Panel driver can listen for any of
+	 * these events to perform appropriate actions for panel initialization
+	 * and teardown.
+	 */
+	int (*event_handler) (struct mdss_panel_data *pdata, int e, void *arg);
+
+	struct mdss_panel_data *next;
+};
+
+int mdss_register_panel(struct platform_device *pdev,
+	struct mdss_panel_data *pdata);
+
+/*
+ * mdss_panel_is_power_off: - checks if a panel is off
+ * @panel_power_state: enum identifying the power state to be checked
+ */
+static inline bool mdss_panel_is_power_off(int panel_power_state)
+{
+	return (panel_power_state == MDSS_PANEL_POWER_OFF);
+}
+
+/**
+ * mdss_panel_is_power_on_interactive: - checks if a panel is on and interactive
+ * @panel_power_state: enum identifying the power state to be checked
+ *
+ * This function returns true only is the panel is fully interactive and
+ * opertaing in normal mode.
+ */
+static inline bool mdss_panel_is_power_on_interactive(int panel_power_state)
+{
+	return (panel_power_state == MDSS_PANEL_POWER_ON);
+}
+
+/**
+ * mdss_panel_is_panel_power_on: - checks if a panel is on
+ * @panel_power_state: enum identifying the power state to be checked
+ *
+ * A panel is considered to be on as long as it can accept any commands
+ * or data. Sometimes it is posible to program the panel to be in a low
+ * power non-interactive state. This function returns false only if panel
+ * has explicitly been turned off.
+ */
+static inline bool mdss_panel_is_power_on(int panel_power_state)
+{
+	return !mdss_panel_is_power_off(panel_power_state);
+}
+
+/**
+ * mdss_panel_is_panel_power_on_lp: - checks if a panel is in a low power mode
+ * @pdata: pointer to the panel struct associated to the panel
+ * @panel_power_state: enum identifying the power state to be checked
+ *
+ * This function returns true if the panel is in an intermediate low power
+ * state where it is still on but not fully interactive. It may or may not
+ * accept any commands and display updates.
+ */
+static inline bool mdss_panel_is_power_on_lp(int panel_power_state)
+{
+	return !mdss_panel_is_power_off(panel_power_state) &&
+		!mdss_panel_is_power_on_interactive(panel_power_state);
+}
+
+/**
+ * mdss_panel_is_panel_power_on_ulp: - checks if panel is in ultra low power mode
+ * @pdata: pointer to the panel struct associated to the panel
+ * @panel_power_state: enum identifying the power state to be checked
+ *
+ * This function returns true if the panel is in a ultra low power
+ * state where it is still on but cannot recieve any display updates.
+ */
+static inline bool mdss_panel_is_power_on_ulp(int panel_power_state)
+{
+	return panel_power_state == MDSS_PANEL_POWER_LP2;
+}
+
+#endif /* MDSS_PANEL_H */
diff --git a/drivers/video/fbdev/qti/mdss_qpic.c b/drivers/video/fbdev/qti/mdss_qpic.c
new file mode 100644
index 0000000..f031831
--- /dev/null
+++ b/drivers/video/fbdev/qti/mdss_qpic.c
@@ -0,0 +1,742 @@
+/* Copyright (c) 2013-2014, 2020 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
+ * 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/module.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+
+#include "mdss_fb.h"
+#include "mdss_qpic.h"
+#include "mdss_qpic_panel.h"
+
+static int mdss_qpic_probe(struct platform_device *pdev);
+static int mdss_qpic_remove(struct platform_device *pdev);
+static void qpic_interrupt_en(u32 en);
+
+struct qpic_data_type *qpic_res;
+
+/* for debugging */
+static u32 use_bam = true;
+static u32 use_irq = true;
+static u32 use_vsync = true;
+
+static const struct of_device_id mdss_qpic_dt_match[] = {
+	{ .compatible = "qti,mdss_qpic",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, mdss_qpic_dt_match);
+
+static struct platform_driver mdss_qpic_driver = {
+	.probe = mdss_qpic_probe,
+	.remove = mdss_qpic_remove,
+	.shutdown = NULL,
+	.driver = {
+		/*
+		 * Simulate mdp hw
+		 */
+		.name = "mdp",
+		.of_match_table = mdss_qpic_dt_match,
+	},
+};
+
+int qpic_on(struct msm_fb_data_type *mfd)
+{
+	int ret;
+	ret = mdss_qpic_panel_on(qpic_res->panel_data, &qpic_res->panel_io);
+	return ret;
+}
+
+int qpic_off(struct msm_fb_data_type *mfd)
+{
+	int ret;
+	ret = mdss_qpic_panel_off(qpic_res->panel_data, &qpic_res->panel_io);
+	if (use_irq)
+		qpic_interrupt_en(false);
+	return ret;
+}
+
+
+static void mdss_qpic_pan_display(struct msm_fb_data_type *mfd)
+{
+
+	struct fb_info *fbi;
+	u32 offset, fb_offset, size, data;
+	int bpp;
+
+	if (!mfd) {
+		pr_err("%s: mfd is NULL!", __func__);
+		return;
+	}
+
+	fbi = mfd->fbi;
+
+	bpp = fbi->var.bits_per_pixel / 8;
+	offset = fbi->var.xoffset * bpp +
+		 fbi->var.yoffset * fbi->fix.line_length;
+
+	if (offset > fbi->fix.smem_len) {
+		pr_err("invalid fb offset=%u total length=%u\n",
+		       (unsigned int)offset, fbi->fix.smem_len);
+		return;
+	}
+	if (use_bam)
+		fb_offset = (u32)fbi->fix.smem_start + offset;
+	else
+		fb_offset = (u32)(uintptr_t)(mfd->fbi->screen_base + offset);
+
+	mdss_qpic_panel_on(qpic_res->panel_data, &qpic_res->panel_io);
+	size = fbi->var.xres * fbi->var.yres * bpp;
+
+	if (size < (1024 * 1024)) {
+		qpic_send_frame(0, 0, fbi->var.xres - 1, fbi->var.yres - 1,
+		(u32 *)((uintptr_t)fb_offset), size);
+	} else {
+		/* LCDC BAM can't trnasfer more than 1MB */
+		qpic_send_frame(0, 0, fbi->var.xres - 1, fbi->var.yres - 1,
+		(u32 *)((uintptr_t)fb_offset), size / 2);
+
+		/* Disable vsync interrupt for second packet */
+		if (use_vsync) {
+			data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL);
+			data &= ~(1 << 0);
+			QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data);
+		}
+
+		qpic_send_frame(0,  fbi->var.yres / 2, fbi->var.xres - 1,
+			 fbi->var.yres - 1, (u32 *)((uintptr_t)(fb_offset +
+(size / 2))), size / 2);
+
+		/* Enable vsync interrupt after sending second packet */
+		if (use_vsync) {
+			data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL);
+			data |= (1 << 0);
+			QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data);
+		}
+	}
+}
+
+static void qpic_bam_cb(void *param)
+{
+	complete(&qpic_res->completion);
+}
+
+void mdss_qpic_dma_pages_ops(dma_addr_t base, size_t size,
+			     void page_ops(struct page *page))
+{
+	dma_addr_t cur;
+	struct page *page;
+
+	for (cur = base; cur < base + size; cur += PAGE_SIZE) {
+		page = pfn_to_page(cur >> PAGE_SHIFT);
+		page_ops(page);
+	}
+}
+
+int mdss_qpic_alloc_fb_mem(struct msm_fb_data_type *mfd)
+{
+	size_t size;
+	u32 yres = mfd->fbi->var.yres_virtual;
+
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
+
+	if (!qpic_res->res_init)
+		return -EINVAL;
+
+	if (mfd->index != 0) {
+		mfd->fbi->fix.smem_start = 0;
+		mfd->fbi->screen_base = NULL;
+		mfd->fbi->fix.smem_len = 0;
+		return 0;
+	}
+
+	if (!qpic_res->cmd_buf_virt) {
+		qpic_res->cmd_buf_virt = dma_alloc_wc(
+			&qpic_res->pdev->dev, QPIC_MAX_CMD_BUF_SIZE,
+			(dma_addr_t *)&qpic_res->cmd_buf_phys, GFP_KERNEL);
+		if (!qpic_res->cmd_buf_virt) {
+			pr_err("%s cmd buf allocation failed", __func__);
+			return -ENOMEM;
+		}
+
+		pr_debug("%s cmd_buf virt=%p phys=%x", __func__,
+			qpic_res->cmd_buf_virt,
+			qpic_res->cmd_buf_phys);
+	}
+
+	if (!qpic_res->fb_virt) {
+		qpic_res->fb_virt = (void *)dmam_alloc_coherent(
+						&qpic_res->pdev->dev,
+						size,
+						(dma_addr_t *)&qpic_res->fb_phys,
+						GFP_KERNEL);
+		if (!qpic_res->fb_virt) {
+			pr_err("%s fb allocation failed", __func__);
+			dma_free_wc(&qpic_res->pdev->dev,
+					      QPIC_MAX_CMD_BUF_SIZE,
+					      qpic_res->cmd_buf_virt,
+					      qpic_res->cmd_buf_phys);
+			qpic_res->cmd_buf_virt = NULL;
+			return -ENOMEM;
+		}
+
+		pr_debug("%s size=%d vir_addr=%p phys_addr=0x%x",
+			__func__, (int)size, qpic_res->fb_virt,
+			qpic_res->fb_phys);
+
+		qpic_res->fb_size = size;
+		mdss_qpic_dma_pages_ops(qpic_res->fb_phys, size, get_page);
+	}
+
+	mfd->fbi->fix.smem_start = qpic_res->fb_phys;
+	mfd->fbi->screen_base = qpic_res->fb_virt;
+	mfd->fbi->fix.smem_len = size;
+
+	return 0;
+}
+
+u32 mdss_qpic_fb_stride(u32 fb_index, u32 xres, int bpp)
+{
+	return xres * bpp;
+}
+
+int mdss_qpic_overlay_init(struct msm_fb_data_type *mfd)
+{
+	struct msm_mdp_interface *qpic_interface = &mfd->mdp;
+	qpic_interface->on_fnc = qpic_on;
+	qpic_interface->off_fnc = qpic_off;
+	qpic_interface->cursor_update = NULL;
+	qpic_interface->dma_fnc = mdss_qpic_pan_display;
+	qpic_interface->ioctl_handler = NULL;
+	return 0;
+}
+
+int qpic_register_panel(struct mdss_panel_data *pdata)
+{
+	struct platform_device *mdss_fb_dev = NULL;
+	int rc;
+
+	mdss_fb_dev = platform_device_alloc("mdss_fb", pdata->panel_info.pdest);
+	if (!mdss_fb_dev) {
+		pr_err("unable to allocate mdss_fb device\n");
+		return -ENOMEM;
+	}
+
+	mdss_fb_dev->dev.platform_data = pdata;
+
+	rc = platform_device_add(mdss_fb_dev);
+	if (rc) {
+		platform_device_put(mdss_fb_dev);
+		pr_err("unable to probe mdss_fb device (%d)\n", rc);
+		return rc;
+	}
+
+	qpic_res->panel_data = pdata;
+
+	return rc;
+}
+
+void mdss_qpic_set_cfg0(void)
+{
+	/*
+	 * RD_CS_HOLD=1,RD_ACTIVE=8,CS_WR_RD_SETUP=0,
+	 * WR_CS_HOLD,WR_ACTIVE,ADDR_CS_SETUP=0,
+	 * CMD_BUS_ALIGNMENT=0.
+	 */
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG0, 0x2000101);
+}
+
+void mdss_qpic_reset(void)
+{
+	u32 time_end;
+
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_RESET, 1 << 0);
+	/* wait 100 us after reset as suggested by hw */
+	usleep_range(100, 100);
+	time_end = (u32)ktime_to_ms(ktime_get()) +
+		QPIC_MAX_VSYNC_WAIT_TIME;
+	while (((QPIC_INP(QPIC_REG_QPIC_LCDC_STTS) & (1 << 8)) == 0)) {
+		if ((u32)ktime_to_ms(ktime_get()) > time_end) {
+			pr_err("%s reset not finished", __func__);
+			break;
+		}
+		/* yield 100 us for next polling by experiment*/
+		usleep_range(100, 100);
+	}
+}
+
+static void qpic_interrupt_en(u32 en)
+{
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff);
+	if (en) {
+		if (!qpic_res->irq_ena) {
+			init_completion(&qpic_res->fifo_eof_comp);
+			qpic_res->irq_ena = true;
+			enable_irq(qpic_res->irq);
+		}
+	} else {
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, 0);
+		disable_irq(qpic_res->irq);
+		qpic_res->irq_ena = false;
+	}
+}
+
+static irqreturn_t qpic_irq_handler(int irq, void *ptr)
+{
+	u32 data;
+	data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS);
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff);
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, 0);
+
+	if (data & ((1 << 2) | (1 << 4)))
+		complete(&qpic_res->fifo_eof_comp);
+	return IRQ_HANDLED;
+}
+
+static int qpic_send_pkt_bam(u32 cmd, u32 len, u8 *param)
+{
+	int ret = 0;
+	struct dma_async_tx_descriptor *dma_desc;
+	dma_cookie_t cookie = 0;
+
+	u32 cfg2;
+	dma_addr_t phys_addr;
+
+	if ((cmd != OP_WRITE_MEMORY_START) &&
+		(cmd != OP_WRITE_MEMORY_CONTINUE)) {
+		memcpy((u8 *)qpic_res->cmd_buf_virt, param, len);
+		phys_addr = qpic_res->cmd_buf_phys;
+	} else {
+		phys_addr = (dma_addr_t)param;
+	}
+	cfg2 = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2);
+	cfg2 &= ~0xFF;
+	cfg2 |= cmd;
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2);
+
+	dma_desc = dmaengine_prep_slave_single(qpic_res->chan, phys_addr, len,
+				DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+	if (!dma_desc) {
+		pr_err("failed to prepare dma desc for command %x\n",
+				cmd);
+		return -EINVAL;
+	}
+
+	dma_desc->callback = qpic_bam_cb;
+	dma_desc->callback_param = qpic_res;
+
+	cookie = dmaengine_submit(dma_desc);
+	if (dma_submit_error(cookie)) {
+		pr_err("failed to submit command %x\n",
+			cmd);
+		ret = -EINVAL;
+	}
+
+	reinit_completion(&qpic_res->completion);
+	dma_async_issue_pending(qpic_res->chan);
+
+	ret = wait_for_completion_timeout(
+		&qpic_res->completion,
+		qpic_res->bam_timeout);
+
+	if (ret <= 0)
+		pr_err("%s timeout %x", __func__, ret);
+	else
+		ret = 0;
+
+	return ret;
+}
+
+void qpic_dump_reg(void)
+{
+	pr_info("%s\n", __func__);
+	pr_info("QPIC_REG_QPIC_LCDC_CTRL = %x\n",
+		QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL));
+	pr_info("QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT = %x\n",
+		QPIC_INP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT));
+	pr_info("QPIC_REG_QPIC_LCDC_CFG0 = %x\n",
+		QPIC_INP(QPIC_REG_QPIC_LCDC_CFG0));
+	pr_info("QPIC_REG_QPIC_LCDC_CFG1 = %x\n",
+		QPIC_INP(QPIC_REG_QPIC_LCDC_CFG1));
+	pr_info("QPIC_REG_QPIC_LCDC_CFG2 = %x\n",
+		QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2));
+	pr_info("QPIC_REG_QPIC_LCDC_IRQ_EN = %x\n",
+		QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_EN));
+	pr_info("QPIC_REG_QPIC_LCDC_IRQ_STTS = %x\n",
+		QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS));
+	pr_info("QPIC_REG_QPIC_LCDC_STTS = %x\n",
+		QPIC_INP(QPIC_REG_QPIC_LCDC_STTS));
+	pr_info("QPIC_REG_QPIC_LCDC_FIFO_SOF = %x\n",
+		QPIC_INP(QPIC_REG_QPIC_LCDC_FIFO_SOF));
+}
+
+static int qpic_wait_for_fifo(void)
+{
+	u32 data, time_end;
+	int ret = 0;
+
+	if (use_irq) {
+		data = QPIC_INP(QPIC_REG_QPIC_LCDC_STTS);
+		data &= 0x3F;
+		if (data == 0)
+			return ret;
+		reinit_completion(&qpic_res->fifo_eof_comp);
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, (1 << 4));
+		ret = wait_for_completion_timeout(&qpic_res->fifo_eof_comp,
+				msecs_to_jiffies(QPIC_MAX_VSYNC_WAIT_TIME));
+		if (ret > 0) {
+			ret = 0;
+		} else {
+			pr_err("%s timeout %x\n", __func__, ret);
+			ret = -ETIMEDOUT;
+		}
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, 0);
+	} else {
+		time_end = (u32)ktime_to_ms(ktime_get()) +
+			QPIC_MAX_VSYNC_WAIT_TIME;
+		while (1) {
+			data = QPIC_INP(QPIC_REG_QPIC_LCDC_STTS);
+			data &= 0x3F;
+			if (data == 0)
+				break;
+			/* yield 10 us for next polling by experiment*/
+			usleep_range(10, 10);
+			if (ktime_to_ms(ktime_get()) > time_end) {
+				pr_err("%s time out", __func__);
+				ret = -EBUSY;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+static int qpic_wait_for_eof(void)
+{
+	u32 data, time_end;
+	int ret = 0;
+	if (use_irq) {
+		data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS);
+		if (data & (1 << 2))
+			return ret;
+		reinit_completion(&qpic_res->fifo_eof_comp);
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, (1 << 2));
+		ret = wait_for_completion_timeout(&qpic_res->fifo_eof_comp,
+				msecs_to_jiffies(QPIC_MAX_VSYNC_WAIT_TIME));
+		if (ret > 0) {
+			ret = 0;
+		} else {
+			pr_err("%s timeout %x\n", __func__, ret);
+			ret = -ETIMEDOUT;
+		}
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, 0);
+	} else {
+		time_end = (u32)ktime_to_ms(ktime_get()) +
+			QPIC_MAX_VSYNC_WAIT_TIME;
+		while (1) {
+			data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS);
+			if (data & (1 << 2))
+				break;
+			/* yield 10 us for next polling by experiment*/
+			usleep_range(10, 10);
+			if (ktime_to_ms(ktime_get()) > time_end) {
+				pr_err("%s wait for eof time out\n", __func__);
+				qpic_dump_reg();
+				ret = -EBUSY;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+static int qpic_send_pkt_sw(u32 cmd, u32 len, u8 *param)
+{
+	u32 bytes_left, data, cfg2;
+	int i, ret = 0;
+	if (len <= 4) {
+		data = 0;
+		if (param) {
+			for (i = 0; i < len; i++)
+				data |= (u32)param[i] << (8 * i);
+		}
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, len);
+		QPIC_OUTP(QPIC_REG_LCD_DEVICE_CMD0 + (4 * cmd), data);
+		return 0;
+	}
+
+	if ((len & 0x1) != 0) {
+		pr_debug("%s: number of bytes needs be even", __func__);
+		len = (len + 1) & (~0x1);
+	}
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff);
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, 0);
+	cfg2 = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2);
+	if ((cmd != OP_WRITE_MEMORY_START) &&
+		(cmd != OP_WRITE_MEMORY_CONTINUE))
+		cfg2 |= (1 << 24); /* transparent mode */
+	else
+		cfg2 &= ~(1 << 24);
+
+	cfg2 &= ~0xFF;
+	cfg2 |= cmd;
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2);
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_SOF, 0x0);
+	bytes_left = len;
+
+	i = 0;
+	while (bytes_left > 0) {
+		ret = qpic_wait_for_fifo();
+		if (ret)
+			goto exit_send_cmd_sw;
+
+		data = (u32)param[i];
+
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_DATA_PORT0, data);
+		bytes_left--;
+		i++;
+	}
+	/* finished */
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_EOF, 0x0);
+	ret = qpic_wait_for_eof();
+exit_send_cmd_sw:
+	cfg2 &= ~(1 << 24);
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2);
+	return ret;
+}
+
+int qpic_send_pkt(u32 cmd, u8 *param, u32 len)
+{
+	if (!use_bam || ((cmd != OP_WRITE_MEMORY_CONTINUE) &&
+		(cmd != OP_WRITE_MEMORY_START)))
+		return qpic_send_pkt_sw(cmd, len, param);
+	else
+		return qpic_send_pkt_bam(cmd, len, param);
+}
+EXPORT_SYMBOL(qpic_send_pkt);
+
+int mdss_qpic_init(void)
+{
+	int ret = 0;
+	u32 data;
+	mdss_qpic_reset();
+
+	pr_info("%s version=%x", __func__, QPIC_INP(QPIC_REG_LCDC_VERSION));
+	data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL);
+	/* clear vsync wait , bam mode = 0*/
+	data &= ~(3 << 0);
+	data &= ~(0x1f << 3);
+	data |= (1 << 3); /* threshold */
+	data |= (1 << 8); /* lcd_en */
+	data &= ~(0x1f << 9);
+	data |= (1 << 9); /* threshold */
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data);
+
+	if (use_irq && (!qpic_res->irq_requested)) {
+		ret = devm_request_irq(&qpic_res->pdev->dev,
+			qpic_res->irq, qpic_irq_handler,
+			0,	"QPIC", qpic_res);
+		if (ret) {
+			pr_err("qpic request_irq() failed!\n");
+			use_irq = false;
+		} else {
+			disable_irq(qpic_res->irq);
+		}
+		qpic_res->irq_requested = true;
+	}
+
+	qpic_interrupt_en(use_irq);
+
+	data = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2);
+	data &= ~(0xFFF);
+	data |= 0x200; /* XRGB */
+	data |= 0x2C;
+	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, data);
+
+	if (use_bam) {
+		if (!qpic_res->chan) {
+			qpic_res->chan = dma_request_slave_channel(
+						&qpic_res->pdev->dev, "chan");
+			if (!qpic_res->chan) {
+				dev_err(&qpic_res->pdev->dev,
+						"failed to request channel\n");
+				return -ENODEV;
+			}
+		}
+
+		data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL);
+		data |= (1 << 1);
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data);
+	}
+
+	/* TE enable */
+	if (use_vsync) {
+		data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL);
+		data |= (1 << 0);
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data);
+	}
+
+	return ret;
+}
+
+u32 qpic_read_data(u32 cmd_index, u32 size)
+{
+	u32 data = 0;
+	if (size <= 4) {
+		QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, size);
+		data = QPIC_INP(QPIC_REG_LCD_DEVICE_CMD0 + (cmd_index * 4));
+	}
+	return data;
+}
+EXPORT_SYMBOL(qpic_read_data);
+
+static int mdss_qpic_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int rc = 0;
+	u32 bam_timeout;
+	static struct msm_mdp_interface qpic_interface = {
+		.init_fnc = mdss_qpic_overlay_init,
+		.fb_mem_alloc_fnc = mdss_qpic_alloc_fb_mem,
+		.fb_stride = mdss_qpic_fb_stride,
+	};
+
+
+	if (!pdev->dev.of_node) {
+		pr_err("qpic driver only supports device tree probe\n");
+		return -ENOTSUPP;
+	}
+
+	if (!qpic_res)
+		qpic_res = devm_kzalloc(&pdev->dev,
+			sizeof(*qpic_res), GFP_KERNEL);
+
+	if (!qpic_res)
+		return -ENOMEM;
+
+	if (qpic_res->res_init) {
+		pr_err("qpic already initialized\n");
+		return -EINVAL;
+	}
+
+	qpic_res->core_clk = devm_clk_get(dev, "core");
+	if (IS_ERR(qpic_res->core_clk))
+		return PTR_ERR(qpic_res->core_clk);
+
+	qpic_res->aon_clk = devm_clk_get(dev, "aon");
+	if (IS_ERR(qpic_res->aon_clk))
+		return PTR_ERR(qpic_res->aon_clk);
+
+	rc = clk_prepare_enable(qpic_res->core_clk);
+	if (rc)
+		return rc;
+
+	rc = clk_prepare_enable(qpic_res->aon_clk);
+	if (rc)
+		goto err_aon_clk;
+
+	pdev->id = 0;
+
+	qpic_res->pdev = pdev;
+	platform_set_drvdata(pdev, qpic_res);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		pr_err("unable to get QPIC reg base address\n");
+		rc = -ENOMEM;
+		goto clk_disable;
+	}
+
+	qpic_res->qpic_reg_size = resource_size(res);
+	qpic_res->qpic_base = devm_ioremap(&pdev->dev, res->start,
+					qpic_res->qpic_reg_size);
+	if (unlikely(!qpic_res->qpic_base)) {
+		pr_err("unable to map MDSS QPIC base\n");
+		rc = -ENOMEM;
+		goto clk_disable;
+	}
+	qpic_res->qpic_phys = res->start;
+	pr_info("MDSS QPIC HW Base phy_Address=0x%x virt=%p\n",
+		(int) res->start,
+		(void *)qpic_res->qpic_base);
+
+	qpic_res->irq = platform_get_irq(pdev, 0);
+	if (qpic_res->irq < 0) {
+		dev_warn(&pdev->dev, "missing 'lcdc_irq' resource entry");
+		rc = -EINVAL;
+		goto clk_disable;
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node,
+				 "qti,bam_timeout", &bam_timeout))
+		bam_timeout = QPIC_BAM_TIMEOUT;
+
+	qpic_res->bam_timeout = msecs_to_jiffies(bam_timeout);
+
+	qpic_res->res_init = true;
+	init_completion(&qpic_res->completion);
+
+	rc = mdss_fb_register_mdp_instance(&qpic_interface);
+	if (rc) {
+		pr_err("unable to register QPIC instance\n");
+		goto clk_disable;
+	}
+
+	return 0;
+
+clk_disable:
+	clk_disable_unprepare(qpic_res->aon_clk);
+err_aon_clk:
+	clk_disable_unprepare(qpic_res->core_clk);
+
+	return rc;
+}
+
+static int mdss_qpic_remove(struct platform_device *pdev)
+{
+	if (qpic_res->chan)
+		dma_release_channel(qpic_res->chan);
+
+	if (qpic_res->fb_virt)
+		mdss_qpic_dma_pages_ops(qpic_res->fb_phys,
+					qpic_res->fb_size, put_page);
+
+	if (!qpic_res->cmd_buf_virt)
+		dma_free_wc(&qpic_res->pdev->dev,
+				      QPIC_MAX_CMD_BUF_SIZE,
+				      qpic_res->cmd_buf_virt,
+				      qpic_res->cmd_buf_phys);
+
+	clk_disable_unprepare(qpic_res->aon_clk);
+	clk_disable_unprepare(qpic_res->core_clk);
+
+	return 0;
+}
+
+static int __init mdss_qpic_driver_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&mdss_qpic_driver);
+	if (ret)
+		pr_err("mdss_qpic_register_driver() failed!\n");
+	return ret;
+}
+
+module_init(mdss_qpic_driver_init);
+
+
diff --git a/drivers/video/fbdev/qti/mdss_qpic.h b/drivers/video/fbdev/qti/mdss_qpic.h
new file mode 100644
index 0000000..36ca681
--- /dev/null
+++ b/drivers/video/fbdev/qti/mdss_qpic.h
@@ -0,0 +1,98 @@
+/* Copyright (c) 2014, 2020 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
+ * 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_QPIC_H
+#define MDSS_QPIC_H
+
+#include <linux/list.h>
+
+#include <linux/pinctrl/consumer.h>
+#include "mdss_panel.h"
+#include "mdss_qpic_panel.h"
+
+#define QPIC_REG_QPIC_LCDC_CTRL				0x22000
+#define QPIC_REG_LCDC_VERSION				0x22004
+#define QPIC_REG_QPIC_LCDC_IRQ_EN			0x22008
+#define QPIC_REG_QPIC_LCDC_IRQ_STTS			0x2200C
+#define QPIC_REG_QPIC_LCDC_IRQ_CLR			0x22010
+#define QPIC_REG_QPIC_LCDC_STTS				0x22014
+#define QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT	0x22018
+#define QPIC_REG_QPIC_LCDC_CFG0				0x22020
+#define QPIC_REG_QPIC_LCDC_CFG1				0x22024
+#define QPIC_REG_QPIC_LCDC_CFG2				0x22028
+#define QPIC_REG_QPIC_LCDC_RESET			0x2202C
+#define QPIC_REG_QPIC_LCDC_FIFO_SOF			0x22100
+#define QPIC_REG_LCD_DEVICE_CMD0			0x23000
+#define QPIC_REG_QPIC_LCDC_FIFO_DATA_PORT0	0x22140
+#define QPIC_REG_QPIC_LCDC_FIFO_EOF			0x22180
+
+#define QPIC_OUTP(off, data) \
+	writel_relaxed((data), qpic_res->qpic_base + (off))
+#define QPIC_OUTPW(off, data) \
+	writew_relaxed((data), qpic_res->qpic_base + (off))
+#define QPIC_INP(off) \
+	readl_relaxed(qpic_res->qpic_base + (off))
+
+#define QPIC_MAX_VSYNC_WAIT_TIME			500
+#define QPIC_MAX_CMD_BUF_SIZE				512
+
+#define QPIC_BAM_TIMEOUT				400
+
+int mdss_qpic_init(void);
+void mdss_qpic_set_cfg0(void);
+int qpic_send_pkt(u32 cmd, u8 *param, u32 len);
+u32 qpic_read_data(u32 cmd_index, u32 size);
+int mdss_qpic_panel_on(struct mdss_panel_data *pdata,
+	struct qpic_panel_io_desc *panel_io);
+int mdss_qpic_panel_off(struct mdss_panel_data *pdata,
+	struct qpic_panel_io_desc *panel_io);
+int qpic_register_panel(struct mdss_panel_data *pdata);
+
+struct qpic_data_type {
+	u32 rev;
+	struct platform_device *pdev;
+	size_t qpic_reg_size;
+	u32 qpic_phys;
+	char __iomem *qpic_base;
+	int irq;
+	int bam_irq;
+	u32 irq_ena;
+	u32 res_init;
+	void *fb_virt;
+	u32 fb_phys;
+	size_t fb_size;
+	void *cmd_buf_virt;
+	u32 cmd_buf_phys;
+	u32 irq_requested;
+	struct mdss_panel_data *panel_data;
+	struct qpic_panel_io_desc panel_io;
+	u32 bus_handle;
+	unsigned long bam_timeout;
+	struct completion fifo_eof_comp;
+	struct completion completion;
+	struct dma_chan *chan;
+	struct clk *core_clk;
+	struct clk *aon_clk;
+};
+
+u32 qpic_send_frame(
+		u32 x_start,
+		u32 y_start,
+		u32 x_end,
+		u32 y_end,
+		u32 *data,
+		u32 total_bytes);
+
+u32 qpic_panel_get_framerate(void);
+
+#endif /* MDSS_QPIC_H */
diff --git a/drivers/video/fbdev/qti/mdss_qpic_panel.c b/drivers/video/fbdev/qti/mdss_qpic_panel.c
new file mode 100644
index 0000000..dd9d9ba
--- /dev/null
+++ b/drivers/video/fbdev/qti/mdss_qpic_panel.c
@@ -0,0 +1,199 @@
+/* Copyright (c) 2014, 2020 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
+ * 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/module.h>
+#include <linux/of.h>
+
+#include "mdss_panel.h"
+#include "mdss_qpic.h"
+#include "mdss_qpic_panel.h"
+
+static u32 panel_is_on;
+static u32 panel_refresh_rate;
+
+int (*qpic_panel_on)(struct qpic_panel_io_desc *qpic_panel_io);
+EXPORT_SYMBOL(qpic_panel_on);
+void (*qpic_panel_off)(struct qpic_panel_io_desc *qpic_panel_io);
+EXPORT_SYMBOL(qpic_panel_off);
+
+u32 qpic_panel_get_framerate(void)
+{
+	return panel_refresh_rate;
+}
+
+/* write a frame of pixels to a MIPI screen */
+u32 qpic_send_frame(u32 x_start,
+				u32 y_start,
+				u32 x_end,
+				u32 y_end,
+				u32 *data,
+				u32 total_bytes)
+{
+	u8 param[4];
+	u32 status;
+	u32 start_0_7;
+	u32 end_0_7;
+	u32 start_8_15;
+	u32 end_8_15;
+
+	/* convert to 16 bit representation */
+	x_start = x_start & 0xffff;
+	y_start = y_start & 0xffff;
+	x_end = x_end & 0xffff;
+	y_end = y_end & 0xffff;
+
+	/* set column/page */
+	start_0_7 = x_start & 0xff;
+	end_0_7 = x_end & 0xff;
+	start_8_15 = (x_start >> 8) & 0xff;
+	end_8_15 = (x_end >> 8) & 0xff;
+	param[0] = start_8_15;
+	param[1] = start_0_7;
+	param[2] = end_8_15;
+	param[3] = end_0_7;
+	status = qpic_send_pkt(OP_SET_COLUMN_ADDRESS, param, 4);
+	if (status) {
+		pr_err("Failed to set column address");
+		return status;
+	}
+
+	start_0_7 = y_start & 0xff;
+	end_0_7 = y_end & 0xff;
+	start_8_15 = (y_start >> 8) & 0xff;
+	end_8_15 = (y_end >> 8) & 0xff;
+	param[0] = start_8_15;
+	param[1] = start_0_7;
+	param[2] = end_8_15;
+	param[3] = end_0_7;
+	status = qpic_send_pkt(OP_SET_PAGE_ADDRESS, param, 4);
+	if (status) {
+		pr_err("Failed to set page address");
+		return status;
+	}
+
+	status = qpic_send_pkt(OP_WRITE_MEMORY_START, (u8 *)data, total_bytes);
+	if (status) {
+		pr_err("Failed to start memory write");
+		return status;
+	}
+	return 0;
+}
+
+int mdss_qpic_panel_on(struct mdss_panel_data *pdata,
+	struct qpic_panel_io_desc *panel_io)
+{
+	int rc = 0;
+
+	if (panel_is_on)
+		return 0;
+	mdss_qpic_init();
+
+	if (!panel_io->init) {
+		panel_io->init = true;
+	}
+
+	if (qpic_panel_on)
+		rc = qpic_panel_on(panel_io);
+	if (rc)
+		return rc;
+	panel_is_on = true;
+	mdss_qpic_set_cfg0();
+	return 0;
+}
+
+int mdss_qpic_panel_off(struct mdss_panel_data *pdata,
+	struct qpic_panel_io_desc *panel_io)
+{
+	if (qpic_panel_off)
+		qpic_panel_off(panel_io);
+
+	panel_is_on = false;
+	return 0;
+}
+
+static int mdss_panel_parse_dt(struct platform_device *pdev,
+			       struct mdss_panel_data *panel_data)
+{
+	struct device_node *np = pdev->dev.of_node;
+	u32 res[6], tmp;
+	int rc;
+
+	rc = of_property_read_u32_array(np, "qti,mdss-pan-res", res, 2);
+	if (rc) {
+		pr_err("%s:%d, panel resolution not specified\n",
+						__func__, __LINE__);
+		return -EINVAL;
+	}
+	panel_data->panel_info.xres = (!rc ? res[0] : 240);
+	panel_data->panel_info.yres = (!rc ? res[1] : 320);
+	rc = of_property_read_u32(np, "qti,mdss-pan-bpp", &tmp);
+	if (rc) {
+		pr_err("%s:%d, panel bpp not specified\n",
+						__func__, __LINE__);
+		return -EINVAL;
+	}
+	panel_data->panel_info.bpp = (!rc ? tmp : 24);
+	of_property_read_u32(np, "qti,refresh_rate", &panel_refresh_rate);
+
+	panel_data->panel_info.type = EBI2_PANEL;
+	panel_data->panel_info.pdest = DISPLAY_1;
+
+	return rc;
+}
+
+static int mdss_qpic_panel_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	static struct mdss_panel_data vendor_pdata;
+	static const char *panel_name;
+
+	pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	panel_name = of_get_property(pdev->dev.of_node, "label", NULL);
+	if (!panel_name)
+		pr_info("%s:%d, panel name not specified\n",
+						__func__, __LINE__);
+	else
+		pr_info("%s: Panel Name = %s\n", __func__, panel_name);
+
+	rc = mdss_panel_parse_dt(pdev, &vendor_pdata);
+	if (rc)
+		return rc;
+
+	rc = qpic_register_panel(&vendor_pdata);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static const struct of_device_id mdss_qpic_panel_match[] = {
+	{.compatible = "qti,mdss-qpic-panel"},
+	{}
+};
+
+static struct platform_driver this_driver = {
+	.probe  = mdss_qpic_panel_probe,
+	.driver = {
+		.name = "qpic_panel",
+		.of_match_table = mdss_qpic_panel_match,
+	},
+};
+
+static int __init mdss_qpic_panel_init(void)
+{
+	return platform_driver_register(&this_driver);
+}
+MODULE_DEVICE_TABLE(of, mdss_qpic_panel_match);
+module_init(mdss_qpic_panel_init);
diff --git a/drivers/video/fbdev/qti/mdss_qpic_panel.h b/drivers/video/fbdev/qti/mdss_qpic_panel.h
new file mode 100644
index 0000000..f5a49ec
--- /dev/null
+++ b/drivers/video/fbdev/qti/mdss_qpic_panel.h
@@ -0,0 +1,137 @@
+/* Copyright (c) 2014, 2020 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
+ * 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_QPIC_PANEL_H
+#define MDSS_QPIC_PANEL_H
+
+#include <linux/list.h>
+
+#include "mdss_panel.h"
+
+#define LCDC_INTERNAL_BUFFER_SIZE   30
+
+/**
+   Macros for coding MIPI commands
+*/
+#define INV_SIZE             0xFFFF
+/* Size of argument to MIPI command is variable */
+#define OP_SIZE_PAIR(op, size)    ((op<<16) | size)
+/* MIPI {command, argument size} tuple */
+#define LCDC_EXTRACT_OP_SIZE(op_identifier)    ((op_identifier&0xFFFF))
+/* extract size from command identifier */
+#define LCDC_EXTRACT_OP_CMD(op_identifier)    (((op_identifier>>16)&0xFFFF))
+/* extract command id from command identifier */
+
+
+/* MIPI standard efinitions */
+#define LCDC_ADDRESS_MODE_ORDER_BOTTOM_TO_TOP                0x80
+#define LCDC_ADDRESS_MODE_ORDER_RIGHT_TO_LEFT                0x40
+#define LCDC_ADDRESS_MODE_ORDER_REVERSE                      0x20
+#define LCDC_ADDRESS_MODE_ORDER_REFRESH_BOTTOM_TO_TOP        0x10
+#define LCDC_ADDRESS_MODE_ORDER_BGER_RGB                     0x08
+#define LCDC_ADDRESS_MODE_ORDER_REFERESH_RIGHT_TO_LEFT       0x04
+#define LCDC_ADDRESS_MODE_FLIP_HORIZONTAL                    0x02
+#define LCDC_ADDRESS_MODE_FLIP_VERTICAL                      0x01
+
+#define LCDC_PIXEL_FORMAT_3_BITS_PER_PIXEL    0x1
+#define LCDC_PIXEL_FORMAT_8_BITS_PER_PIXEL    0x2
+#define LCDC_PIXEL_FORMAT_12_BITS_PER_PIXEL   0x3
+#define LCDC_PIXEL_FORMAT_16_BITS_PER_PIXEL   0x5
+#define LCDC_PIXEL_FORMAT_18_BITS_PER_PIXEL   0x6
+#define LCDC_PIXEL_FORMAT_24_BITS_PER_PIXEL   0x7
+
+#define LCDC_CREATE_PIXEL_FORMAT(dpi_format, dbi_format) \
+	(dpi_format | (dpi_format<<4))
+
+#define POWER_MODE_IDLE_ON       0x40
+#define POWER_MODE_PARTIAL_ON    0x20
+#define POWER_MODE_SLEEP_ON      0x10
+#define POWER_MODE_NORMAL_ON     0x08
+#define POWER_MODE_DISPLAY_ON    0x04
+
+#define LCDC_DISPLAY_MODE_SCROLLING_ON       0x80
+#define LCDC_DISPLAY_MODE_INVERSION_ON       0x20
+#define LCDC_DISPLAY_MODE_GAMMA_MASK         0x07
+
+/**
+ * LDCc MIPI Type B supported commands
+ */
+#define	OP_ENTER_IDLE_MODE      0x39
+#define	OP_ENTER_INVERT_MODE    0x21
+#define	OP_ENTER_NORMAL_MODE    0x13
+#define	OP_ENTER_PARTIAL_MODE   0x12
+#define	OP_ENTER_SLEEP_MODE     0x10
+#define	OP_EXIT_INVERT_MODE     0x20
+#define	OP_EXIT_SLEEP_MODE      0x11
+#define	OP_EXIT_IDLE_MODE       0x38
+#define	OP_GET_ADDRESS_MODE     0x0B /* size 1 */
+#define	OP_GET_BLUE_CHANNEL     0x08 /* size 1 */
+#define	OP_GET_DIAGNOSTIC       0x0F /* size 2 */
+#define	OP_GET_DISPLAY_MODE     0x0D /* size 1 */
+#define	OP_GET_GREEN_CHANNEL    0x07 /* size 1 */
+#define	OP_GET_PIXEL_FORMAT     0x0C /* size 1 */
+#define	OP_GET_POWER_MODE       0x0A /* size 1 */
+#define	OP_GET_RED_CHANNEL      0x06 /* size 1 */
+#define	OP_GET_SCANLINE         0x45 /* size 1 */
+#define	OP_GET_SIGNAL_MODE      0x0E /* size 1 */
+#define	OP_NOP                  0x00
+#define	OP_READ_DDB_CONTINUE    0xA8 /* size not fixed */
+#define	OP_READ_DDB_START       0xA1 /* size not fixed */
+#define	OP_READ_MEMORY_CONTINUE 0x3E /* size not fixed */
+#define	OP_READ_MEMORY_START    0x2E /* size not fixed */
+#define	OP_SET_ADDRESS_MODE     0x36 /* size 1 */
+#define	OP_SET_COLUMN_ADDRESS   0x2A /* size 4 */
+#define	OP_SET_DISPLAY_OFF      0x28
+#define	OP_SET_DISPLAY_ON       0x29
+#define	OP_SET_GAMMA_CURVE      0x26 /* size 1 */
+#define	OP_SET_PAGE_ADDRESS     0x2B /* size 4 */
+#define	OP_SET_PARTIAL_COLUMNS  0x31 /* size 4 */
+#define	OP_SET_PARTIAL_ROWS     0x30 /* size 4 */
+#define	OP_SET_PIXEL_FORMAT     0x3A /* size 1 */
+#define	OP_SOFT_RESET           0x01
+#define	OP_WRITE_MEMORY_CONTINUE  0x3C /* size not fixed */
+#define	OP_WRITE_MEMORY_START   0x2C /* size not fixed */
+
+/**
+ * ILI9341 commands
+ */
+#define OP_ILI9341_INTERFACE_CONTROL	0xf6
+#define OP_ILI9341_TEARING_EFFECT_LINE_ON	0x35
+
+struct qpic_pinctrl_res {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *gpio_state_active;
+	struct pinctrl_state *gpio_state_suspend;
+};
+
+struct qpic_panel_io_desc {
+	int rst_gpio;
+	int cs_gpio;
+	int ad8_gpio;
+	int te_gpio;
+	int bl_gpio;
+	struct regulator *vdd_vreg;
+	struct regulator *avdd_vreg;
+	u32 init;
+	struct qpic_pinctrl_res pin_res;
+};
+
+int mdss_qpic_panel_io_init(struct platform_device *pdev,
+	struct qpic_panel_io_desc *qpic_panel_io);
+u32 qpic_panel_get_cmd(u32 command, u32 size);
+int ili9341_on(struct qpic_panel_io_desc *qpic_panel_io);
+void ili9341_off(struct qpic_panel_io_desc *qpic_panel_io);
+extern int (*qpic_panel_on)(struct qpic_panel_io_desc *qpic_panel_io);
+extern void (*qpic_panel_off)(struct qpic_panel_io_desc *qpic_panel_io);
+
+#endif /* MDSS_QPIC_PANEL_H */
diff --git a/drivers/video/fbdev/qti/qpic_panel_er_ssd1963.c b/drivers/video/fbdev/qti/qpic_panel_er_ssd1963.c
new file mode 100644
index 0000000..b760f7c
--- /dev/null
+++ b/drivers/video/fbdev/qti/qpic_panel_er_ssd1963.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include "mdss_qpic.h"
+#include "mdss_qpic_panel.h"
+#include "qpic_panel_er_ssd1963.h"
+
+void ertft_off(struct qpic_panel_io_desc *qpic_panel_io)
+{
+	/* TODO : add shutdown related code if needed */
+}
+
+int ertft_on(struct qpic_panel_io_desc *qpic_panel_io)
+{
+	u8 param[8];
+
+	/* Set PLL MN */
+	param[0] = 0x23;
+	param[1] = 0x02;
+	param[2] = 0x54;
+	qpic_send_pkt(OP_SSD1963_SET_PLL_MN, param, 3);
+
+	/* Use PLL output as system clock */
+	param[0] = 0x1;
+	qpic_send_pkt(OP_SSD1963_SET_PLL, param, 1);
+	msleep(120);
+
+	/* Enable PLL */
+	param[0] = 0x03;
+	qpic_send_pkt(OP_SSD1963_SET_PLL, param, 1);
+	msleep(120);
+
+	/* Software Reset */
+	qpic_send_pkt(OP_SOFT_RESET, NULL, 0);
+	/* wait for 120 ms after reset as panel spec suggests */
+	msleep(120);
+
+	/* Set the LSHIFT (pixel clock) frequency */
+	param[0] = 0x04;
+	param[1] = 0x66;
+	param[2] = 0x65;
+	qpic_send_pkt(OP_SSD1963_SET_LSHIFT_FREQ, param, 3);
+	msleep(20);
+
+	/* Set the LCD panel mode and resolution */
+	param[0] = 0x20;
+	param[1] = 0x00;
+	param[2] = 0x03;
+	param[3] = 0x1f;
+	param[4] = 0x01;
+	param[5] = 0xdf;
+	param[6] = 0x00;
+	qpic_send_pkt(OP_SSD1963_SET_LCD_MODE, param, 7);
+	msleep(20);
+
+	/* Set front porch */
+	param[0] = 0x04;
+	param[1] = 0x1f;
+	param[2] = 0x00;
+	param[3] = 0xd2;
+	param[4] = 0x00;
+	param[5] = 0x00;
+	param[6] = 0x00;
+	param[7] = 0x00;
+	qpic_send_pkt(OP_SSD1963_SET_HOR_PERIOD, param, 8);
+
+	/* Set the vertical blanking interval between last scan line and
+	 * next LFRAME pulse
+	 */
+	param[0] = 0x02;
+	param[1] = 0x0c;
+	param[2] = 0x00;
+	param[3] = 0x22;
+	param[4] = 0x00;
+	param[5] = 0x00;
+	param[6] = 0x00;
+	qpic_send_pkt(OP_SSD1963_SET_VER_PERIOD, param, 7);
+	msleep(20);
+
+	/* Set GPIO config */
+	param[0] = 0x0f;
+	param[1] = 0x01;
+	qpic_send_pkt(OP_SSD1963_SET_GPIO_CONFIG, param, 2);
+	msleep(20);
+
+	/* Set GPIO Value */
+	param[0] = 0x1;
+	qpic_send_pkt(OP_SSD1963_SET_GPIO_VAL, param, 1);
+
+	/* set memory access control */
+	param[0] = 0x08;
+	qpic_send_pkt(OP_SET_ADDRESS_MODE, param, 1);
+	/* wait for 20 ms after command sent as panel spec suggests */
+	msleep(20);
+
+	param[0] = 0x60;
+	qpic_send_pkt(OP_SET_PIXEL_FORMAT, param, 1);
+
+	/* Set the pixel data format of the parallel host processor
+	 * interface
+	 */
+	param[0] = 0x06;
+	qpic_send_pkt(OP_SSD1963_SET_PIXEL_DATA_IFACE, param, 1);
+	/* wait for 20 ms after command sent as panel spec suggests */
+	msleep(20);
+
+	/* set post proc */
+	param[0] = 0x40;
+	param[1] = 0x80;
+	param[2] = 0x40;
+	param[3] = 0x01;
+	qpic_send_pkt(OP_SSD1963_SET_POST_PROC, param, 4);
+	/* wait for 20 ms after command sent */
+	msleep(20);
+
+	/* display on */
+	qpic_send_pkt(OP_SET_DISPLAY_ON, NULL, 0);
+	/* wait for 20 ms after command sent as panel spec suggests */
+	msleep(20);
+
+	param[0] = 0x06;
+	param[1] = 0x80;
+	param[2] = 0x01;
+	param[3] = 0xf0;
+	param[4] = 0x00;
+	param[5] = 0x00;
+	qpic_send_pkt(OP_SSD1963_SET_PWM_CONFIG, param, 6);
+	/* wait for 20 ms after command sent as panel spec suggests */
+	msleep(20);
+
+	param[0] = 0x0d;
+	qpic_send_pkt(OP_SSD1963_SET_DBC_CONFIG, param, 1);
+	/* wait for 20 ms after command sent as panel spec suggests */
+	msleep(20);
+
+	param[0] = 0x00;
+	qpic_send_pkt(OP_SSD1963_TEARING_EFFECT_LINE_ON, param, 1);
+
+	param[0] = qpic_read_data(OP_GET_PIXEL_FORMAT, 1);
+	pr_info("Pixel format =%x", param[0]);
+
+	return 0;
+}
+
+static int __init mdss_qpic_ertft_panel_init(void)
+{
+	qpic_panel_on = ertft_on;
+	qpic_panel_off = ertft_off;
+	return 0;
+}
+
+static void __exit mdss_qpic_ertft_panel_exit(void)
+{
+	qpic_panel_on = NULL;
+	qpic_panel_off = NULL;
+}
+module_init(mdss_qpic_ertft_panel_init);
+module_exit(mdss_qpic_ertft_panel_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/video/fbdev/qti/qpic_panel_er_ssd1963.h b/drivers/video/fbdev/qti/qpic_panel_er_ssd1963.h
new file mode 100644
index 0000000..e741737
--- /dev/null
+++ b/drivers/video/fbdev/qti/qpic_panel_er_ssd1963.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MDSS_QPIC_ERTFT_PANEL_H
+#define MDSS_QPIC_ERTFT_PANEL_H
+
+/**
+ * SSD1963 commands. ER panel */
+#define OP_SSD1963_TEARING_EFFECT_LINE_ON	0x35
+#define OP_SSD1963_SET_LCD_MODE			0xB0
+#define OP_SSD1963_SET_HOR_PERIOD		0xB4
+#define OP_SSD1963_SET_VER_PERIOD		0xB6
+#define OP_SSD1963_SET_GPIO_CONFIG		0xB8
+#define OP_SSD1963_SET_GPIO_VAL			0xBA
+#define OP_SSD1963_SET_POST_PROC		0xBC
+#define OP_SSD1963_SET_PWM_CONFIG		0xBE
+#define OP_SSD1963_SET_PLL			0xE0
+#define OP_SSD1963_SET_PLL_MN			0xE2
+#define OP_SSD1963_SET_LSHIFT_FREQ		0xE6
+#define OP_SSD1963_SET_PIXEL_DATA_IFACE		0xF0
+#define OP_SSD1963_SET_DBC_CONFIG		0xD0
+
+#endif
diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c
index 51c9d95..ca593a3 100644
--- a/drivers/video/fbdev/riva/fbdev.c
+++ b/drivers/video/fbdev/riva/fbdev.c
@@ -1088,9 +1088,6 @@ 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/sm712fb.c b/drivers/video/fbdev/sm712fb.c
index 83d0560..2466814 100644
--- a/drivers/video/fbdev/sm712fb.c
+++ b/drivers/video/fbdev/sm712fb.c
@@ -1047,7 +1047,7 @@ static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
 	if (count + p > total_size)
 		count = total_size - p;
 
-	buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
 	if (!buffer)
 		return -ENOMEM;
 
@@ -1059,14 +1059,25 @@ static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
 	while (count) {
 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
 		dst = buffer;
-		for (i = (c + 3) >> 2; i--;) {
-			u32 val;
-
-			val = fb_readl(src);
-			*dst = big_swap(val);
-			src++;
+		for (i = c >> 2; i--;) {
+			*dst = fb_readl(src++);
+			*dst = big_swap(*dst);
 			dst++;
 		}
+		if (c & 3) {
+			u8 *dst8 = (u8 *)dst;
+			u8 __iomem *src8 = (u8 __iomem *)src;
+
+			for (i = c & 3; i--;) {
+				if (i & 1) {
+					*dst8++ = fb_readb(++src8);
+				} else {
+					*dst8++ = fb_readb(--src8);
+					src8 += 2;
+				}
+			}
+			src = (u32 __iomem *)src8;
+		}
 
 		if (copy_to_user(buf, buffer, c)) {
 			err = -EFAULT;
@@ -1119,7 +1130,7 @@ static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
 		count = total_size - p;
 	}
 
-	buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
 	if (!buffer)
 		return -ENOMEM;
 
@@ -1137,11 +1148,24 @@ static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
 			break;
 		}
 
-		for (i = (c + 3) >> 2; i--;) {
-			fb_writel(big_swap(*src), dst);
-			dst++;
+		for (i = c >> 2; i--;) {
+			fb_writel(big_swap(*src), dst++);
 			src++;
 		}
+		if (c & 3) {
+			u8 *src8 = (u8 *)src;
+			u8 __iomem *dst8 = (u8 __iomem *)dst;
+
+			for (i = c & 3; i--;) {
+				if (i & 1) {
+					fb_writeb(*src8++, ++dst8);
+				} else {
+					fb_writeb(*src8++, --dst8);
+					dst8 += 2;
+				}
+			}
+			dst = (u32 __iomem *)dst8;
+		}
 
 		*ppos += c;
 		buf += c;
diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c
index ad60f73..0e0f5bb 100644
--- a/drivers/video/fbdev/smscufx.c
+++ b/drivers/video/fbdev/smscufx.c
@@ -1657,7 +1657,6 @@ static int ufx_usb_probe(struct usb_interface *interface,
 	info->par = dev;
 	info->pseudo_palette = dev->pseudo_palette;
 	info->fbops = &ufx_ops;
-	INIT_LIST_HEAD(&info->modelist);
 
 	retval = fb_alloc_cmap(&info->cmap, 256, 0);
 	if (retval < 0) {
@@ -1668,6 +1667,8 @@ static int ufx_usb_probe(struct usb_interface *interface,
 	INIT_DELAYED_WORK(&dev->free_framebuffer_work,
 			  ufx_free_framebuffer_work);
 
+	INIT_LIST_HEAD(&info->modelist);
+
 	retval = ufx_reg_read(dev, 0x3000, &id_rev);
 	check_warn_goto_error(retval, "error %d reading 0x3000 register from device", retval);
 	dev_dbg(dev->gdev, "ID_REV register value 0x%08x", id_rev);
diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c
index 8e8af40..fe373b6 100644
--- a/drivers/video/fbdev/udlfb.c
+++ b/drivers/video/fbdev/udlfb.c
@@ -1017,7 +1017,6 @@ static void dlfb_ops_destroy(struct fb_info *info)
 	}
 	vfree(dlfb->backing_buffer);
 	kfree(dlfb->edid);
-	dlfb_free_urb_list(dlfb);
 	usb_put_dev(dlfb->udev);
 	kfree(dlfb);
 
@@ -1427,7 +1426,7 @@ static ssize_t metrics_bytes_rendered_show(struct device *fbdev,
 				   struct device_attribute *a, char *buf) {
 	struct fb_info *fb_info = dev_get_drvdata(fbdev);
 	struct dlfb_data *dlfb = fb_info->par;
-	return sysfs_emit(buf, "%u\n",
+	return snprintf(buf, PAGE_SIZE, "%u\n",
 			atomic_read(&dlfb->bytes_rendered));
 }
 
@@ -1435,7 +1434,7 @@ static ssize_t metrics_bytes_identical_show(struct device *fbdev,
 				   struct device_attribute *a, char *buf) {
 	struct fb_info *fb_info = dev_get_drvdata(fbdev);
 	struct dlfb_data *dlfb = fb_info->par;
-	return sysfs_emit(buf, "%u\n",
+	return snprintf(buf, PAGE_SIZE, "%u\n",
 			atomic_read(&dlfb->bytes_identical));
 }
 
@@ -1443,7 +1442,7 @@ static ssize_t metrics_bytes_sent_show(struct device *fbdev,
 				   struct device_attribute *a, char *buf) {
 	struct fb_info *fb_info = dev_get_drvdata(fbdev);
 	struct dlfb_data *dlfb = fb_info->par;
-	return sysfs_emit(buf, "%u\n",
+	return snprintf(buf, PAGE_SIZE, "%u\n",
 			atomic_read(&dlfb->bytes_sent));
 }
 
@@ -1451,7 +1450,7 @@ static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev,
 				   struct device_attribute *a, char *buf) {
 	struct fb_info *fb_info = dev_get_drvdata(fbdev);
 	struct dlfb_data *dlfb = fb_info->par;
-	return sysfs_emit(buf, "%u\n",
+	return snprintf(buf, PAGE_SIZE, "%u\n",
 			atomic_read(&dlfb->cpu_kcycles_used));
 }
 
@@ -1650,9 +1649,8 @@ static int dlfb_usb_probe(struct usb_interface *intf,
 	const struct device_attribute *attr;
 	struct dlfb_data *dlfb;
 	struct fb_info *info;
-	int retval;
+	int retval = -ENOMEM;
 	struct usb_device *usbdev = interface_to_usbdev(intf);
-	struct usb_endpoint_descriptor *out;
 
 	/* usb initialization */
 	dlfb = kzalloc(sizeof(*dlfb), GFP_KERNEL);
@@ -1666,12 +1664,6 @@ static int dlfb_usb_probe(struct usb_interface *intf,
 	dlfb->udev = usb_get_dev(usbdev);
 	usb_set_intfdata(intf, dlfb);
 
-	retval = usb_find_common_endpoints(intf->cur_altsetting, NULL, &out, NULL, NULL);
-	if (retval) {
-		dev_err(&intf->dev, "Device should have at lease 1 bulk endpoint!\n");
-		goto error;
-	}
-
 	dev_dbg(&intf->dev, "console enable=%d\n", console);
 	dev_dbg(&intf->dev, "fb_defio enable=%d\n", fb_defio);
 	dev_dbg(&intf->dev, "shadow enable=%d\n", shadow);
@@ -1681,7 +1673,6 @@ static int dlfb_usb_probe(struct usb_interface *intf,
 	if (!dlfb_parse_vendor_descriptor(dlfb, intf)) {
 		dev_err(&intf->dev,
 			"firmware not recognized, incompatible device?\n");
-		retval = -ENODEV;
 		goto error;
 	}
 
@@ -1695,10 +1686,8 @@ static int dlfb_usb_probe(struct usb_interface *intf,
 
 	/* allocates framebuffer driver structure, not framebuffer memory */
 	info = framebuffer_alloc(0, &dlfb->udev->dev);
-	if (!info) {
-		retval = -ENOMEM;
+	if (!info)
 		goto error;
-	}
 
 	dlfb->info = info;
 	info->par = dlfb;
diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c
index 52ec80b..e30f942 100644
--- a/drivers/video/fbdev/w100fb.c
+++ b/drivers/video/fbdev/w100fb.c
@@ -770,18 +770,12 @@ int w100fb_probe(struct platform_device *pdev)
 		fb_dealloc_cmap(&info->cmap);
 		kfree(info->pseudo_palette);
 	}
-	if (remapped_fbuf != NULL) {
+	if (remapped_fbuf != NULL)
 		iounmap(remapped_fbuf);
-		remapped_fbuf = NULL;
-	}
-	if (remapped_regs != NULL) {
+	if (remapped_regs != NULL)
 		iounmap(remapped_regs);
-		remapped_regs = NULL;
-	}
-	if (remapped_base != NULL) {
+	if (remapped_base != NULL)
 		iounmap(remapped_base);
-		remapped_base = NULL;
-	}
 	if (info)
 		framebuffer_release(info);
 	return err;
@@ -801,11 +795,8 @@ static int w100fb_remove(struct platform_device *pdev)
 	fb_dealloc_cmap(&info->cmap);
 
 	iounmap(remapped_base);
-	remapped_base = NULL;
 	iounmap(remapped_regs);
-	remapped_regs = NULL;
 	iounmap(remapped_fbuf);
-	remapped_fbuf = NULL;
 
 	framebuffer_release(info);