video: sunxi_display: Convert to DM_VIDEO

Message ID 20200616204922.587560-1-jagan@amarulasolutions.com
State New
Headers show
Series
  • video: sunxi_display: Convert to DM_VIDEO
Related show

Commit Message

Jagan Teki June 16, 2020, 8:49 p.m. UTC
DM_VIDEO migration deadline is already expired, but around
80 Allwinner boards are still using video in a legacy way.

Patch

===================== WARNING ======================
This board does not use CONFIG_DM_VIDEO Please update
the board to use CONFIG_DM_VIDEO before the v2019.07 release.
Failure to update by the deadline may result in board removal.
See doc/driver-model/migration.rst for more info.
====================================================

So let's live these boards on the tree before the video maintainer
removes it by converting in to DM_VIDEO.

Tested in Bananapi M1+ Plus 1920x1200 HDMI out.

Cc: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Note: Existing video log would break since the similar
configuration of cfb_console will not build for DM_VIDEO.
Will try to send the splashscreen, in next version or the
next patches.

 arch/arm/mach-sunxi/Kconfig         |   3 +-
 drivers/video/sunxi/sunxi_display.c | 264 ++++++++++++++++------------
 include/configs/sunxi-common.h      |   7 -
 scripts/config_whitelist.txt        |   1 -
 4 files changed, 156 insertions(+), 119 deletions(-)

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index be0822bfb7..4fd31f7d61 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -758,7 +758,8 @@  config VIDEO_SUNXI
 	depends on !MACH_SUN9I
 	depends on !MACH_SUN50I
 	depends on !MACH_SUN50I_H6
-	select VIDEO
+	select DM_VIDEO
+	select DISPLAY
 	imply VIDEO_DT_SIMPLEFB
 	default y
 	---help---
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index f52aba4d21..fb51b0c5ba 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -7,6 +7,8 @@ 
  */
 
 #include <common.h>
+#include <display.h>
+#include <dm.h>
 #include <cpu_func.h>
 #include <efi_loader.h>
 #include <init.h>
@@ -28,7 +30,9 @@ 
 #include <fdt_support.h>
 #include <i2c.h>
 #include <malloc.h>
+#include <video.h>
 #include <video_fb.h>
+#include <dm/uclass-internal.h>
 #include "../videomodes.h"
 #include "../anx9804.h"
 #include "../hitachi_tx18d42vm_lcd.h"
@@ -45,6 +49,13 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
+enum {
+	/* Maximum LCD size we support */
+	LCD_MAX_WIDTH		= 3840,
+	LCD_MAX_HEIGHT		= 2160,
+	LCD_MAX_LOG2_BPP	= VIDEO_BPP32,
+};
+
 enum sunxi_monitor {
 	sunxi_monitor_none,
 	sunxi_monitor_dvi,
@@ -59,12 +70,11 @@  enum sunxi_monitor {
 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
 
 struct sunxi_display {
-	GraphicDevice graphic_device;
 	enum sunxi_monitor monitor;
 	unsigned int depth;
 	unsigned int fb_addr;
 	unsigned int fb_size;
-} sunxi_display;
+};
 
 const struct ctfb_res_modes composite_video_modes[2] = {
 	/*  x     y  hz  pixclk ps/kHz   le   ri  up  lo   hs vs  s  vmode */
@@ -214,7 +224,8 @@  static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
 	return r;
 }
 
-static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
+static int sunxi_hdmi_edid_get_mode(struct sunxi_display *sunxi_display,
+				    struct ctfb_res_modes *mode,
 				    bool verbose_mode)
 {
 	struct edid1_info edid1;
@@ -291,14 +302,14 @@  static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
 	}
 
 	/* Check for basic audio support, if found enable hdmi output */
-	sunxi_display.monitor = sunxi_monitor_dvi;
+	sunxi_display->monitor = sunxi_monitor_dvi;
 	for (i = 0; i < ext_blocks; i++) {
 		if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
 		    cea681[i].revision < 2)
 			continue;
 
 		if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
-			sunxi_display.monitor = sunxi_monitor_hdmi;
+			sunxi_display->monitor = sunxi_monitor_hdmi;
 	}
 
 	return 0;
