new file mode 100644
@@ -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.
@@ -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
new file mode 100644
@@ -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, ¶ms) != 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);