[PATCH 14/23] drm/exynos: Remove exynos_drm_hdmi shim
Sean Paul
seanpaul at chromium.org
Fri Oct 11 02:30:27 CEST 2013
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 <seanpaul at chromium.org>
---
drivers/gpu/drm/exynos/Makefile | 3 +-
drivers/gpu/drm/exynos/exynos_drm_drv.c | 13 -
drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 433 -------------------------------
drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 69 -----
drivers/gpu/drm/exynos/exynos_hdmi.c | 102 +++++---
drivers/gpu/drm/exynos/exynos_mixer.c | 144 +++++-----
drivers/gpu/drm/exynos/exynos_mixer.h | 20 ++
7 files changed, 156 insertions(+), 628 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 819961a..afbe499 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 250903c..4b265bf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -329,13 +329,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
@@ -428,10 +421,6 @@ out_vidi:
#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);
@@ -473,8 +462,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 8fc9d6d..0000000
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * Authors:
- * Inki Dae <inki.dae at samsung.com>
- * Seung-Woo Kim <sw0312.kim at samsung.com>
- *
- * 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 <drm/drmP.h>
-
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-
-#include <drm/exynos_drm.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
-
-#define to_context(dev) platform_get_drvdata(to_platform_device(dev))
-
-/* platform device pointer for common drm hdmi device. */
-static struct platform_device *exynos_drm_hdmi_pdev;
-
-/* Common hdmi 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(void *in_ctx, struct drm_device *drm_dev)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- if (!hdmi_ctx) {
- DRM_ERROR("hdmi context not initialized.\n");
- return -EINVAL;
- }
- ctx->hdmi_ctx = hdmi_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(void *in_ctx)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- if (hdmi_ops && hdmi_ops->is_connected)
- return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
-
- return false;
-}
-
-static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
- unsigned int *height)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- if (hdmi_ops && hdmi_ops->get_max_resol)
- hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
-}
-
-static struct edid *drm_hdmi_get_edid(void *in_ctx,
- struct drm_connector *connector)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- if (hdmi_ops && hdmi_ops->get_edid)
- return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector);
-
- return NULL;
-}
-
-static void drm_hdmi_mode_set(void *in_ctx, struct drm_display_mode *mode)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- if (hdmi_ops && hdmi_ops->mode_set)
- hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
-}
-
-static int drm_hdmi_check_mode(void *in_ctx, struct drm_display_mode *mode)
-{
- struct drm_hdmi_context *ctx = in_ctx;
- 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 void drm_hdmi_mode_fixup(void *in_ctx, struct drm_connector *connector,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct drm_hdmi_context *ctx = in_ctx;
- struct drm_display_mode *m;
- int mode_ok;
-
- drm_mode_set_crtcinfo(adjusted_mode, 0);
-
- mode_ok = drm_hdmi_check_mode(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, 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_display_dpms(void *in_ctx, int mode)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- if (hdmi_ops && hdmi_ops->dpms)
- hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
-}
-
-static struct exynos_drm_display_ops drm_hdmi_display_ops = {
- .initialize = drm_hdmi_display_initialize,
- .is_connected = drm_hdmi_is_connected,
- .get_max_resol = drm_hdmi_get_max_resol,
- .get_edid = drm_hdmi_get_edid,
- .mode_fixup = drm_hdmi_mode_fixup,
- .mode_set = drm_hdmi_mode_set,
- .check_mode = drm_hdmi_check_mode,
- .dpms = drm_hdmi_display_dpms,
-};
-
-static struct exynos_drm_display hdmi_display = {
- .type = EXYNOS_DISPLAY_TYPE_HDMI,
- .ops = &drm_hdmi_display_ops,
-};
-
-static int drm_hdmi_enable_vblank(void *in_ctx)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- if (mixer_ops && mixer_ops->enable_vblank)
- return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
- ctx->mixer_ctx->pipe);
-
- return 0;
-}
-
-static void drm_hdmi_disable_vblank(void *in_ctx)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- if (mixer_ops && mixer_ops->disable_vblank)
- return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
-}
-
-static void drm_hdmi_wait_for_vblank(void *in_ctx)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- if (mixer_ops && mixer_ops->wait_for_vblank)
- mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
-}
-
-static void drm_hdmi_commit(void *in_ctx)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- if (hdmi_ops && hdmi_ops->commit)
- hdmi_ops->commit(ctx->hdmi_ctx->ctx);
-}
-
-static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device *drm_dev,
- int pipe)
-{
- struct drm_hdmi_context *ctx = in_ctx;
- int ret = 0;
-
- if (!mixer_ctx) {
- DRM_ERROR("mixer context not initialized.\n");
- return -EFAULT;
- }
- ctx->mixer_ctx = mixer_ctx;
- ctx->mixer_ctx->pipe = pipe;
-
- 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(void *in_ctx)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- if (mixer_ops->iommu_on)
- mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
-}
-
-static void drm_hdmi_dpms(void *in_ctx, int mode)
-{
- struct drm_hdmi_context *ctx = in_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_hdmi_apply(void *in_ctx)
-{
- struct drm_hdmi_context *ctx = in_ctx;
- int i;
-
- for (i = 0; i < MIXER_WIN_NR; i++) {
- if (!ctx->enabled[i])
- continue;
- if (mixer_ops && mixer_ops->win_commit)
- mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
- }
-
- if (hdmi_ops && hdmi_ops->commit)
- hdmi_ops->commit(ctx->hdmi_ctx->ctx);
-}
-
-static void drm_mixer_win_mode_set(void *in_ctx,
- struct exynos_drm_overlay *overlay)
-{
- struct drm_hdmi_context *ctx = in_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(void *in_ctx, int zpos)
-{
- struct drm_hdmi_context *ctx = in_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(void *in_ctx, int zpos)
-{
- struct drm_hdmi_context *ctx = in_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,
- .apply = drm_hdmi_apply,
- .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 drm_hdmi_context *ctx;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- hdmi_manager.ctx = ctx;
- exynos_drm_manager_register(&hdmi_manager);
-
- hdmi_display.ctx = ctx;
- exynos_drm_display_register(&hdmi_display);
-
- platform_set_drvdata(pdev, ctx);
-
- 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 37059ea..0000000
--- 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 <inki.dae at samsung.com>
- *
- * 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 c6df564..d95df28 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -39,7 +39,7 @@
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
+#include "exynos_mixer.h"
#include <linux/gpio.h>
#include <media/s5p_hdmi.h>
@@ -188,7 +188,6 @@ struct hdmi_context {
struct mutex hdmi_mutex;
void __iomem *regs;
- void *parent_ctx;
int irq;
struct i2c_client *ddc_port;
@@ -809,12 +808,61 @@ 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(void *in_ctx, 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(in_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 = hdmi_check_mode(in_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 hdmi_set_acr(u32 freq, u8 *acr)
{
u32 n, cts;
@@ -1753,24 +1801,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);
@@ -1892,7 +1942,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;
@@ -1907,20 +1956,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, hdata);
match = of_match_node(hdmi_match_types, dev->of_node);
if (!match)
@@ -1985,17 +2027,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);
@@ -2011,6 +2050,7 @@ err_ddc:
static int hdmi_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct hdmi_context *hdata = get_hdmi_context(dev);
pm_runtime_disable(dev);
@@ -2023,8 +2063,7 @@ 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 hdmi_context *hdata = get_hdmi_context(dev);
disable_irq(hdata->irq);
@@ -2044,8 +2083,7 @@ static int hdmi_suspend(struct device *dev)
static int hdmi_resume(struct device *dev)
{
- struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
- struct hdmi_context *hdata = ctx->ctx;
+ struct hdmi_context *hdata = get_hdmi_context(dev);
hdata->hpd = gpio_get_value(hdata->hpd_gpio);
@@ -2065,8 +2103,7 @@ 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 hdmi_context *hdata = get_hdmi_context(dev);
hdmi_poweroff(hdata);
@@ -2075,8 +2112,7 @@ static int hdmi_runtime_suspend(struct device *dev)
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 hdmi_context *hdata = get_hdmi_context(dev);
hdmi_poweron(hdata);
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 2f204c1..9de4ac0 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -36,11 +36,14 @@
#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 MIXER_WIN_NR 3
+#define MIXER_DEFAULT_WIN 0
+
struct hdmi_win_data {
dma_addr_t dma_addr;
dma_addr_t chroma_dma_addr;
@@ -94,7 +97,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;
};
@@ -685,35 +687,36 @@ static void mixer_win_reset(struct mixer_context *ctx)
spin_unlock_irqrestore(&res->reg_slock, flags);
}
-static int mixer_initialize(void *ctx, struct drm_device *drm_dev)
+static int mixer_initialize(void *ctx, struct drm_device *drm_dev, int pipe)
{
struct mixer_context *mixer_ctx = ctx;
mixer_ctx->drm_dev = drm_dev;
+ mixer_ctx->pipe = pipe;
- return 0;
+ 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(void *ctx)
{
- struct mixer_context *mdata = ctx;
-
- if (is_drm_iommu_supported(mdata->drm_dev)) {
- if (enable)
- return drm_iommu_attach_device(mdata->drm_dev,
- mdata->dev);
+ struct mixer_context *mixer_ctx = ctx;
- 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(void *ctx)
{
struct mixer_context *mixer_ctx = 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,
@@ -783,9 +786,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(void *ctx, int zpos)
{
struct mixer_context *mixer_ctx = ctx;
+ int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
DRM_DEBUG_KMS("win: %d\n", win);
@@ -804,10 +808,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(void *ctx, int zpos)
{
struct mixer_context *mixer_ctx = 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);
@@ -831,29 +836,6 @@ 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)
{
struct mixer_context *mixer_ctx = ctx;
@@ -973,20 +955,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 irqreturn_t mixer_irq_handler(int irq, void *arg)
@@ -1042,10 +1045,9 @@ out:
return IRQ_HANDLED;
}
-static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
+static int mixer_resources_init(struct mixer_context *mixer_ctx,
struct platform_device *pdev)
{
- struct mixer_context *mixer_ctx = ctx->ctx;
struct device *dev = &pdev->dev;
struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
struct resource *res;
@@ -1094,10 +1096,9 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
return 0;
}
-static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
+static int vp_resources_init(struct mixer_context *mixer_ctx,
struct platform_device *pdev)
{
- struct mixer_context *mixer_ctx = ctx->ctx;
struct device *dev = &pdev->dev;
struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
struct resource *res;
@@ -1182,21 +1183,17 @@ 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;
int ret;
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);
@@ -1209,18 +1206,16 @@ static int mixer_probe(struct platform_device *pdev)
platform_get_device_id(pdev)->driver_data;
}
- ctx->dev = dev;
- ctx->parent_ctx = (void *)drm_hdmi_ctx;
- drm_hdmi_ctx->ctx = (void *)ctx;
+ ctx->dev = &pdev->dev;
ctx->vp_enabled = drv->is_vp_enabled;
ctx->mxr_ver = drv->version;
DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
atomic_set(&ctx->wait_vsync_event, 0);
- platform_set_drvdata(pdev, drm_hdmi_ctx);
+ platform_set_drvdata(pdev, ctx);
/* acquire resources: regs, irqs, clocks */
- ret = mixer_resources_init(drm_hdmi_ctx, pdev);
+ ret = mixer_resources_init(ctx, pdev);
if (ret) {
DRM_ERROR("mixer_resources_init failed\n");
goto fail;
@@ -1228,18 +1223,15 @@ static int mixer_probe(struct platform_device *pdev)
if (ctx->vp_enabled) {
/* acquire vp resources: regs, irqs, clocks */
- ret = vp_resources_init(drm_hdmi_ctx, pdev);
+ ret = vp_resources_init(ctx, pdev);
if (ret) {
DRM_ERROR("vp_resources_init failed\n");
goto fail;
}
}
- /* 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;
+ exynos_drm_manager_register(&mixer_manager);
pm_runtime_enable(dev);
@@ -1263,8 +1255,7 @@ 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 mixer_context *ctx = get_mixer_context(dev);
if (pm_runtime_suspended(dev)) {
DRM_DEBUG_KMS("Already suspended\n");
@@ -1278,8 +1269,7 @@ static int mixer_suspend(struct device *dev)
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 mixer_context *ctx = get_mixer_context(dev);
if (!pm_runtime_suspended(dev)) {
DRM_DEBUG_KMS("Already resumed\n");
@@ -1295,8 +1285,7 @@ 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 mixer_context *ctx = get_mixer_context(dev);
mixer_poweroff(ctx);
@@ -1305,8 +1294,7 @@ static int mixer_runtime_suspend(struct device *dev)
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 mixer_context *ctx = get_mixer_context(dev);
mixer_poweron(ctx);
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h
new file mode 100644
index 0000000..3811e41
--- /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
--
1.8.4
More information about the dri-devel
mailing list