@@ -414,9 +425,9 @@  static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
 static void sunxi_frontend_enable(void) {}
 #endif
 
-static bool sunxi_is_composite(void)
+static bool sunxi_is_composite(enum sunxi_monitor monitor)
 {
-	switch (sunxi_display.monitor) {
+	switch (monitor) {
 	case sunxi_monitor_none:
 	case sunxi_monitor_dvi:
 	case sunxi_monitor_hdmi:
@@ -473,7 +484,8 @@  static const u32 sunxi_rgb2yuv_coef[12] = {
 };
 
 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
-				    unsigned int address)
+				    unsigned int address,
+				    enum sunxi_monitor monitor)
 {
 	struct sunxi_de_be_reg * const de_be =
 		(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
@@ -502,7 +514,7 @@  static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
 #endif
 			     SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
 
-	if (sunxi_is_composite()) {
+	if (sunxi_is_composite(monitor)) {
 		writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
 		       &de_be->output_color_ctrl);
 		for (i = 0; i < 12; i++)
@@ -616,7 +628,8 @@  static void sunxi_lcdc_backlight_enable(void)
 		gpio_direction_output(pin, PWM_ON);
 }
 
-static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
+static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display *sunxi_display,
+				      const struct ctfb_res_modes *mode,
 				      bool for_ext_vga_dac)
 {
 	struct sunxi_lcdc_reg * const lcdc =
@@ -643,17 +656,18 @@  static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
 	}
 
 	lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
-		     sunxi_is_composite());
+		     sunxi_is_composite(sunxi_display->monitor));
 
 	video_ctfb_mode_to_display_timing(mode, &timing);
 	lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
-			    sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
+			    sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
 }
 
 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
 				      int *clk_div, int *clk_double,
-				      bool use_portd_hvsync)
+				      bool use_portd_hvsync,
+				      enum sunxi_monitor monitor)
 {
 	struct sunxi_lcdc_reg * const lcdc =
 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
@@ -663,7 +677,7 @@  static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
 
 	video_ctfb_mode_to_display_timing(mode, &timing);
 	lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
-			    sunxi_is_composite());
+			    sunxi_is_composite(monitor));
 
 	if (use_portd_hvsync) {
 		sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
@@ -671,7 +685,7 @@  static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
 	}
 
 	lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
-		     sunxi_is_composite());
+		     sunxi_is_composite(monitor));
 }
 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
 
@@ -725,7 +739,8 @@  static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
 }
 
 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
