diff --git a/Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga b/Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga
new file mode 100644
index 0000000..bfd568d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga
@@ -0,0 +1,5 @@
+What:		/sys/bus/platform/drivers/vexpress-muxfpga/<muxfpga device>/source
+Date:		April 2013
+Contant:	Pawel Moll <pawel.moll@arm.com>
+Description:	This file stores the id of the video signal source
+		supposed to be routed to the board's DVI output.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index b989e8e..84c6083 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -176,3 +176,6 @@ obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o
 obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o
 obj-$(CONFIG_VIDEOMODE) += videomode.o
 obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
+
+# platform specific output drivers
+obj-$(CONFIG_VEXPRESS_CONFIG)	  += vexpress-muxfpga.o
diff --git a/drivers/video/vexpress-muxfpga.c b/drivers/video/vexpress-muxfpga.c
new file mode 100644
index 0000000..1731ad0
--- /dev/null
+++ b/drivers/video/vexpress-muxfpga.c
@@ -0,0 +1,228 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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.
+ *
+ * Copyright (C) 2013 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-muxfpga: " fmt
+
+#include <linux/fb.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/vexpress.h>
+#include <video/display.h>
+#include <video/videomode.h>
+
+
+static struct vexpress_config_func *vexpress_muxfpga_func;
+static struct display_entity *vexpress_muxfpga_output;
+
+
+static struct vexpress_muxfpga_source {
+	struct display_entity display;
+	struct videomode mode;
+	bool updated;
+} vexpress_muxfpga_sources[__VEXPRESS_SITE_LAST];
+static u32 vexpress_muxfpga_source_site = VEXPRESS_SITE_MB;
+static bool vexpress_muxfpga_source_stored;
+
+
+static int vexpress_muxfpga_set_site(u32 site)
+{
+	int err;
+
+	if (site >= ARRAY_SIZE(vexpress_muxfpga_sources))
+		return -EINVAL;
+
+	err = vexpress_config_write(vexpress_muxfpga_func, 0, site);
+	if (!err) {
+		pr_debug("Selected site %d as source\n", site);
+		vexpress_muxfpga_source_site = site;
+	} else {
+		pr_warn("Failed to select site %d as source! (%d)\n",
+				site, err);
+	}
+
+	return err;
+}
+
+static unsigned int vexpress_muxfpga_preferred_sites[] = {
+	VEXPRESS_SITE_MASTER,
+	VEXPRESS_SITE_DB1,
+	VEXPRESS_SITE_DB2,
+	VEXPRESS_SITE_MB,
+};
+static unsigned int vexpress_muxfpga_preferred_sites_num =
+		ARRAY_SIZE(vexpress_muxfpga_preferred_sites);
+module_param_array_named(preferred_sites, vexpress_muxfpga_preferred_sites,
+		uint, &vexpress_muxfpga_preferred_sites_num, S_IRUGO);
+MODULE_PARM_DESC(preferred_sites, "Preferred order of MUXFPGA (DVI output) "
+		"sources; values can be a daughterboard site ID (1-2), the "
+		"motherboard ID (0) or a value describing the master site "
+		"(0xf).");
+
+static int vexpress_muxfpga_get_priority(u32 site)
+{
+	int i;
+
+	for (i = 0; i < vexpress_muxfpga_preferred_sites_num; i++) {
+		u32 preference = vexpress_muxfpga_preferred_sites[i];
+
+		if (site == vexpress_get_site(preference))
+			return i;
+	}
+
+	return INT_MAX;
+}
+
+static void vexpress_muxfpga_set_preffered_site(u32 site)
+{
+	int current_priority = vexpress_muxfpga_get_priority(
+			vexpress_muxfpga_source_site);
+	int new_priority = vexpress_muxfpga_get_priority(site);
+
+	if (new_priority <= current_priority)
+		vexpress_muxfpga_set_site(site);
+}
+
+
+static int vexpress_muxfpga_display_update(struct display_entity *display,
+		const struct videomode *mode)
+{
+	int err = display_entity_update(vexpress_muxfpga_output, mode);
+
+	if (!err) {
+		struct vexpress_muxfpga_source *source = container_of(display,
+				struct vexpress_muxfpga_source, display);
+
+		source->updated = true;
+		source->mode = *mode;
+	}
+
+	return err;
+}
+
+static int vexpress_muxfpga_display_get_modes(struct display_entity *display,
+		const struct videomode **modes)
+{
+	return display_entity_get_modes(vexpress_muxfpga_output, modes);
+}
+
+static int vexpress_muxfpga_display_get_params(struct display_entity *display,
+		struct display_entity_interface_params *params)
+{
+	return display_entity_get_params(vexpress_muxfpga_output, params);
+}
+
+static const struct display_entity_control_ops vexpress_muxfpga_display_ops = {
+	.update = vexpress_muxfpga_display_update,
+	.get_modes = vexpress_muxfpga_display_get_modes,
+	.get_params = vexpress_muxfpga_display_get_params,
+};
+
+
+static ssize_t vexpress_muxfpga_show_source(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+
+	return sprintf(buf, "%u\n", vexpress_muxfpga_source_site);
+}
+
+static ssize_t vexpress_muxfpga_store_source(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	u32 site;
+	int err = kstrtou32(buf, 0, &site);
+
+	if (!err) {
+		site = vexpress_get_site(site);
+		err = vexpress_muxfpga_set_site(site);
+	}
+
+	if (!err)
+		vexpress_muxfpga_source_stored = true;
+
+	if (!err && vexpress_muxfpga_sources[site].updated)
+		vexpress_muxfpga_display_update(
+				&vexpress_muxfpga_sources[site].display,
+				&vexpress_muxfpga_sources[site].mode);
+
+	return err ? err : count;
+}
+
+DEVICE_ATTR(source, S_IRUGO | S_IWUSR, vexpress_muxfpga_show_source,
+		vexpress_muxfpga_store_source);
+
+static struct display_entity *vexpress_muxfpga_display_get(
+		struct of_phandle_args *spec, void *data)
+{
+	u32 site = vexpress_get_site(spec->args[0]);
+
+	if (WARN_ON(spec->args_count != 1 ||
+			site >= ARRAY_SIZE(vexpress_muxfpga_sources)))
+		return NULL;
+
+	/* Skip source selection if the user made his choice */
+	if (!vexpress_muxfpga_source_stored)
+		vexpress_muxfpga_set_preffered_site(site);
+
+	return &vexpress_muxfpga_sources[site].display;
+}
+
+
+static struct of_device_id vexpress_muxfpga_of_match[] = {
+	{ .compatible = "arm,vexpress-muxfpga", },
+	{}
+};
+
+static int vexpress_muxfpga_probe(struct platform_device *pdev)
+{
+	struct display_entity_interface_params params;
+	int i;
+
+	vexpress_muxfpga_output = of_display_entity_get(pdev->dev.of_node, 0);
+	if (!vexpress_muxfpga_output)
+		return -EPROBE_DEFER;
+
+	if (display_entity_get_params(vexpress_muxfpga_output, &params) != 0 ||
+			params.type != DISPLAY_ENTITY_INTERFACE_TFT_PARALLEL)
+		return -EINVAL;
+
+	vexpress_muxfpga_func = vexpress_config_func_get_by_dev(&pdev->dev);
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_muxfpga_sources); i++) {
+		struct vexpress_muxfpga_source *source =
+			&vexpress_muxfpga_sources[i];
+
+		source->display.dev = &pdev->dev;
+		source->display.ops.ctrl = &vexpress_muxfpga_display_ops;
+		WARN_ON(display_entity_register(&source->display));
+		of_display_entity_add_provider(pdev->dev.of_node,
+				vexpress_muxfpga_display_get, NULL);
+	}
+
+	device_create_file(&pdev->dev, &dev_attr_source);
+
+	return 0;
+}
+
+static struct platform_driver vexpress_muxfpga_driver = {
+	.probe = vexpress_muxfpga_probe,
+	.driver = {
+		.name = "vexpress-muxfpga",
+		.of_match_table = vexpress_muxfpga_of_match,
+	},
+};
+
+static int __init vexpress_muxfpga_init(void)
+{
+	return platform_driver_register(&vexpress_muxfpga_driver);
+}
+device_initcall(vexpress_muxfpga_init);
