diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index caf1efc..f17eb0a 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -4,6 +4,46 @@
 
 menu "Graphics support"
 
+config DM_VIDEO
+	bool "Enable driver model support for LCD/video"
+	depends on DM
+	help
+	  This enables driver model for LCD and video devices. These support
+	  a bitmap display of various sizes and depths which can be drawn on
+	  to display a command-line console or splash screen. Enabling this
+	  option compiles in the video uclass and routes all LCD/video access
+	  through this.
+
+config VIDEO_BPP8
+	bool "Support 8-bit-per-pixel displays"
+	depends on DM_VIDEO
+	default y if DM_VIDEO
+	help
+	  Support drawing text and bitmaps onto a 8-bit-per-pixel display.
+	  Ebabling this will include code to support this display. Without
+	  this option, such displays will not be supported and console output
+	  will be empty.
+
+config VIDEO_BPP16
+	bool "Support 16-bit-per-pixel displays"
+	depends on DM_VIDEO
+	default y if DM_VIDEO
+	help
+	  Support drawing text and bitmaps onto a 16-bit-per-pixel display.
+	  Ebabling this will include code to support this display. Without
+	  this option, such displays will not be supported and console output
+	  will be empty.
+
+config VIDEO_BPP32
+	bool "Support 32-bit-per-pixel displays"
+	depends on DM_VIDEO
+	default y if DM_VIDEO
+	help
+	  Support drawing text and bitmaps onto a 32-bit-per-pixel display.
+	  Ebabling this will include code to support this display. Without
+	  this option, such displays will not be supported and console output
+	  will be empty.
+
 config VIDEO_VESA
 	bool "Enable VESA video driver support"
 	default n
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index e85fd8a..7192013 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -7,6 +7,7 @@
 
 ifdef CONFIG_DM
 obj-$(CONFIG_DISPLAY_PORT) += dp-uclass.o
+obj-$(CONFIG_DM_VIDEO) += video-uclass.o
 endif
 
 obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