-				int clk_div, int clk_double)
+				int clk_div, int clk_double,
+				enum sunxi_monitor monitor)
 {
 	struct sunxi_hdmi_reg * const hdmi =
 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
@@ -734,7 +749,7 @@  static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
 	/* Write clear interrupt status bits */
 	writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
 
-	if (sunxi_display.monitor == sunxi_monitor_hdmi)
+	if (monitor == sunxi_monitor_hdmi)
 		sunxi_hdmi_setup_info_frames(mode);
 
 	/* Set input sync enable */
@@ -789,7 +804,7 @@  static void sunxi_hdmi_enable(void)
 
 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
 
-static void sunxi_tvencoder_mode_set(void)
+static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor)
 {
 	struct sunxi_ccm_reg * const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
@@ -801,7 +816,7 @@  static void sunxi_tvencoder_mode_set(void)
 	/* Clock on */
 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
 
-	switch (sunxi_display.monitor) {
+	switch (monitor) {
 	case sunxi_monitor_vga:
 		tvencoder_mode_set(tve, tve_mode_vga);
 		break;
@@ -896,26 +911,28 @@  static void sunxi_engines_init(void)
 	sunxi_drc_init();
 }
 
-static void sunxi_mode_set(const struct ctfb_res_modes *mode,
+static void sunxi_mode_set(struct sunxi_display *sunxi_display,
+			   const struct ctfb_res_modes *mode,
 			   unsigned int address)
 {
+	enum sunxi_monitor monitor = sunxi_display->monitor;
 	int __maybe_unused clk_div, clk_double;
 	struct sunxi_lcdc_reg * const lcdc =
 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
 	struct sunxi_tve_reg * __maybe_unused const tve =
 		(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
 
-	switch (sunxi_display.monitor) {
+	switch (sunxi_display->monitor) {
 	case sunxi_monitor_none:
 		break;
 	case sunxi_monitor_dvi:
 	case sunxi_monitor_hdmi:
 #ifdef CONFIG_VIDEO_HDMI
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
-		sunxi_hdmi_mode_set(mode, clk_div, clk_double);
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
+		sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 		sunxi_hdmi_enable();
 #endif
 		break;
@@ -930,7 +947,7 @@  static void sunxi_mode_set(const struct ctfb_res_modes *mode,
 			axp_set_eldo(3, 1800);
 			anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
 				     ANX9804_DATA_RATE_1620M,
-				     sunxi_display.depth);
+				     sunxi_display->depth);
 		}
 		if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
 			mdelay(50); /* Wait for lcd controller power on */
@@ -942,10 +959,10 @@  static void sunxi_mode_set(const struct ctfb_res_modes *mode,
 			i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
 			i2c_set_bus_num(orig_i2c_bus);
 		}
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon0_mode_set(mode, false);
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 #ifdef CONFIG_VIDEO_LCD_SSD2828
 		sunxi_ssd2828_init(mode);
 #endif
@@ -953,17 +970,17 @@  static void sunxi_mode_set(const struct ctfb_res_modes *mode,
 		break;
 	case sunxi_monitor_vga:
 #ifdef CONFIG_VIDEO_VGA
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
-		sunxi_tvencoder_mode_set();
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor);
+		sunxi_tvencoder_mode_set(monitor);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 		tvencoder_enable(tve);
 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon0_mode_set(mode, true);
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 		sunxi_vga_external_dac_enable();
 #endif
 		break;
@@ -972,11 +989,11 @@  static void sunxi_mode_set(const struct ctfb_res_modes *mode,
 	case sunxi_monitor_composite_pal_m:
 	case sunxi_monitor_composite_pal_nc:
 #ifdef CONFIG_VIDEO_COMPOSITE
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
-		sunxi_tvencoder_mode_set();
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
+		sunxi_tvencoder_mode_set(monitor);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 		tvencoder_enable(tve);
 #endif
 		break;
@@ -999,11 +1016,6 @@  static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
 	}
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
-{
-	return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
-}
-
 static bool sunxi_has_hdmi(void)
 {
 #ifdef CONFIG_VIDEO_HDMI
@@ -1052,9 +1064,11 @@  static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
 		return sunxi_monitor_none;
 }
 
-void *video_hw_init(void)
+static int sunxi_de_probe(struct udevice *dev)
 {
-	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+	struct sunxi_display *sunxi_display = dev_get_priv(dev);
 	const struct ctfb_res_modes *mode;
 	struct ctfb_res_modes custom;
 	const char *options;
@@ -1067,10 +1081,8 @@  void *video_hw_init(void)
 	char mon[16];
 	char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
 
-	memset(&sunxi_display, 0, sizeof(struct sunxi_display));
-
 	video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
-				 &sunxi_display.depth, &options);
+				 &sunxi_display->depth, &options);
 #ifdef CONFIG_VIDEO_HDMI
 	hpd = video_get_option_int(options, "hpd", 1);
 	hpd_delay = video_get_option_int(options, "hpd_delay", 500);
@@ -1078,35 +1090,35 @@  void *video_hw_init(void)
 #endif
 	overscan_x = video_get_option_int(options, "overscan_x", -1);
 	overscan_y = video_get_option_int(options, "overscan_y", -1);
-	sunxi_display.monitor = sunxi_get_default_mon(true);
+	sunxi_display->monitor = sunxi_get_default_mon(true);
 	video_get_option_string(options, "monitor", mon, sizeof(mon),
-				sunxi_get_mon_desc(sunxi_display.monitor));
+				sunxi_get_mon_desc(sunxi_display->monitor));
 	for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
 		if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
-			sunxi_display.monitor = i;
+			sunxi_display->monitor = i;
 			break;
 		}
 	}
 	if (i > SUNXI_MONITOR_LAST)
 		printf("Unknown monitor: '%s', falling back to '%s'\n",
-		       mon, sunxi_get_mon_desc(sunxi_display.monitor));
+		       mon, sunxi_get_mon_desc(sunxi_display->monitor));
 
 #ifdef CONFIG_VIDEO_HDMI
 	/* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
-	if (sunxi_display.monitor == sunxi_monitor_dvi ||
-	    sunxi_display.monitor == sunxi_monitor_hdmi) {
+	if (sunxi_display->monitor == sunxi_monitor_dvi ||
+	    sunxi_display->monitor == sunxi_monitor_hdmi) {
 		/* Always call hdp_detect, as it also enables clocks, etc. */
 		hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
 		if (hdmi_present && edid) {
 			printf("HDMI connected: ");
-			if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
+			if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0)
 				mode = &custom;
 			else
 				hdmi_present = false;
 		}
 		/* Fall back to EDID in case HPD failed */
 		if (edid && !hdmi_present) {
-			if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
+			if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) {
 				mode = &custom;
 				hdmi_present = true;
 			}
