Backend-independent videomode. At the moment this is not very different from fb_mode or drm_mode. It is supposed to be a generic description of videomodes and conversion step to the desired backend video mode representation. At the moment, only really makes sense when used with of_display Signed-off-by: Steffen Trumtrar <s.trumtrar@xxxxxxxxxxxxxx> --- drivers/video/Makefile | 1 + drivers/video/videomode.c | 146 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/videomode.h | 38 ++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 drivers/video/videomode.c create mode 100644 include/linux/videomode.h diff --git a/drivers/video/Makefile b/drivers/video/Makefile index ee8dafb..6a02fe0 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -170,3 +170,4 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o #video output switch sysfs driver obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o +obj-y += videomode.o diff --git a/drivers/video/videomode.c b/drivers/video/videomode.c new file mode 100644 index 0000000..b118d00 --- /dev/null +++ b/drivers/video/videomode.c @@ -0,0 +1,146 @@ +/* + * generic videomode helper + * + * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@xxxxxxxxxxxxxx>, Pengutronix + * + * This file is released under the GPLv2 + */ +#include <linux/of.h> +#include <linux/fb.h> +#include <linux/slab.h> +#include <drm/drm_mode.h> +#include <linux/display.h> +#include <linux/videomode.h> + +struct videomode *videomode_from_display(struct display *disp, int index) +{ + struct videomode *vm; + struct signal_timing *st; + + vm = kmalloc(sizeof(struct videomode *), GFP_KERNEL); + + if (!vm) + return NULL; + + st = display_get_timing(disp, index); + + vm->pixelclock = signal_timing_get_value(&st->pixelclock, 0); + vm->hactive = signal_timing_get_value(&st->hactive, 0); + vm->hfront_porch = signal_timing_get_value(&st->hfront_porch, 0); + vm->hback_porch = signal_timing_get_value(&st->hback_porch, 0); + vm->hsync_len = signal_timing_get_value(&st->hsync_len, 0); + + vm->vactive = signal_timing_get_value(&st->vactive, 0); + vm->vfront_porch = signal_timing_get_value(&st->vfront_porch, 0); + vm->vback_porch = signal_timing_get_value(&st->vback_porch, 0); + vm->vsync_len = signal_timing_get_value(&st->vsync_len, 0); + + vm->vah = disp->vsync_pol_active_high; + vm->hah = disp->hsync_pol_active_high; + + return vm; +} + +#if defined(CONFIG_DRM) +int videomode_to_display_mode(struct videomode *vm, struct drm_display_mode *dmode) +{ + memset(dmode, 0, sizeof(*dmode)); + + dmode->hdisplay = vm->hactive; + dmode->hsync_start = dmode->hdisplay + vm->hfront_porch; + dmode->hsync_end = dmode->hsync_start + vm->hsync_len; + dmode->htotal = dmode->hsync_end + vm->hback_porch; + + dmode->vdisplay = vm->vactive; + dmode->vsync_start = dmode->vdisplay + vm->vfront_porch; + dmode->vsync_end = dmode->vsync_start + vm->vsync_len; + dmode->vtotal = dmode->vtotal + vm->vback_porch; + + dmode->clock = vm->pixelclock / 1000; + + if (vm->hah) + dmode->flags |= DRM_MODE_FLAG_PHSYNC; + else + dmode->flags |= DRM_MODE_FLAG_NHSYNC; + if (vm->vah) + dmode->flags |= DRM_MODE_FLAG_PVSYNC; + else + dmode->flags |= DRM_MODE_FLAG_NVSYNC; + if (vm->interlaced) + dmode->flags |= DRM_MODE_FLAG_INTERLACE; + if (vm->doublescan) + dmode->flags |= DRM_MODE_FLAG_DBLSCAN; + drm_mode_set_name(dmode); + + return 0; +} +EXPORT_SYMBOL_GPL(videomode_to_display_mode); +#else +int videomode_to_displaymode(struct videomode *vm, struct drm_display_mode *dmode) +{ + return 0; +} +#endif + +int videomode_to_fb_videomode(struct videomode *vm, struct fb_videomode *fbmode) +{ + memset(fbmode, 0, sizeof(*fbmode)); + + fbmode->xres = vm->hactive; + fbmode->left_margin = vm->hback_porch; + fbmode->right_margin = vm->hfront_porch; + fbmode->hsync_len = vm->hsync_len; + + fbmode->yres = vm->vactive; + fbmode->upper_margin = vm->vback_porch; + fbmode->lower_margin = vm->vfront_porch; + fbmode->vsync_len = vm->vsync_len; + + fbmode->pixclock = KHZ2PICOS(vm->pixelclock) / 1000; + + if (vm->hah) + fbmode->sync |= FB_SYNC_HOR_HIGH_ACT; + if (vm->vah) + fbmode->sync |= FB_SYNC_VERT_HIGH_ACT; + if (vm->interlaced) + fbmode->vmode |= FB_VMODE_INTERLACED; + if (vm->doublescan) + fbmode->vmode |= FB_VMODE_DOUBLE; + + return 0; +} +EXPORT_SYMBOL_GPL(videomode_to_fb_videomode); + +int of_get_display_mode(struct device_node *np, struct drm_display_mode *dmode, int index) +{ + struct videomode *vm; + struct display *disp; + + disp = of_get_display(np); + + if (!disp) { + pr_err("%s: no display specified\n", __func__); + return -EINVAL; + } + + if (index == OF_DEFAULT_TIMING) + index = disp->default_timing; + + vm = videomode_from_display(disp, index); + + if (!vm) { + pr_err("%s: could not get videomode %d\n", __func__, index); + return -EINVAL; + } + + videomode_to_display_mode(vm, dmode); + + pr_info("%s: got %dx%d display mode from %s\n", __func__, vm->hactive, vm->vactive, np->name); + + display_release(disp); + kfree(vm); + + return 0; + +} +EXPORT_SYMBOL_GPL(of_get_display_mode); diff --git a/include/linux/videomode.h b/include/linux/videomode.h new file mode 100644 index 0000000..100c88b --- /dev/null +++ b/include/linux/videomode.h @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Steffen Trumtrar <s.trumtrar@xxxxxxxxxxxxxx> + * + * generic videomode description + * + * This file is released under the GPLv2 + */ + +#ifndef __LINUX_VIDEOMODE_H +#define __LINUX_VIDEOMODE_H + +#include <drm/drmP.h> + +struct videomode { + u32 pixelclock; + u32 refreshrate; + + u32 hactive; + u32 hfront_porch; + u32 hback_porch; + u32 hsync_len; + + u32 vactive; + u32 vfront_porch; + u32 vback_porch; + u32 vsync_len; + + bool hah; + bool vah; + bool interlaced; + bool doublescan; + +}; + +int videomode_to_display_mode(struct videomode *vm, struct drm_display_mode *dmode); +int videomode_to_fb_videomode(struct videomode *vm, struct fb_videomode *fbmode); +int of_get_display_mode(struct device_node *np, struct drm_display_mode *dmode, int index); +#endif /* __LINUX_VIDEOMODE_H */ -- 1.7.10.4 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel