From d73a32d90f3e75e3936796783728536907e874b4 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 17 Sep 2012 18:09:28 +0100 Subject: [PATCH 1/6] video: Versatile Express DVI output driver Versatile Express' DVI video output can be connected to one the three sources - motherboard's CLCD controller or a video signal generated by one of the daughterboards. This driver configures the muxer FPGA so the output displays content of one of the framebuffers in the system (0 by default, can be changed by user writing to the "fb" sysfs attribute of the muxfpga device). It will also set up the display formatter mode and keep it up to date with mode changes requested by the user (eg. with fbset tool). Signed-off-by: Pawel Moll --- drivers/video/Makefile | 3 + drivers/video/vexpress-dvi.c | 220 +++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 drivers/video/vexpress-dvi.c diff --git a/drivers/video/Makefile b/drivers/video/Makefile index e8bae8dd4804..5084e8c4da9f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -177,3 +177,6 @@ obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o ifeq ($(CONFIG_OF),y) obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o endif + +# platform specific output drivers +obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-dvi.o diff --git a/drivers/video/vexpress-dvi.c b/drivers/video/vexpress-dvi.c new file mode 100644 index 000000000000..f08753450ee4 --- /dev/null +++ b/drivers/video/vexpress-dvi.c @@ -0,0 +1,220 @@ +/* + * 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) 2012 ARM Limited + */ + +#define pr_fmt(fmt) "vexpress-dvi: " fmt + +#include +#include +#include +#include + + +static struct vexpress_config_func *vexpress_dvimode_func; + +static struct { + u32 xres, yres, mode; +} vexpress_dvi_dvimodes[] = { + { 640, 480, 0 }, /* VGA */ + { 800, 600, 1 }, /* SVGA */ + { 1024, 768, 2 }, /* XGA */ + { 1280, 1024, 3 }, /* SXGA */ + { 1600, 1200, 4 }, /* UXGA */ + { 1920, 1080, 5 }, /* HD1080 */ +}; + +static void vexpress_dvi_mode_set(struct fb_info *info, u32 xres, u32 yres) +{ + int err = -ENOENT; + int i; + + if (!vexpress_dvimode_func) + return; + + for (i = 0; i < ARRAY_SIZE(vexpress_dvi_dvimodes); i++) { + if (vexpress_dvi_dvimodes[i].xres == xres && + vexpress_dvi_dvimodes[i].yres == yres) { + pr_debug("mode: %ux%u = %d\n", xres, yres, + vexpress_dvi_dvimodes[i].mode); + err = vexpress_config_write(vexpress_dvimode_func, 0, + vexpress_dvi_dvimodes[i].mode); + break; + } + } + + if (err) + pr_warn("Failed to set %ux%u mode! (%d)\n", xres, yres, err); +} + + +static struct vexpress_config_func *vexpress_muxfpga_func; +static int vexpress_dvi_fb = -1; + +static int vexpress_dvi_mux_set(struct fb_info *info) +{ + int err; + u32 site = vexpress_get_site_by_dev(info->device); + + if (!vexpress_muxfpga_func) + return -ENXIO; + + err = vexpress_config_write(vexpress_muxfpga_func, 0, site); + if (!err) { + pr_debug("Selected MUXFPGA input %d (fb%d)\n", site, + info->node); + vexpress_dvi_fb = info->node; + vexpress_dvi_mode_set(info, info->var.xres, + info->var.yres); + } else { + pr_warn("Failed to select MUXFPGA input %d (fb%d)! (%d)\n", + site, info->node, err); + } + + return err; +} + +static int vexpress_dvi_fb_select(int fb) +{ + int err; + struct fb_info *info; + + /* fb0 is the default */ + if (fb < 0) + fb = 0; + + info = registered_fb[fb]; + if (!info || !lock_fb_info(info)) + return -ENODEV; + + err = vexpress_dvi_mux_set(info); + + unlock_fb_info(info); + + return err; +} + +static ssize_t vexpress_dvi_fb_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", vexpress_dvi_fb); +} + +static ssize_t vexpress_dvi_fb_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + long value; + int err = kstrtol(buf, 0, &value); + + if (!err) + err = vexpress_dvi_fb_select(value); + + return err ? err : count; +} + +DEVICE_ATTR(fb, S_IRUGO | S_IWUSR, vexpress_dvi_fb_show, + vexpress_dvi_fb_store); + + +static int vexpress_dvi_fb_event_notify(struct notifier_block *self, + unsigned long action, void *data) +{ + struct fb_event *event = data; + struct fb_info *info = event->info; + struct fb_videomode *mode = event->data; + + switch (action) { + case FB_EVENT_FB_REGISTERED: + if (vexpress_dvi_fb < 0) + vexpress_dvi_mux_set(info); + break; + case FB_EVENT_MODE_CHANGE: + case FB_EVENT_MODE_CHANGE_ALL: + if (info->node == vexpress_dvi_fb) + vexpress_dvi_mode_set(info, mode->xres, mode->yres); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block vexpress_dvi_fb_notifier = { + .notifier_call = vexpress_dvi_fb_event_notify, +}; +static bool vexpress_dvi_fb_notifier_registered; + + +enum vexpress_dvi_func { FUNC_MUXFPGA, FUNC_DVIMODE }; + +static struct of_device_id vexpress_dvi_of_match[] = { + { + .compatible = "arm,vexpress-muxfpga", + .data = (void *)FUNC_MUXFPGA, + }, { + .compatible = "arm,vexpress-dvimode", + .data = (void *)FUNC_DVIMODE, + }, + {} +}; + +static int vexpress_dvi_probe(struct platform_device *pdev) +{ + enum vexpress_dvi_func func; + const struct of_device_id *match = + of_match_device(vexpress_dvi_of_match, &pdev->dev); + + if (match) + func = (enum vexpress_dvi_func)match->data; + else + func = pdev->id_entry->driver_data; + + switch (func) { + case FUNC_MUXFPGA: + vexpress_muxfpga_func = + vexpress_config_func_get_by_dev(&pdev->dev); + device_create_file(&pdev->dev, &dev_attr_fb); + break; + case FUNC_DVIMODE: + vexpress_dvimode_func = + vexpress_config_func_get_by_dev(&pdev->dev); + break; + } + + if (!vexpress_dvi_fb_notifier_registered) { + fb_register_client(&vexpress_dvi_fb_notifier); + vexpress_dvi_fb_notifier_registered = true; + } + + vexpress_dvi_fb_select(vexpress_dvi_fb); + + return 0; +} + +static const struct platform_device_id vexpress_dvi_id_table[] = { + { .name = "vexpress-muxfpga", .driver_data = FUNC_MUXFPGA, }, + { .name = "vexpress-dvimode", .driver_data = FUNC_DVIMODE, }, + {} +}; + +static struct platform_driver vexpress_dvi_driver = { + .probe = vexpress_dvi_probe, + .driver = { + .name = "vexpress-dvi", + .of_match_table = vexpress_dvi_of_match, + }, + .id_table = vexpress_dvi_id_table, +}; + +static int __init vexpress_dvi_init(void) +{ + return platform_driver_register(&vexpress_dvi_driver); +} +device_initcall(vexpress_dvi_init); From c3e43a142a26fa86463426b085e2fb89a452fdb2 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 15 Jan 2013 17:45:19 +0000 Subject: [PATCH 2/6] video: Make vexpress DVI driver depend on CONFIG_FB The driver uses symbols from fbmem.c so if CONFIG_FB is not selected we get build errors like: drivers/built-in.o: In function `vexpress_dvi_fb_select': :(.text+0x1b6c): undefined reference to `lock_fb_info' :(.text+0x1ba0): undefined reference to `registered_fb' Note, this is only a partial solution because we still have a problem if CONFIG_FB is selected as a module. Signed-off-by: Jon Medhurst --- drivers/video/Kconfig | 5 +++++ drivers/video/Makefile | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2e937bdace6f..aa9429fd4d4f 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -39,6 +39,11 @@ config VIDEOMODE_HELPERS config HDMI bool +config VEXPRESS_DVI_CONTROL + bool "Versatile Express DVI control" + depends on FB && VEXPRESS_CONFIG + default y + menuconfig FB tristate "Support for frame buffer devices" ---help--- diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 5084e8c4da9f..6b5d5f2b4307 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -179,4 +179,4 @@ obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o endif # platform specific output drivers -obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-dvi.o +obj-$(CONFIG_VEXPRESS_DVI_CONTROL) += vexpress-dvi.o From 5f97d66c4a98e658892b0a0d8dcb99332bfa2b54 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 10 Jun 2013 16:05:06 +0100 Subject: [PATCH 3/6] clk: vexpress: Use full node name to identify individual clocks Previously all the clocks were reported as "osc". Now it will be something like "/dcc/osc@0". Signed-off-by: Pawel Moll --- drivers/clk/versatile/clk-vexpress-osc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c index 256c8be74df8..2dc8b41a339d 100644 --- a/drivers/clk/versatile/clk-vexpress-osc.c +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -107,7 +107,7 @@ void __init vexpress_osc_of_setup(struct device_node *node) osc->func = vexpress_config_func_get_by_node(node); if (!osc->func) { pr_err("Failed to obtain config func for node '%s'!\n", - node->name); + node->full_name); goto error; } @@ -119,7 +119,7 @@ void __init vexpress_osc_of_setup(struct device_node *node) of_property_read_string(node, "clock-output-names", &init.name); if (!init.name) - init.name = node->name; + init.name = node->full_name; init.ops = &vexpress_osc_ops; init.flags = CLK_IS_ROOT; From 503552ea012f92de0186efa8b03e7b6208776f98 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 10 Jun 2013 16:05:07 +0100 Subject: [PATCH 4/6] clk: vexpress: Make the clock drivers directly available for arm64 The new arm64 architecture has no idea of platform or machine, so it doesn't have to define ARCH_VEXPRESS configuration option at all. To allow user to select the drivers at all, make it depend on ARM64 as well. Signed-off-by: Pawel Moll Acked-by: Catalin Marinas --- drivers/clk/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 0357ac44638b..d0d9b2124752 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -42,7 +42,7 @@ config COMMON_CLK_WM831X config COMMON_CLK_VERSATILE bool "Clock driver for ARM Reference designs" - depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS + depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64 ---help--- Supports clocking on ARM Reference designs: - Integrator/AP and Integrator/CP From 981794e2f24b5c57558d89a52e1129eadbed46d8 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 10 Jun 2013 16:12:01 +0100 Subject: [PATCH 5/6] power/reset: Make the vexpress driver optional on arm and arm64 The driver can be used on either arm or arm64 platforms, but the latter doesn't have any platform-specific configuration options, so it must be possible to manually enable the driver. Signed-off-by: Pawel Moll Acked-by: Catalin Marinas --- drivers/power/reset/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 349e9ae8090a..ee039dcead04 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -32,7 +32,8 @@ config POWER_RESET_RESTART user presses a key. u-boot then boots into Linux. config POWER_RESET_VEXPRESS - bool + bool "ARM Versatile Express power-off and reset driver" + depends on ARM || ARM64 depends on POWER_RESET help Power off and reset support for the ARM Ltd. Versatile From abe8e2fe9ee8b3cdef3d753706513eb7f340e28d Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Tue, 11 Jun 2013 11:56:02 +0100 Subject: [PATCH 6/6] mfd: vexpress: Make the driver optional for arm and arm64 The driver can be used on either arm or arm64 platforms, but the latter doesn't have any platform-specific configuration options, so it must be possible to manually enable the driver. As the gpiolib is optional for arm64 arch, the gpio/led code must be compiled conditionally. Signed-off-by: Pawel Moll Acked-by: Catalin Marinas --- drivers/mfd/Kconfig | 3 ++- drivers/mfd/vexpress-sysreg.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d54e985748b7..6959b8dc0cba 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1144,7 +1144,8 @@ config MCP_UCB1200_TS endmenu config VEXPRESS_CONFIG - bool + bool "ARM Versatile Express platform infrastructure" + depends on ARM || ARM64 help Platform configuration infrastructure for the ARM Ltd. Versatile Express. diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index 96a020b1dcd1..981bef4b7ebc 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c @@ -351,6 +351,8 @@ void __init vexpress_sysreg_of_early_init(void) } +#ifdef CONFIG_GPIOLIB + #define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \ [VEXPRESS_GPIO_##_name] = { \ .reg = _reg, \ @@ -445,6 +447,8 @@ struct gpio_led_platform_data vexpress_sysreg_leds_pdata = { .leds = vexpress_sysreg_leds, }; +#endif + static ssize_t vexpress_sysreg_sys_id_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -480,6 +484,9 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) setup_timer(&vexpress_sysreg_config_timer, vexpress_sysreg_config_complete, 0); + vexpress_sysreg_dev = &pdev->dev; + +#ifdef CONFIG_GPIOLIB vexpress_sysreg_gpio_chip.dev = &pdev->dev; err = gpiochip_add(&vexpress_sysreg_gpio_chip); if (err) { @@ -490,11 +497,10 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) return err; } - vexpress_sysreg_dev = &pdev->dev; - platform_device_register_data(vexpress_sysreg_dev, "leds-gpio", PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata, sizeof(vexpress_sysreg_leds_pdata)); +#endif device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);