new file mode 100644
index 0000000..1615889
--- /dev/null
+++ b/drivers/video/video-uclass.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <stdio_dev.h>
+#include <video.h>
+#include <video_console.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#ifdef CONFIG_SANDBOX
+#include <asm/sdl.h>
+#endif
+
+/*
+ * Theory of operation:
+ *
+ * Before relocation each device is bound. The driver for each device must
+ * set the @align and @size values in struct video_uc_platdata. This
+ * information represents the requires size and alignment of the frame buffer
+ * for the device. The values can be an over-estimate but cannot be too
+ * small. The actual values will be suppled (in the same manner) by the bind()
+ * method after relocation.
+ *
+ * This information is then picked up by video_reserve() which works out how
+ * much memory is needed for all devices. This is allocated between
+ * gd->video_bottom and gd->video_top.
+ *
+ * After relocation the same process occurs. The driver supplies the same
+ * @size and @align information and this time video_post_bind() checks that
+ * the drivers does not overflow the allocated memory.
+ *
+ * The frame buffer address is actually set (to plat->base) in
+ * video_post_probe(). This function also clears the frame buffer and
+ * allocates a suitable text console device. This can then be used to write
+ * text to the video device.
+ */
+DECLARE_GLOBAL_DATA_PTR;
+
+static ulong alloc_fb(struct udevice *dev, ulong *addrp)
+{
+	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+	ulong base, align, size;
+
+	align = plat->align ? plat->align : 1 << 20;
+	base = *addrp - plat->size;
+	base &= ~(align - 1);
+	plat->base = base;
+	size = *addrp - base;
+	*addrp = base;
+
+	return size;
+}
+
+int video_reserve(ulong *addrp)
+{
+	struct udevice *dev;
+	ulong size;
+
+	gd->video_top = *addrp;
+	for (uclass_find_first_device(UCLASS_VIDEO, &dev);
+	     dev;
+	     uclass_find_next_device(&dev)) {
+		size = alloc_fb(dev, addrp);
+		debug("%s: Reserving %lx bytes at %lx for video device '%s'\n",
+		      __func__, size, *addrp, dev->name);
+	}
+	gd->video_bottom = *addrp;
+	debug("Video frame buffers from %lx to %lx\n", gd->video_bottom,
+	      gd->video_top);
+
+	return 0;
+}
+
+static int video_clear(struct udevice *dev)
+{
+	struct video_priv *priv = dev_get_uclass_priv(dev);
+
+	if (priv->bpix == VIDEO_BPP32) {
+		u32 *ppix = priv->fb;
+		u32 *end = priv->fb + priv->fb_size;
+
+		while (ppix < end)
+			*ppix++ = priv->colour_bg;
+	} else {
+		memset(priv->fb, priv->colour_bg, priv->fb_size);
+	}
+
+	return 0;
+}
+
+/* Flush video activity to the caches */
+void video_sync(struct udevice *vid)
+{
+	/*
+	 * flush_dcache_range() is declared in common.h but it seems that some
+	 * architectures do not actually implement it. Is there a way to find
+	 * out whether it exists? For now, ARM is safe.
+	 */
+#if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF)
+	struct video_priv *priv = dev_get_uclass_priv(vid);
+
+	if (priv->flush_dcache) {
+		flush_dcache_range((ulong)priv->fb,
+				   (ulong)priv->fb + priv->fb_size);
+	}
+#elif defined(CONFIG_VIDEO_SANDBOX_SDL)
+	struct video_priv *priv = dev_get_uclass_priv(vid);
+	static ulong last_sync;
+
+	if (get_timer(last_sync) > 10) {
+		sandbox_sdl_sync(priv->fb);
+		last_sync = get_timer(0);
+	}
+#endif
+}
+
+void video_sync_all(void)
+{
+	struct udevice *dev;
+
+	for (uclass_find_first_device(UCLASS_VIDEO, &dev);
+	     dev;
+	     uclass_find_next_device(&dev)) {
+		if (device_active(dev))
+			video_sync(dev);
+	}
+}
+
+int video_get_xsize(struct udevice *dev)
+{
+	struct video_priv *priv = dev_get_uclass_priv(dev);
+
+	return priv->xsize;
+}
+
+int video_get_ysize(struct udevice *dev)
+{
+	struct video_priv *priv = dev_get_uclass_priv(dev);
+
+	return priv->ysize;
+}
+
+/* Set up the colour map */
+static int video_pre_probe(struct udevice *dev)
+{
+	struct video_priv *priv = dev_get_uclass_priv(dev);
+
+	priv->cmap = calloc(256, sizeof(ushort));
+	if (!priv->cmap)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int video_pre_remove(struct udevice *dev)
+{
+	struct video_priv *priv = dev_get_uclass_priv(dev);
+
+	free(priv->cmap);
+
+	return 0;
+}
+
+/* Set up the display ready for use */
+static int video_post_probe(struct udevice *dev)
+{
+	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+	struct video_priv *priv = dev_get_uclass_priv(dev);
+	char name[30], drv[15], *str;
+	struct udevice *cons;
+	int ret;
+
+	/* Set up the line and display size */
+	priv->fb = map_sysmem(plat->base, plat->size);
+	priv->line_length = priv->xsize * VNBYTES(priv->bpix);
+	priv->fb_size = priv->line_length * priv->ysize;
+
+	/* Set up colours - we could in future support other colours */
+#ifdef CONFIG_SYS_WHITE_ON_BLACK
+	priv->colour_fg = 0xffffff;
+#else
+	priv->colour_bg = 0xffffff;
+#endif
+	video_clear(dev);
+
+	return 0;
+};
+
+/* Post-relocation, allocate memory for the frame buffer */
+static int video_post_bind(struct udevice *dev)
+{
+	ulong addr = gd->video_top;
+	ulong size;
+
+	/* Before relocation there is nothing to do here */
+	if ((!gd->flags & GD_FLG_RELOC))
+		return 0;
+	size = alloc_fb(dev, &addr);
+	if (addr < gd->video_bottom) {
+		/* Device tree node may need the 'u-boot,dm-pre-reloc' tag */
+		printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n",
+		       dev->name);
+		return -ENOSPC;
+	}
+	debug("%s: Claiming %lx bytes at %lx for video device '%s'\n",
+	      __func__, size, addr, dev->name);
+	gd->video_bottom = addr;
+
+	return 0;
+}
+
+UCLASS_DRIVER(video) = {
+	.id		= UCLASS_VIDEO,
+	.name		= "video",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.post_bind	= video_post_bind,
+	.pre_probe	= video_pre_probe,
+	.post_probe	= video_post_probe,
+	.pre_remove	= video_pre_remove,
+	.per_device_auto_alloc_size	= sizeof(struct video_priv),
+	.per_device_platdata_auto_alloc_size = sizeof(struct video_uc_platdata),
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 27fa0b6..3934375 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -66,6 +66,7 @@ enum uclass_id {
 	UCLASS_USB,		/* USB bus */
 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
 	UCLASS_USB_HUB,		/* USB hub */
+	UCLASS_VIDEO,		/* Video or LCD device */
 	UCLASS_VIDEO_BRIDGE,	/* Video bridge, e.g. DisplayPort to LVDS */
 
 	UCLASS_COUNT,
diff --git a/include/video.h b/include/video.h
index 65e4ec1..5fd426e 100644
--- a/include/video.h
+++ b/include/video.h
@@ -1,14 +1,168 @@
 /*
-** MPC823 Video Controller
-** =======================
-** (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
-** AIRVENT SAM s.p.a - RIMINI(ITALY)
-**
-*/
+ * Video uclass and legacy implementation
+ *
+ * Copyright (c) 2015 Google, Inc
+ *
+ * MPC823 Video Controller
+ * =======================
+ * (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
+ * AIRVENT SAM s.p.a - RIMINI(ITALY)
+ *
+ */
 
 #ifndef _VIDEO_H_
 #define _VIDEO_H_
 
+#ifdef CONFIG_DM_VIDEO
+
+#include <stdio_dev.h>
+
+struct video_uc_platdata {
+	uint align;
+	uint size;
+	ulong base;
+};
+
+/*
+ * Bits per pixel selector. Each value n is such that the bits-per-pixel is
+ * 2 ^ n
+ */
+enum video_log2_bpp {
+	VIDEO_BPP1	= 0,
+	VIDEO_BPP2,
+	VIDEO_BPP4,
+	VIDEO_BPP8,
+	VIDEO_BPP16,
+	VIDEO_BPP32,
+};
+
+/*
+ * Convert enum video_log2_bpp to bytes and bits. Note we omit the outer
+ * brackets to allow multiplication by fractional pixels.
+ */
+#define VNBYTES(bpix)	(1 << (bpix)) / 8
+
+#define VNBITS(bpix)	(1 << (bpix))
+
+/**
+ * struct video_priv - Device information used by the video uclass
+ *
+ * @xsize:	Number of pixel columns (e.g. 1366)
+ * @ysize:	Number of pixels rows (e.g.. 768)
+ * @tor:	Display rotation (0=none, 1=90 degrees clockwise, etc.)
+ * @bpix:	Encoded bits per pixel
+ * @fb:		Frame buffer
+ * @fb_size:	Frame buffer size
+ * @fb_size:	Frame buffer size
+ * @line_length:	Length of each frame buffer line, in bytes
+ * @colour_fg:	Foreground colour (pixel value)
+ * @colour_bg:	Background colour (pixel value)
+ * @flush_dcache:	true to enable flushing of the data cache after
+ *		the LCD is updated
+ * @cmap:	Colour map for 8-bit-per-pixel displays
+ */
+struct video_priv {
+	/* Things set up by the driver: */
+	ushort xsize;
+	ushort ysize;
+	ushort rot;
+	enum video_log2_bpp bpix;
+
+	/*
+	 * Things that are private to the uclass: don't use these in the
+	 * driver
+	 */
+	void *fb;
+	int fb_size;
+	int line_length;
+	int colour_fg;
+	int colour_bg;
+	bool flush_dcache;
+	ushort *cmap;
+};
+
+/* Placeholder - there are no video operations at present */
+struct video_ops {
+};
+
+#define video_get_ops(dev)        ((struct video_ops *)(dev)->driver->ops)
+
+/**
+ * video_reserve() - Reserve frame-buffer memory for video devices
+ *
+ * Note: This function is for internal use.
+ *
+ * This uses the uclass platdata's @size and @align members to figure out
+ * a size and position for each frame buffer as part of the pre-relocation
+ * process of determining the post-relocation memory layout.
+ *
+ * gd->video_top is set to the initial value of *@addrp and gd->video_bottom
+ * is set to the final value.
+ *
+ * @addrp:	On entry, the top of available memory. On exit, the new top,
+ *		after allocating the required memory.
+ * @return 0
+ */
+int video_reserve(ulong *addrp);
+
+/**
+ * video_sync() - Sync a device's frame buffer with its hardware
+ *
+ * Some frame buffers are cached or have a secondary frame buffer. This
+ * function syncs these up so that the current contents of the U-Boot frame
+ * buffer are displayed to the user.
+ *
+ * @dev:	Device to sync
+ */
+void video_sync(struct udevice *vid);
+
+/**
+ * video_sync_all() - Sync all devices' frame buffers with there hardware
+ *
+ * This calls video_sync() on all active video devices.
+ */
+void video_sync_all(void);
+
+/**
+ * video_bmp_display() - Display a BMP file
+ *
+ * @dev:	Device to display the bitmap on
+ * @bmp_image:	Address of bitmap image to display
+ * @x:		X position in pixels from the left
+ * @y:		Y position in pixels from the top
+ * @align:	true to adjust the coordinates to centre the image. If false
+ *		the coordinates are used as is. If true:
+ * 
+ *		- if a coordinate is 0x7fff then the image will be centred in
+ *		  that direction
+ *		- if a coordinate is -ve then it will be offset to the
+ *		  left/top of the centre by that many pixels
+ *		- if a coordinate is positive it will be used unchnaged.
+ * @return 0 if OK, -ve on error
+ */
+int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
+		      bool align);
+
+/**
+ * video_get_xsize() - Get the width of the display in pixels
+ *
+ * @dev:	Device to check
+ * @return device frame buffer width in pixels
+ */
+int video_get_xsize(struct udevice *dev);
+
+/**
+ * video_get_xsize() - Get the height of the display in pixels
+ *
+ * @dev:	Device to check
+ * @return device frame buffer height in pixels
+ */
+int video_get_ysize(struct udevice *dev);
+
+#endif /* CONFIG_DM_VIDEO */
+
+#ifndef CONFIG_DM_VIDEO
+
 /* Video functions */
 
 struct stdio_dev;
@@ -73,4 +227,7 @@ int kwh043st20_f01_spi_startup(unsigned int bus, unsigned int cs,
 int lg4573_spi_startup(unsigned int bus, unsigned int cs,
 	unsigned int max_hz, unsigned int spi_mode);
 #endif
+
+#endif /* CONFIG_DM_VIDEO */
+
 #endif