@@ -1114,38 +1126,39 @@  void *video_hw_init(void)
 		/* Shut down when display was not found */
 		if ((hpd || edid) && !hdmi_present) {
 			sunxi_hdmi_shutdown();
-			sunxi_display.monitor = sunxi_get_default_mon(false);
+			sunxi_display->monitor = sunxi_get_default_mon(false);
 		} /* else continue with hdmi/dvi without a cable connected */
 	}
 #endif
 
-	switch (sunxi_display.monitor) {
+	switch (sunxi_display->monitor) {
 	case sunxi_monitor_none:
-		return NULL;
+		printf("Unknown monitor\n");
+		return -EINVAL;
 	case sunxi_monitor_dvi:
 	case sunxi_monitor_hdmi:
 		if (!sunxi_has_hdmi()) {
 			printf("HDMI/DVI not supported on this board\n");
-			sunxi_display.monitor = sunxi_monitor_none;
-			return NULL;
+			sunxi_display->monitor = sunxi_monitor_none;
+			return -EINVAL;
 		}
 		break;
 	case sunxi_monitor_lcd:
 		if (!sunxi_has_lcd()) {
 			printf("LCD not supported on this board\n");
-			sunxi_display.monitor = sunxi_monitor_none;
-			return NULL;
+			sunxi_display->monitor = sunxi_monitor_none;
+			return -EINVAL;
 		}
-		sunxi_display.depth = video_get_params(&custom, lcd_mode);
+		sunxi_display->depth = video_get_params(&custom, lcd_mode);
 		mode = &custom;
 		break;
 	case sunxi_monitor_vga:
 		if (!sunxi_has_vga()) {
 			printf("VGA not supported on this board\n");
-			sunxi_display.monitor = sunxi_monitor_none;
-			return NULL;
+			sunxi_display->monitor = sunxi_monitor_none;
+			return -EINVAL;
 		}
-		sunxi_display.depth = 18;
+		sunxi_display->depth = 18;
 		break;
 	case sunxi_monitor_composite_pal:
 	case sunxi_monitor_composite_ntsc:
@@ -1153,85 +1166,103 @@  void *video_hw_init(void)
 	case sunxi_monitor_composite_pal_nc:
 		if (!sunxi_has_composite()) {
 			printf("Composite video not supported on this board\n");
-			sunxi_display.monitor = sunxi_monitor_none;
-			return NULL;
+			sunxi_display->monitor = sunxi_monitor_none;
+			return -EINVAL;
 		}
-		if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
-		    sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
+		if (sunxi_display->monitor == sunxi_monitor_composite_pal ||
+		    sunxi_display->monitor == sunxi_monitor_composite_pal_nc)
 			mode = &composite_video_modes[0];
 		else
 			mode = &composite_video_modes[1];
-		sunxi_display.depth = 24;
+		sunxi_display->depth = 24;
 		break;
 	}
 
 	/* Yes these defaults are quite high, overscan on composite sucks... */
 	if (overscan_x == -1)
-		overscan_x = sunxi_is_composite() ? 32 : 0;
+		overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0;
 	if (overscan_y == -1)
-		overscan_y = sunxi_is_composite() ? 20 : 0;
+		overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0;
 
-	sunxi_display.fb_size =
-		(mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
+	sunxi_display->fb_size = plat->size;
 	overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
 	/* We want to keep the fb_base for simplefb page aligned, where as
 	 * the sunxi dma engines will happily accept an unaligned address. */
 	if (overscan_offset)
-		sunxi_display.fb_size += 0x1000;
-
-	if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
-		printf("Error need %dkB for fb, but only %dkB is reserved\n",
-		       sunxi_display.fb_size >> 10,
-		       CONFIG_SUNXI_MAX_FB_SIZE >> 10);
-		return NULL;
-	}
+		sunxi_display->fb_size += 0x1000;
 
 	printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
 	       mode->xres, mode->yres,
 	       (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
-	       sunxi_get_mon_desc(sunxi_display.monitor),
+	       sunxi_get_mon_desc(sunxi_display->monitor),
 	       overscan_x, overscan_y);
 
-	gd->fb_base = gd->bd->bi_dram[0].start +
-		      gd->bd->bi_dram[0].size - sunxi_display.fb_size;
+	sunxi_display->fb_addr = plat->base;
 	sunxi_engines_init();
 
 #ifdef CONFIG_EFI_LOADER
-	efi_add_memory_map(gd->fb_base, sunxi_display.fb_size,
+	efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size,
 			   EFI_RESERVED_MEMORY_TYPE);
 #endif
 
-	fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
-	sunxi_display.fb_addr = gd->fb_base;
+	fb_dma_addr = sunxi_display->fb_addr - CONFIG_SYS_SDRAM_BASE;
 	if (overscan_offset) {
 		fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
-		sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
-		memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
-		flush_cache(gd->fb_base, sunxi_display.fb_size);
+		sunxi_display->fb_addr += (overscan_offset + 0xfff) & ~0xfff;
+		memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size);
+		flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size);
 	}
-	sunxi_mode_set(mode, fb_dma_addr);
+	sunxi_mode_set(sunxi_display, mode, fb_dma_addr);
 
 	/*
 	 * These are the only members of this structure that are used. All the
 	 * others are driver specific. The pitch is stored in plnSizeX.
 	 */
-	graphic_device->frameAdrs = sunxi_display.fb_addr;
-	graphic_device->gdfIndex = GDF_32BIT_X888RGB;
-	graphic_device->gdfBytesPP = 4;
-	graphic_device->winSizeX = mode->xres - 2 * overscan_x;
-	graphic_device->winSizeY = mode->yres - 2 * overscan_y;
-	graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
-
-	return graphic_device;
+	uc_priv->bpix = VIDEO_BPP32;
+	uc_priv->xsize = mode->xres;
+	uc_priv->ysize = mode->yres;
+
+	video_set_flush_dcache(dev, 1);
+
+	return 0;
+}
+
+static int sunxi_de_bind(struct udevice *dev)
+{
+	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+
+	plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
+		     (1 << LCD_MAX_LOG2_BPP) / 8;
+
+	return 0;
 }
 
+static const struct video_ops sunxi_de_ops = {
+};
+
+U_BOOT_DRIVER(sunxi_de) = {
+	.name	= "sunxi_de",
+	.id	= UCLASS_VIDEO,
+	.ops	= &sunxi_de_ops,
+	.bind	= sunxi_de_bind,
+	.probe	= sunxi_de_probe,
+	.priv_auto_alloc_size = sizeof(struct sunxi_display),
+	.flags	= DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DEVICE(sunxi_de) = {
+	.name = "sunxi_de"
+};
+
 /*
  * Simplefb support.
  */
 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
 int sunxi_simplefb_setup(void *blob)
 {
-	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+	struct sunxi_display *sunxi_display;
+	struct video_priv *uc_priv;
+	struct udevice *de;
 	int offset, ret;
 	u64 start, size;
 	const char *pipeline = NULL;
@@ -1242,7 +1273,19 @@  int sunxi_simplefb_setup(void *blob)
 #define PIPELINE_PREFIX
 #endif
 
-	switch (sunxi_display.monitor) {
+	ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de);
+	if (ret) {
+		printf("DE not present\n");
+		return 0;
+	} else if (!device_active(de)) {
+		printf("DE is present but not probed\n");
+		return 0;
+	}
+
+	uc_priv = dev_get_uclass_priv(de);
+	sunxi_display = dev_get_priv(de);
+
+	switch (sunxi_display->monitor) {
 	case sunxi_monitor_none:
 		return 0;
 	case sunxi_monitor_dvi:
@@ -1280,16 +1323,17 @@  int sunxi_simplefb_setup(void *blob)
 	 * linux/arch/arm/mm/ioremap.c around line 301.
 	 */
 	start = gd->bd->bi_dram[0].start;
-	size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
+	size = gd->bd->bi_dram[0].size - sunxi_display->fb_size;
 	ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
 	if (ret) {
 		eprintf("Cannot setup simplefb: Error reserving memory\n");
 		return ret;
 	}
 
-	ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
-			graphic_device->winSizeX, graphic_device->winSizeY,
-			graphic_device->plnSizeX, "x8r8g8b8");
+	ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr,
+				      uc_priv->xsize, uc_priv->ysize,
+				      VNBYTES(uc_priv->bpix) * uc_priv->xsize,
+				      "x8r8g8b8");
 	if (ret)
 		eprintf("Cannot setup simplefb: Error setting properties\n");
 
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 5b0bec0561..290ef12969 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -254,15 +254,8 @@  extern int soft_i2c_gpio_scl;
 #endif /* ifdef CONFIG_REQUIRE_SERIAL_CONSOLE */
 
 #ifdef CONFIG_VIDEO_SUNXI
-/*
- * The amount of RAM to keep free at the top of RAM when relocating u-boot,
- * to use as framebuffer. This must be a multiple of 4096.
- */
-#define CONFIG_SUNXI_MAX_FB_SIZE (16 << 20)
-
 #define CONFIG_VIDEO_LOGO
 #define CONFIG_VIDEO_STD_TIMINGS
-#define CONFIG_I2C_EDID
 #define VIDEO_LINE_LEN (pGD->plnSizeX)
 
 /* allow both serial and cfb console. */
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index f6bf6f2474..30a101638e 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -1724,7 +1724,6 @@  CONFIG_STV0991
 CONFIG_STV0991_HZ
 CONFIG_STV0991_HZ_CLOCK
 CONFIG_ST_SMI
-CONFIG_SUNXI_MAX_FB_SIZE
 CONFIG_SXNI855T
 CONFIG_SYSFLAGS_ADDR
 CONFIG_SYSFS