From f041b257a8997c8472a1013e9f252c3e2a1d879e Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Thu, 30 Jan 2014 16:19:15 -0500 Subject: [PATCH] drm/exynos: Remove exynos_drm_hdmi shim This patch trims exynos_drm_hdmi out of the driver. The reason it existed in the first place was to make up for the mixture of display/overlay/manager ops being spread across hdmi and mixer. With that code now rationalized, mixer and hdmi map directly to exynos_drm_crtc and exynos_drm_encoder, respectively. Since there is a 1:1 mapping, we no longer need this layer. Signed-off-by: Sean Paul Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/Makefile | 3 +- drivers/gpu/drm/exynos/exynos_drm_drv.c | 13 - drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 416 ----------------------- drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 69 ---- drivers/gpu/drm/exynos/exynos_hdmi.c | 162 +++++---- drivers/gpu/drm/exynos/exynos_mixer.c | 192 +++++------ drivers/gpu/drm/exynos/exynos_mixer.h | 20 ++ 7 files changed, 217 insertions(+), 658 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.c delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.h create mode 100644 drivers/gpu/drm/exynos/exynos_mixer.h diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index 819961a3858c..afbe49954451 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -11,8 +11,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \ exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o -exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \ - exynos_drm_hdmi.o +exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 57a19a8c6a59..d55012594cd9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -370,13 +370,6 @@ static int __init exynos_drm_init(void) ret = platform_driver_register(&mixer_driver); if (ret < 0) goto out_mixer; - ret = platform_driver_register(&exynos_drm_common_hdmi_driver); - if (ret < 0) - goto out_common_hdmi; - - ret = exynos_platform_device_hdmi_register(); - if (ret < 0) - goto out_common_hdmi_dev; #endif #ifdef CONFIG_DRM_EXYNOS_VIDI @@ -469,10 +462,6 @@ static int __init exynos_drm_init(void) #endif #ifdef CONFIG_DRM_EXYNOS_HDMI - exynos_platform_device_hdmi_unregister(); -out_common_hdmi_dev: - platform_driver_unregister(&exynos_drm_common_hdmi_driver); -out_common_hdmi: platform_driver_unregister(&mixer_driver); out_mixer: platform_driver_unregister(&hdmi_driver); @@ -514,8 +503,6 @@ static void __exit exynos_drm_exit(void) #endif #ifdef CONFIG_DRM_EXYNOS_HDMI - exynos_platform_device_hdmi_unregister(); - platform_driver_unregister(&exynos_drm_common_hdmi_driver); platform_driver_unregister(&mixer_driver); platform_driver_unregister(&hdmi_driver); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c deleted file mode 100644 index b0b09b298ac3..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright (C) 2011 Samsung Electronics Co.Ltd - * Authors: - * Inki Dae - * Seung-Woo Kim - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include - -#include -#include -#include -#include - -#include - -#include "exynos_drm_drv.h" -#include "exynos_drm_hdmi.h" - -/* platform device pointer for common drm hdmi device. */ -static struct platform_device *exynos_drm_hdmi_pdev; - -/* Common hdmi subdrv needs to access the hdmi and mixer though context. -* These should be initialied by the repective drivers */ -static struct exynos_drm_hdmi_context *hdmi_ctx; -static struct exynos_drm_hdmi_context *mixer_ctx; - -/* these callback points shoud be set by specific drivers. */ -static struct exynos_hdmi_ops *hdmi_ops; -static struct exynos_mixer_ops *mixer_ops; - -struct drm_hdmi_context { - struct exynos_drm_hdmi_context *hdmi_ctx; - struct exynos_drm_hdmi_context *mixer_ctx; - - bool enabled[MIXER_WIN_NR]; -}; - -int exynos_platform_device_hdmi_register(void) -{ - struct platform_device *pdev; - - if (exynos_drm_hdmi_pdev) - return -EEXIST; - - pdev = platform_device_register_simple( - "exynos-drm-hdmi", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - exynos_drm_hdmi_pdev = pdev; - - return 0; -} - -void exynos_platform_device_hdmi_unregister(void) -{ - if (exynos_drm_hdmi_pdev) { - platform_device_unregister(exynos_drm_hdmi_pdev); - exynos_drm_hdmi_pdev = NULL; - } -} - -void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx) -{ - if (ctx) - hdmi_ctx = ctx; -} - -void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx) -{ - if (ctx) - mixer_ctx = ctx; -} - -void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops) -{ - if (ops) - hdmi_ops = ops; -} - -void exynos_mixer_ops_register(struct exynos_mixer_ops *ops) -{ - if (ops) - mixer_ops = ops; -} - -static int drm_hdmi_display_initialize(struct exynos_drm_display *display, - struct drm_device *drm_dev) -{ - struct drm_hdmi_context *ctx = display->ctx; - - if (hdmi_ops && hdmi_ops->initialize) - return hdmi_ops->initialize(ctx->hdmi_ctx->ctx, drm_dev); - - return 0; -} - - -static bool drm_hdmi_is_connected(struct exynos_drm_display *display) -{ - struct drm_hdmi_context *ctx = display->ctx; - - if (hdmi_ops && hdmi_ops->is_connected) - return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx); - - return false; -} - -static struct edid *drm_hdmi_get_edid(struct exynos_drm_display *display, - struct drm_connector *connector) -{ - struct drm_hdmi_context *ctx = display->ctx; - - if (hdmi_ops && hdmi_ops->get_edid) - return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector); - - return NULL; -} -static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx, - struct drm_display_mode *mode) -{ - int ret = 0; - - /* - * Both, mixer and hdmi should be able to handle the requested mode. - * If any of the two fails, return mode as BAD. - */ - - if (mixer_ops && mixer_ops->check_mode) - ret = mixer_ops->check_mode(ctx->mixer_ctx->ctx, mode); - - if (ret) - return ret; - - if (hdmi_ops && hdmi_ops->check_mode) - return hdmi_ops->check_mode(ctx->hdmi_ctx->ctx, mode); - - return 0; -} - -static int drm_hdmi_check_mode(struct exynos_drm_display *display, - struct drm_display_mode *mode) -{ - struct drm_hdmi_context *ctx = display->ctx; - - return drm_hdmi_check_mode_ctx(ctx, mode); -} - -static void drm_hdmi_display_dpms(struct exynos_drm_display *display, int mode) -{ - struct drm_hdmi_context *ctx = display->ctx; - - if (hdmi_ops && hdmi_ops->dpms) - hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode); -} - -static void drm_hdmi_mode_fixup(struct exynos_drm_display *display, - struct drm_connector *connector, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct drm_hdmi_context *ctx = display->ctx; - struct drm_display_mode *m; - int mode_ok; - - drm_mode_set_crtcinfo(adjusted_mode, 0); - - mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode); - - /* just return if user desired mode exists. */ - if (mode_ok == 0) - return; - - /* - * otherwise, find the most suitable mode among modes and change it - * to adjusted_mode. - */ - list_for_each_entry(m, &connector->modes, head) { - mode_ok = drm_hdmi_check_mode_ctx(ctx, m); - - if (mode_ok == 0) { - struct drm_mode_object base; - struct list_head head; - - DRM_INFO("desired mode doesn't exist so\n"); - DRM_INFO("use the most suitable mode among modes.\n"); - - DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n", - m->hdisplay, m->vdisplay, m->vrefresh); - - /* preserve display mode header while copying. */ - head = adjusted_mode->head; - base = adjusted_mode->base; - memcpy(adjusted_mode, m, sizeof(*m)); - adjusted_mode->head = head; - adjusted_mode->base = base; - break; - } - } -} - -static void drm_hdmi_mode_set(struct exynos_drm_display *display, - struct drm_display_mode *mode) -{ - struct drm_hdmi_context *ctx = display->ctx; - - if (hdmi_ops && hdmi_ops->mode_set) - hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode); -} - -static void drm_hdmi_get_max_resol(struct exynos_drm_display *display, - unsigned int *width, unsigned int *height) -{ - struct drm_hdmi_context *ctx = display->ctx; - - if (hdmi_ops && hdmi_ops->get_max_resol) - hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height); -} - -static struct exynos_drm_display_ops drm_hdmi_display_ops = { - .initialize = drm_hdmi_display_initialize, - .is_connected = drm_hdmi_is_connected, - .get_edid = drm_hdmi_get_edid, - .check_mode = drm_hdmi_check_mode, - .dpms = drm_hdmi_display_dpms, - .mode_fixup = drm_hdmi_mode_fixup, - .mode_set = drm_hdmi_mode_set, - .get_max_resol = drm_hdmi_get_max_resol, -}; - -static struct exynos_drm_display hdmi_display = { - .type = EXYNOS_DISPLAY_TYPE_HDMI, - .ops = &drm_hdmi_display_ops, -}; - -static int drm_hdmi_enable_vblank(struct exynos_drm_manager *mgr) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - - if (mixer_ops && mixer_ops->enable_vblank) - return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx, mgr->pipe); - - return 0; -} - -static void drm_hdmi_disable_vblank(struct exynos_drm_manager *mgr) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - - if (mixer_ops && mixer_ops->disable_vblank) - return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx); -} - -static void drm_hdmi_wait_for_vblank(struct exynos_drm_manager *mgr) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - - if (mixer_ops && mixer_ops->wait_for_vblank) - mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx); -} - -static void drm_hdmi_commit(struct exynos_drm_manager *mgr) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - - if (hdmi_ops && hdmi_ops->commit) - hdmi_ops->commit(ctx->hdmi_ctx->ctx); -} - -static int drm_hdmi_mgr_initialize(struct exynos_drm_manager *mgr, - struct drm_device *drm_dev, int pipe) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - int ret = 0; - - if (!hdmi_ctx) { - DRM_ERROR("hdmi context not initialized.\n"); - return -EFAULT; - } - - if (!mixer_ctx) { - DRM_ERROR("mixer context not initialized.\n"); - return -EFAULT; - } - - ctx->hdmi_ctx = hdmi_ctx; - ctx->mixer_ctx = mixer_ctx; - - if (mixer_ops && mixer_ops->initialize) - ret = mixer_ops->initialize(ctx->mixer_ctx->ctx, drm_dev); - - if (mixer_ops->iommu_on) - mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true); - - return ret; -} - -static void drm_hdmi_mgr_remove(struct exynos_drm_manager *mgr) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - - if (mixer_ops->iommu_on) - mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false); -} - -static void drm_hdmi_dpms(struct exynos_drm_manager *mgr, int mode) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - - if (mixer_ops && mixer_ops->dpms) - mixer_ops->dpms(ctx->mixer_ctx->ctx, mode); - - if (hdmi_ops && hdmi_ops->dpms) - hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode); -} - -static void drm_mixer_win_mode_set(struct exynos_drm_manager *mgr, - struct exynos_drm_overlay *overlay) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - - if (mixer_ops && mixer_ops->win_mode_set) - mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay); -} - -static void drm_mixer_win_commit(struct exynos_drm_manager *mgr, int zpos) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos; - - if (win < 0 || win >= MIXER_WIN_NR) { - DRM_ERROR("mixer window[%d] is wrong\n", win); - return; - } - - if (mixer_ops && mixer_ops->win_commit) - mixer_ops->win_commit(ctx->mixer_ctx->ctx, win); - - ctx->enabled[win] = true; -} - -static void drm_mixer_win_disable(struct exynos_drm_manager *mgr, int zpos) -{ - struct drm_hdmi_context *ctx = mgr->ctx; - int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos; - - if (win < 0 || win >= MIXER_WIN_NR) { - DRM_ERROR("mixer window[%d] is wrong\n", win); - return; - } - - if (mixer_ops && mixer_ops->win_disable) - mixer_ops->win_disable(ctx->mixer_ctx->ctx, win); - - ctx->enabled[win] = false; -} - -static struct exynos_drm_manager_ops drm_hdmi_manager_ops = { - .initialize = drm_hdmi_mgr_initialize, - .remove = drm_hdmi_mgr_remove, - .dpms = drm_hdmi_dpms, - .enable_vblank = drm_hdmi_enable_vblank, - .disable_vblank = drm_hdmi_disable_vblank, - .wait_for_vblank = drm_hdmi_wait_for_vblank, - .commit = drm_hdmi_commit, - .win_mode_set = drm_mixer_win_mode_set, - .win_commit = drm_mixer_win_commit, - .win_disable = drm_mixer_win_disable, -}; - -static struct exynos_drm_manager hdmi_manager = { - .type = EXYNOS_DISPLAY_TYPE_HDMI, - .ops = &drm_hdmi_manager_ops, -}; - -static int exynos_drm_hdmi_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct drm_hdmi_context *ctx; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - hdmi_manager.ctx = ctx; - hdmi_display.ctx = ctx; - - exynos_drm_manager_register(&hdmi_manager); - exynos_drm_display_register(&hdmi_display); - - return 0; -} - -static int exynos_drm_hdmi_remove(struct platform_device *pdev) -{ - exynos_drm_display_unregister(&hdmi_display); - exynos_drm_manager_unregister(&hdmi_manager); - - return 0; -} - -struct platform_driver exynos_drm_common_hdmi_driver = { - .probe = exynos_drm_hdmi_probe, - .remove = exynos_drm_hdmi_remove, - .driver = { - .name = "exynos-drm-hdmi", - .owner = THIS_MODULE, - }, -}; diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h deleted file mode 100644 index 37059ea4f33d..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h +++ /dev/null @@ -1,69 +0,0 @@ -/* exynos_drm_hdmi.h - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * Authoer: Inki Dae - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef _EXYNOS_DRM_HDMI_H_ -#define _EXYNOS_DRM_HDMI_H_ - -#define MIXER_WIN_NR 3 -#define MIXER_DEFAULT_WIN 0 - -/* - * exynos hdmi common context structure. - * - * @drm_dev: pointer to drm_device. - * @pipe: pipe for mixer - * @ctx: pointer to the context of specific device driver. - * this context should be hdmi_context or mixer_context. - */ -struct exynos_drm_hdmi_context { - int pipe; - void *ctx; -}; - -struct exynos_hdmi_ops { - /* display */ - int (*initialize)(void *ctx, struct drm_device *drm_dev); - bool (*is_connected)(void *ctx); - struct edid *(*get_edid)(void *ctx, - struct drm_connector *connector); - int (*check_mode)(void *ctx, struct drm_display_mode *mode); - void (*dpms)(void *ctx, int mode); - - /* manager */ - void (*mode_set)(void *ctx, struct drm_display_mode *mode); - void (*get_max_resol)(void *ctx, unsigned int *width, - unsigned int *height); - void (*commit)(void *ctx); -}; - -struct exynos_mixer_ops { - /* manager */ - int (*initialize)(void *ctx, struct drm_device *drm_dev); - int (*iommu_on)(void *ctx, bool enable); - int (*enable_vblank)(void *ctx, int pipe); - void (*disable_vblank)(void *ctx); - void (*wait_for_vblank)(void *ctx); - void (*dpms)(void *ctx, int mode); - - /* overlay */ - void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay); - void (*win_commit)(void *ctx, int zpos); - void (*win_disable)(void *ctx, int zpos); - - /* display */ - int (*check_mode)(void *ctx, struct drm_display_mode *mode); -}; - -void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx); -void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx); -void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops); -void exynos_mixer_ops_register(struct exynos_mixer_ops *ops); -#endif diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index b0c58e4fdc56..cc02e91848b5 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -40,14 +40,14 @@ #include #include "exynos_drm_drv.h" -#include "exynos_drm_hdmi.h" +#include "exynos_mixer.h" #include #include #define MAX_WIDTH 1920 #define MAX_HEIGHT 1080 -#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) +#define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev)) /* AVI header and aspect ratio */ #define HDMI_AVI_VERSION 0x02 @@ -178,7 +178,6 @@ struct hdmi_context { struct mutex hdmi_mutex; void __iomem *regs; - void *parent_ctx; int irq; struct i2c_client *ddc_port; @@ -791,26 +790,28 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, } } -static int hdmi_initialize(void *ctx, struct drm_device *drm_dev) +static int hdmi_initialize(struct exynos_drm_display *display, + struct drm_device *drm_dev) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = display->ctx; hdata->drm_dev = drm_dev; return 0; } -static bool hdmi_is_connected(void *ctx) +static bool hdmi_is_connected(struct exynos_drm_display *display) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = display->ctx; return hdata->hpd; } -static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector) +static struct edid *hdmi_get_edid(struct exynos_drm_display *display, + struct drm_connector *connector) { struct edid *raw_edid; - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = display->ctx; if (!hdata->ddc_port) return ERR_PTR(-ENODEV); @@ -849,9 +850,10 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) return -EINVAL; } -static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode) +static int hdmi_check_mode(struct exynos_drm_display *display, + struct drm_display_mode *mode) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = display->ctx; int ret; DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n", @@ -859,12 +861,62 @@ static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode) (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true : false, mode->clock * 1000); + ret = mixer_check_mode(mode); + if (ret) + return ret; + ret = hdmi_find_phy_conf(hdata, mode->clock * 1000); if (ret < 0) return ret; return 0; } +static void hdmi_mode_fixup(struct exynos_drm_display *display, + struct drm_connector *connector, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_display_mode *m; + int mode_ok; + + DRM_DEBUG_KMS("%s\n", __FILE__); + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + mode_ok = hdmi_check_mode(display, adjusted_mode); + + /* just return if user desired mode exists. */ + if (mode_ok == 0) + return; + + /* + * otherwise, find the most suitable mode among modes and change it + * to adjusted_mode. + */ + list_for_each_entry(m, &connector->modes, head) { + mode_ok = hdmi_check_mode(display, m); + + if (mode_ok == 0) { + struct drm_mode_object base; + struct list_head head; + + DRM_INFO("desired mode doesn't exist so\n"); + DRM_INFO("use the most suitable mode among modes.\n"); + + DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n", + m->hdisplay, m->vdisplay, m->vrefresh); + + /* preserve display mode header while copying. */ + head = adjusted_mode->head; + base = adjusted_mode->base; + memcpy(adjusted_mode, m, sizeof(*m)); + adjusted_mode->head = head; + adjusted_mode->base = base; + break; + } + } +} + static void hdmi_set_acr(u32 freq, u8 *acr) { u32 n, cts; @@ -1692,9 +1744,10 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata, hdmi_set_reg(tg->tg_3d, 1, 0x0); } -static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode) +static void hdmi_mode_set(struct exynos_drm_display *display, + struct drm_display_mode *mode) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = display->ctx; struct drm_display_mode *m = mode; DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n", @@ -1708,16 +1761,16 @@ static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode) hdmi_v14_mode_set(hdata, mode); } -static void hdmi_get_max_resol(void *ctx, unsigned int *width, - unsigned int *height) +static void hdmi_get_max_resol(struct exynos_drm_display *display, + unsigned int *width, unsigned int *height) { *width = MAX_WIDTH; *height = MAX_HEIGHT; } -static void hdmi_commit(void *ctx) +static void hdmi_commit(struct exynos_drm_display *display) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = display->ctx; mutex_lock(&hdata->hdmi_mutex); if (!hdata->powered) { @@ -1729,8 +1782,9 @@ static void hdmi_commit(void *ctx) hdmi_conf_apply(hdata); } -static void hdmi_poweron(struct hdmi_context *hdata) +static void hdmi_poweron(struct exynos_drm_display *display) { + struct hdmi_context *hdata = display->ctx; struct hdmi_resources *res = &hdata->res; mutex_lock(&hdata->hdmi_mutex); @@ -1751,11 +1805,12 @@ static void hdmi_poweron(struct hdmi_context *hdata) clk_prepare_enable(res->sclk_hdmi); hdmiphy_poweron(hdata); - hdmi_commit(hdata); + hdmi_commit(display); } -static void hdmi_poweroff(struct hdmi_context *hdata) +static void hdmi_poweroff(struct exynos_drm_display *display) { + struct hdmi_context *hdata = display->ctx; struct hdmi_resources *res = &hdata->res; mutex_lock(&hdata->hdmi_mutex); @@ -1783,9 +1838,9 @@ static void hdmi_poweroff(struct hdmi_context *hdata) mutex_unlock(&hdata->hdmi_mutex); } -static void hdmi_dpms(void *ctx, int mode) +static void hdmi_dpms(struct exynos_drm_display *display, int mode) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = display->ctx; DRM_DEBUG_KMS("mode %d\n", mode); @@ -1806,24 +1861,26 @@ static void hdmi_dpms(void *ctx, int mode) } } -static struct exynos_hdmi_ops hdmi_ops = { - /* display */ +static struct exynos_drm_display_ops hdmi_display_ops = { .initialize = hdmi_initialize, .is_connected = hdmi_is_connected, + .get_max_resol = hdmi_get_max_resol, .get_edid = hdmi_get_edid, .check_mode = hdmi_check_mode, - .dpms = hdmi_dpms, - - /* manager */ + .mode_fixup = hdmi_mode_fixup, .mode_set = hdmi_mode_set, - .get_max_resol = hdmi_get_max_resol, + .dpms = hdmi_dpms, .commit = hdmi_commit, }; +static struct exynos_drm_display hdmi_display = { + .type = EXYNOS_DISPLAY_TYPE_HDMI, + .ops = &hdmi_display_ops, +}; + static irqreturn_t hdmi_irq_thread(int irq, void *arg) { - struct exynos_drm_hdmi_context *ctx = arg; - struct hdmi_context *hdata = ctx->ctx; + struct hdmi_context *hdata = arg; mutex_lock(&hdata->hdmi_mutex); hdata->hpd = gpio_get_value(hdata->hpd_gpio); @@ -1945,7 +2002,6 @@ static struct of_device_id hdmi_match_types[] = { static int hdmi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct exynos_drm_hdmi_context *drm_hdmi_ctx; struct hdmi_context *hdata; struct s5p_hdmi_platform_data *pdata; struct resource *res; @@ -1960,20 +2016,13 @@ static int hdmi_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL); - if (!drm_hdmi_ctx) - return -ENOMEM; - hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); if (!hdata) return -ENOMEM; mutex_init(&hdata->hdmi_mutex); - drm_hdmi_ctx->ctx = (void *)hdata; - hdata->parent_ctx = (void *)drm_hdmi_ctx; - - platform_set_drvdata(pdev, drm_hdmi_ctx); + platform_set_drvdata(pdev, &hdmi_display); match = of_match_node(hdmi_match_types, dev->of_node); if (!match) @@ -2038,17 +2087,14 @@ static int hdmi_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(dev, hdata->irq, NULL, hdmi_irq_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "hdmi", drm_hdmi_ctx); + "hdmi", hdata); if (ret) { DRM_ERROR("failed to register hdmi interrupt\n"); goto err_hdmiphy; } - /* Attach HDMI Driver to common hdmi. */ - exynos_hdmi_drv_attach(drm_hdmi_ctx); - - /* register specific callbacks to common hdmi. */ - exynos_hdmi_ops_register(&hdmi_ops); + hdmi_display.ctx = hdata; + exynos_drm_display_register(&hdmi_display); pm_runtime_enable(dev); @@ -2064,8 +2110,8 @@ static int hdmi_probe(struct platform_device *pdev) static int hdmi_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev); - struct hdmi_context *hdata = ctx->ctx; + struct exynos_drm_display *display = get_hdmi_display(dev); + struct hdmi_context *hdata = display->ctx; pm_runtime_disable(dev); @@ -2078,8 +2124,8 @@ static int hdmi_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int hdmi_suspend(struct device *dev) { - struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev); - struct hdmi_context *hdata = ctx->ctx; + struct exynos_drm_display *display = get_hdmi_display(dev); + struct hdmi_context *hdata = display->ctx; disable_irq(hdata->irq); @@ -2092,15 +2138,15 @@ static int hdmi_suspend(struct device *dev) return 0; } - hdmi_poweroff(hdata); + hdmi_poweroff(display); return 0; } static int hdmi_resume(struct device *dev) { - struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev); - struct hdmi_context *hdata = ctx->ctx; + struct exynos_drm_display *display = get_hdmi_display(dev); + struct hdmi_context *hdata = display->ctx; hdata->hpd = gpio_get_value(hdata->hpd_gpio); @@ -2111,7 +2157,7 @@ static int hdmi_resume(struct device *dev) return 0; } - hdmi_poweron(hdata); + hdmi_poweron(display); return 0; } @@ -2120,20 +2166,18 @@ static int hdmi_resume(struct device *dev) #ifdef CONFIG_PM_RUNTIME static int hdmi_runtime_suspend(struct device *dev) { - struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev); - struct hdmi_context *hdata = ctx->ctx; + struct exynos_drm_display *display = get_hdmi_display(dev); - hdmi_poweroff(hdata); + hdmi_poweroff(display); return 0; } static int hdmi_runtime_resume(struct device *dev) { - struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev); - struct hdmi_context *hdata = ctx->ctx; + struct exynos_drm_display *display = get_hdmi_display(dev); - hdmi_poweron(hdata); + hdmi_poweron(display); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 25a440a375fb..d5228577cabb 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -36,10 +36,13 @@ #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" -#include "exynos_drm_hdmi.h" #include "exynos_drm_iommu.h" +#include "exynos_mixer.h" -#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) +#define get_mixer_manager(dev) platform_get_drvdata(to_platform_device(dev)) + +#define MIXER_WIN_NR 3 +#define MIXER_DEFAULT_WIN 0 struct hdmi_win_data { dma_addr_t dma_addr; @@ -95,7 +98,6 @@ struct mixer_context { struct mixer_resources mixer_res; struct hdmi_win_data win_data[MIXER_WIN_NR]; enum mixer_version_id mxr_ver; - void *parent_ctx; wait_queue_head_t wait_vsync_queue; atomic_t wait_vsync_event; }; @@ -827,12 +829,14 @@ static int vp_resources_init(struct mixer_context *mixer_ctx) return 0; } -static int mixer_initialize(void *ctx, struct drm_device *drm_dev) +static int mixer_initialize(struct exynos_drm_manager *mgr, + struct drm_device *drm_dev, int pipe) { int ret; - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; mixer_ctx->drm_dev = drm_dev; + mixer_ctx->pipe = pipe; /* acquire resources: regs, irqs, clocks */ ret = mixer_resources_init(mixer_ctx); @@ -850,29 +854,29 @@ static int mixer_initialize(void *ctx, struct drm_device *drm_dev) } } - return ret; + if (!is_drm_iommu_supported(mixer_ctx->drm_dev)) + return 0; + + return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev); } -static int mixer_iommu_on(void *ctx, bool enable) +static void mixer_mgr_remove(struct exynos_drm_manager *mgr) { - struct mixer_context *mdata = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; - if (is_drm_iommu_supported(mdata->drm_dev)) { - if (enable) - return drm_iommu_attach_device(mdata->drm_dev, - mdata->dev); - - drm_iommu_detach_device(mdata->drm_dev, mdata->dev); - } - return 0; + if (is_drm_iommu_supported(mixer_ctx->drm_dev)) + drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev); } -static int mixer_enable_vblank(void *ctx, int pipe) +static int mixer_enable_vblank(struct exynos_drm_manager *mgr) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; - mixer_ctx->pipe = pipe; + if (!mixer_ctx->powered) { + mixer_ctx->int_en |= MXR_INT_EN_VSYNC; + return 0; + } /* enable vsync interrupt */ mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC, @@ -881,19 +885,19 @@ static int mixer_enable_vblank(void *ctx, int pipe) return 0; } -static void mixer_disable_vblank(void *ctx) +static void mixer_disable_vblank(struct exynos_drm_manager *mgr) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; /* disable vsync interrupt */ mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); } -static void mixer_win_mode_set(void *ctx, - struct exynos_drm_overlay *overlay) +static void mixer_win_mode_set(struct exynos_drm_manager *mgr, + struct exynos_drm_overlay *overlay) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; struct hdmi_win_data *win_data; int win; @@ -942,9 +946,10 @@ static void mixer_win_mode_set(void *ctx, win_data->scan_flags = overlay->scan_flag; } -static void mixer_win_commit(void *ctx, int win) +static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; + int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; DRM_DEBUG_KMS("win: %d\n", win); @@ -963,10 +968,11 @@ static void mixer_win_commit(void *ctx, int win) mixer_ctx->win_data[win].enabled = true; } -static void mixer_win_disable(void *ctx, int win) +static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; + int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; unsigned long flags; DRM_DEBUG_KMS("win: %d\n", win); @@ -990,32 +996,9 @@ static void mixer_win_disable(void *ctx, int win) mixer_ctx->win_data[win].enabled = false; } -static int mixer_check_mode(void *ctx, struct drm_display_mode *mode) -{ - struct mixer_context *mixer_ctx = ctx; - u32 w, h; - - w = mode->hdisplay; - h = mode->vdisplay; - - DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n", - mode->hdisplay, mode->vdisplay, mode->vrefresh, - (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); - - if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16 || - mixer_ctx->mxr_ver == MXR_VER_128_0_0_184) - return 0; - - if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) || - (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) || - (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080)) - return 0; - - return -EINVAL; -} -static void mixer_wait_for_vblank(void *ctx) +static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; mutex_lock(&mixer_ctx->mixer_mutex); if (!mixer_ctx->powered) { @@ -1036,21 +1019,23 @@ static void mixer_wait_for_vblank(void *ctx) DRM_DEBUG_KMS("vblank wait timed out.\n"); } -static void mixer_window_suspend(struct mixer_context *ctx) +static void mixer_window_suspend(struct exynos_drm_manager *mgr) { + struct mixer_context *ctx = mgr->ctx; struct hdmi_win_data *win_data; int i; for (i = 0; i < MIXER_WIN_NR; i++) { win_data = &ctx->win_data[i]; win_data->resume = win_data->enabled; - mixer_win_disable(ctx, i); + mixer_win_disable(mgr, i); } - mixer_wait_for_vblank(ctx); + mixer_wait_for_vblank(mgr); } -static void mixer_window_resume(struct mixer_context *ctx) +static void mixer_window_resume(struct exynos_drm_manager *mgr) { + struct mixer_context *ctx = mgr->ctx; struct hdmi_win_data *win_data; int i; @@ -1059,12 +1044,13 @@ static void mixer_window_resume(struct mixer_context *ctx) win_data->enabled = win_data->resume; win_data->resume = false; if (win_data->enabled) - mixer_win_commit(ctx, i); + mixer_win_commit(mgr, i); } } -static void mixer_poweron(struct mixer_context *ctx) +static void mixer_poweron(struct exynos_drm_manager *mgr) { + struct mixer_context *ctx = mgr->ctx; struct mixer_resources *res = &ctx->mixer_res; mutex_lock(&ctx->mixer_mutex); @@ -1084,11 +1070,12 @@ static void mixer_poweron(struct mixer_context *ctx) mixer_reg_write(res, MXR_INT_EN, ctx->int_en); mixer_win_reset(ctx); - mixer_window_resume(ctx); + mixer_window_resume(mgr); } -static void mixer_poweroff(struct mixer_context *ctx) +static void mixer_poweroff(struct exynos_drm_manager *mgr) { + struct mixer_context *ctx = mgr->ctx; struct mixer_resources *res = &ctx->mixer_res; mutex_lock(&ctx->mixer_mutex); @@ -1096,7 +1083,7 @@ static void mixer_poweroff(struct mixer_context *ctx) goto out; mutex_unlock(&ctx->mixer_mutex); - mixer_window_suspend(ctx); + mixer_window_suspend(mgr); ctx->int_en = mixer_reg_read(res, MXR_INT_EN); @@ -1113,9 +1100,9 @@ static void mixer_poweroff(struct mixer_context *ctx) mutex_unlock(&ctx->mixer_mutex); } -static void mixer_dpms(void *ctx, int mode) +static void mixer_dpms(struct exynos_drm_manager *mgr, int mode) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; switch (mode) { case DRM_MODE_DPMS_ON: @@ -1134,20 +1121,41 @@ static void mixer_dpms(void *ctx, int mode) } } -static struct exynos_mixer_ops mixer_ops = { - /* manager */ +/* Only valid for Mixer version 16.0.33.0 */ +int mixer_check_mode(struct drm_display_mode *mode) +{ + u32 w, h; + + w = mode->hdisplay; + h = mode->vdisplay; + + DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n", + mode->hdisplay, mode->vdisplay, mode->vrefresh, + (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); + + if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) || + (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) || + (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080)) + return 0; + + return -EINVAL; +} + +static struct exynos_drm_manager_ops mixer_manager_ops = { .initialize = mixer_initialize, - .iommu_on = mixer_iommu_on, + .remove = mixer_mgr_remove, + .dpms = mixer_dpms, .enable_vblank = mixer_enable_vblank, .disable_vblank = mixer_disable_vblank, .wait_for_vblank = mixer_wait_for_vblank, - .dpms = mixer_dpms, .win_mode_set = mixer_win_mode_set, .win_commit = mixer_win_commit, .win_disable = mixer_win_disable, +}; - /* display */ - .check_mode = mixer_check_mode, +static struct exynos_drm_manager mixer_manager = { + .type = EXYNOS_DISPLAY_TYPE_HDMI, + .ops = &mixer_manager_ops, }; static struct mixer_drv_data exynos5420_mxr_drv_data = { @@ -1195,20 +1203,16 @@ static struct of_device_id mixer_match_types[] = { static int mixer_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct exynos_drm_hdmi_context *drm_hdmi_ctx; struct mixer_context *ctx; struct mixer_drv_data *drv; dev_info(dev, "probe start\n"); - drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), - GFP_KERNEL); - if (!drm_hdmi_ctx) - return -ENOMEM; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + DRM_ERROR("failed to alloc mixer context.\n"); return -ENOMEM; + } mutex_init(&ctx->mixer_mutex); @@ -1223,20 +1227,14 @@ static int mixer_probe(struct platform_device *pdev) ctx->pdev = pdev; ctx->dev = dev; - ctx->parent_ctx = (void *)drm_hdmi_ctx; - drm_hdmi_ctx->ctx = (void *)ctx; ctx->vp_enabled = drv->is_vp_enabled; ctx->mxr_ver = drv->version; init_waitqueue_head(&ctx->wait_vsync_queue); atomic_set(&ctx->wait_vsync_event, 0); - platform_set_drvdata(pdev, drm_hdmi_ctx); - - /* attach mixer driver to common hdmi. */ - exynos_mixer_drv_attach(drm_hdmi_ctx); - - /* register specific callback point to common hdmi. */ - exynos_mixer_ops_register(&mixer_ops); + mixer_manager.ctx = ctx; + platform_set_drvdata(pdev, &mixer_manager); + exynos_drm_manager_register(&mixer_manager); pm_runtime_enable(dev); @@ -1255,30 +1253,28 @@ static int mixer_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int mixer_suspend(struct device *dev) { - struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); - struct mixer_context *ctx = drm_hdmi_ctx->ctx; + struct exynos_drm_manager *mgr = get_mixer_manager(dev); if (pm_runtime_suspended(dev)) { DRM_DEBUG_KMS("Already suspended\n"); return 0; } - mixer_poweroff(ctx); + mixer_poweroff(mgr); return 0; } static int mixer_resume(struct device *dev) { - struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); - struct mixer_context *ctx = drm_hdmi_ctx->ctx; + struct exynos_drm_manager *mgr = get_mixer_manager(dev); if (!pm_runtime_suspended(dev)) { DRM_DEBUG_KMS("Already resumed\n"); return 0; } - mixer_poweron(ctx); + mixer_poweron(mgr); return 0; } @@ -1287,20 +1283,18 @@ static int mixer_resume(struct device *dev) #ifdef CONFIG_PM_RUNTIME static int mixer_runtime_suspend(struct device *dev) { - struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); - struct mixer_context *ctx = drm_hdmi_ctx->ctx; + struct exynos_drm_manager *mgr = get_mixer_manager(dev); - mixer_poweroff(ctx); + mixer_poweroff(mgr); return 0; } static int mixer_runtime_resume(struct device *dev) { - struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); - struct mixer_context *ctx = drm_hdmi_ctx->ctx; + struct exynos_drm_manager *mgr = get_mixer_manager(dev); - mixer_poweron(ctx); + mixer_poweron(mgr); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h new file mode 100644 index 000000000000..3811e417f0e9 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_mixer.h @@ -0,0 +1,20 @@ +/* + * 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 _EXYNOS_MIXER_H_ +#define _EXYNOS_MIXER_H_ + +/* This function returns 0 if the given timing is valid for the mixer */ +int mixer_check_mode(struct drm_display_mode *mode); + +#endif -- 2.45.2