Optional helper which implements some ADF interface ops for displays using the Display Core framework Signed-off-by: Greg Hackmann <ghackmann@xxxxxxxxxx> --- drivers/video/adf/Kconfig | 5 ++ drivers/video/adf/Makefile | 2 + drivers/video/adf/adf.c | 28 ++++++++- drivers/video/adf/adf.h | 1 + drivers/video/adf/adf_display.c | 123 ++++++++++++++++++++++++++++++++++++++++ include/video/adf_display.h | 31 ++++++++++ 6 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 drivers/video/adf/adf_display.c create mode 100644 include/video/adf_display.h diff --git a/drivers/video/adf/Kconfig b/drivers/video/adf/Kconfig index 0b64408..30b0611 100644 --- a/drivers/video/adf/Kconfig +++ b/drivers/video/adf/Kconfig @@ -3,3 +3,8 @@ menuconfig ADF depends on SW_SYNC depends on DMA_SHARED_BUFFER tristate "Atomic Display Framework" + +menuconfig ADF_DISPLAY_CORE + depends on ADF + depends on DISPLAY_CORE + tristate "Helper for implementing ADF interface ops with Display Core devices" diff --git a/drivers/video/adf/Makefile b/drivers/video/adf/Makefile index 2af5f79..30164ee 100644 --- a/drivers/video/adf/Makefile +++ b/drivers/video/adf/Makefile @@ -8,3 +8,5 @@ obj-$(CONFIG_ADF) += adf.o \ adf_sysfs.o obj-$(CONFIG_COMPAT) += adf_fops32.o + +obj-$(CONFIG_ADF_DISPLAY_CORE) += adf_display.o diff --git a/drivers/video/adf/adf.c b/drivers/video/adf/adf.c index 5dc04af..b3b57dd 100644 --- a/drivers/video/adf/adf.c +++ b/drivers/video/adf/adf.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2013 Google, Inc. - * adf_modeinfo_set_name modified from drm_mode_set_name in + * adf_modeinfo_{set_name,set_vrefresh} modified from * drivers/gpu/drm/drm_modes.c * * This software is licensed under the terms of the GNU General Public @@ -966,6 +966,32 @@ void adf_modeinfo_set_name(struct drm_mode_modeinfo *mode) interlaced ? "i" : ""); } +void adf_modeinfo_set_vrefresh(struct drm_mode_modeinfo *mode) +{ + int refresh = 0; + unsigned int calc_val; + + if (mode->vrefresh > 0) + return; + else if (mode->htotal > 0 && mode->vtotal > 0) { + int vtotal; + vtotal = mode->vtotal; + /* work out vrefresh the value will be x1000 */ + calc_val = (mode->clock * 1000); + calc_val /= mode->htotal; + refresh = (calc_val + vtotal / 2) / vtotal; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + refresh *= 2; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + refresh /= 2; + if (mode->vscan > 1) + refresh /= mode->vscan; + + mode->vrefresh = refresh; + } +} + static void __exit adf_exit(void); static int __init adf_init(void) { diff --git a/drivers/video/adf/adf.h b/drivers/video/adf/adf.h index acad631..5f7260d 100644 --- a/drivers/video/adf/adf.h +++ b/drivers/video/adf/adf.h @@ -44,5 +44,6 @@ struct adf_event_refcount *adf_obj_find_refcount(struct adf_obj *obj, enum adf_event_type type); void adf_modeinfo_set_name(struct drm_mode_modeinfo *mode); +void adf_modeinfo_set_vrefresh(struct drm_mode_modeinfo *mode); #endif /* __ADF_H */ diff --git a/drivers/video/adf/adf_display.c b/drivers/video/adf/adf_display.c new file mode 100644 index 0000000..c87f6a5 --- /dev/null +++ b/drivers/video/adf/adf_display.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2013 Google, Inc. + * adf_modeinfo_from_videomode modified from drm_display_mode_from_videomode in + * drivers/gpu/drm/drm_modes.c + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/slab.h> +#include <video/adf.h> +#include <video/adf_display.h> + +#include "adf.h" + +/** + * adf_display_entity_screen_size - handle the screen_size interface op + * by querying a display core entity + */ +int adf_display_entity_screen_size(struct display_entity *display, + u16 *width_mm, u16 *height_mm) +{ + unsigned int cdf_width, cdf_height; + int ret; + + ret = display_entity_get_size(display, &cdf_width, &cdf_height); + if (!ret) { + *width_mm = cdf_width; + *height_mm = cdf_height; + } + return ret; +} +EXPORT_SYMBOL(adf_display_entity_screen_size); + +/** + * adf_display_entity_notify_connected - notify ADF of a display core entity + * being connected to an interface + * + * @intf: the interface + * @display: the display + * + * adf_display_entity_notify_connected() wraps adf_hotplug_notify_connected() + * but does not require a hardware modelist. @display is queried to + * automatically populate the modelist. + * + * Returns 0 on success or error code (<0) on failure. + */ +int adf_display_entity_notify_connected(struct adf_interface *intf, + struct display_entity *display) +{ + const struct videomode *vmodes; + struct drm_mode_modeinfo *dmodes = NULL; + int ret; + size_t i, n_modes; + + ret = display_entity_get_modes(display, &vmodes); + if (ret < 0) + return ret; + + n_modes = ret; + if (n_modes) { + dmodes = kzalloc(n_modes * sizeof(dmodes[0]), GFP_KERNEL); + if (!dmodes) + return -ENOMEM; + } + + for (i = 0; i < n_modes; i++) + adf_modeinfo_from_videomode(&vmodes[i], &dmodes[i]); + + ret = adf_hotplug_notify_connected(intf, dmodes, n_modes); + kfree(dmodes); + return ret; +} +EXPORT_SYMBOL(adf_display_entity_notify_connected); + +/** + * adf_modeinfo_from_videomode - copy a display core videomode into + * an equivalent &struct drm_mode_modeinfo + * + * @vm: the input display core videomode + * @dmode: the output DRM/ADF modeinfo + */ +void adf_modeinfo_from_videomode(const struct videomode *vm, + struct drm_mode_modeinfo *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->vsync_end + vm->vback_porch; + + dmode->clock = vm->pixelclock / 1000; + + if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH) + dmode->flags |= DRM_MODE_FLAG_PHSYNC; + else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW) + dmode->flags |= DRM_MODE_FLAG_NHSYNC; + if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH) + dmode->flags |= DRM_MODE_FLAG_PVSYNC; + else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW) + dmode->flags |= DRM_MODE_FLAG_NVSYNC; + if (vm->flags & DISPLAY_FLAGS_INTERLACED) + dmode->flags |= DRM_MODE_FLAG_INTERLACE; + if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN) + dmode->flags |= DRM_MODE_FLAG_DBLSCAN; + + adf_modeinfo_set_name(dmode); + adf_modeinfo_set_vrefresh(dmode); +} +EXPORT_SYMBOL_GPL(adf_modeinfo_from_videomode); diff --git a/include/video/adf_display.h b/include/video/adf_display.h new file mode 100644 index 0000000..af8cb6b --- /dev/null +++ b/include/video/adf_display.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _VIDEO_ADF_DISPLAY_H +#define _VIDEO_ADF_DISPLAY_H + +#include <video/adf.h> +#include <video/display.h> +#include <video/videomode.h> + +int adf_display_entity_screen_size(struct display_entity *display, + u16 *width_mm, u16 *height_mm); + +int adf_display_entity_notify_connected(struct adf_interface *intf, + struct display_entity *display); + +void adf_modeinfo_from_videomode(const struct videomode *vm, + struct drm_mode_modeinfo *dmode); + +#endif /* _VIDEO_ADF_DISPLAY_H */ -- 1.8.0 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel