* [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver
@ 2013-10-11 0:30 Sean Paul
2013-10-11 0:30 ` [PATCH 01/23] drm/exynos: Remove useless slab.h include Sean Paul
` (23 more replies)
0 siblings, 24 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patchset refactors parts of the exynos driver to move it closer to a proper
drm driver (rather than just implementing a drm layer on top of the hardware
drivers). The hope is to get to a point where the dp/hdmi drivers can implement
drm_connector/drm_encoder directly, and fimd/mixer can directly implement
drm_crtc.
The notable changes in this set:
- drm_encoder funcs no longer route through the crtc
- DP driver has been moved from video into the drm driver
- fimd no longer implements encoder callbacks
- exynos_drm_hdmi is removed in favor of generic manager/display handling
Sean
Daniel Kurtz (1):
drm/exynos: hdmi: remove the i2c drivers and use devtree
Sean Paul (21):
drm/exynos: Merge overlay_ops into manager_ops
drm/exynos: Add an initialize function to manager and display
drm/exynos: Use manager_op initialize in fimd
drm/exynos: hdmi: Implement initialize op for hdmi
drm/exynos: Pass context in manager ops instead of dev
drm/exynos: Pass context in display_ops instead of dev
drm/exynos: Remove dpms link between encoder/connector
drm/exynos: Rename display_op power_on to dpms
drm/exynos: Don't keep dpms state in encoder
drm/exynos: Use unsigned long for possible_crtcs
drm/exynos: Split manager/display/subdrv
drm/exynos: Remove exynos_drm_hdmi shim
drm/exynos: Use drm_mode_copy to copy modes
drm/exynos: Disable unused crtc planes from crtc
drm/exynos: Add mode_set manager operation
drm/exynos: Implement mode_fixup manager operation
drm/exynos: Use mode_set to configure fimd
drm/exynos: Remove unused/useless fimd_context members
drm/exynos: Move dp driver from video/ to drm/
drm/exynos: Move display implementation into dp
ARM: dts: Move display-timings node from fimd to dp
Stéphane Marchesin (1):
drm/exynos: Remove useless slab.h include
.../devicetree/bindings/video/exynos_dp.txt | 17 +
.../devicetree/bindings/video/samsung-fimd.txt | 2 +
arch/arm/boot/dts/exynos5250-arndale.dts | 7 +-
arch/arm/boot/dts/exynos5250-smdk5250.dts | 7 +-
arch/arm/boot/dts/exynos5250-snow.dts | 7 +-
arch/arm/boot/dts/exynos5420-smdk5420.dts | 7 +-
drivers/gpu/drm/exynos/Kconfig | 7 +
drivers/gpu/drm/exynos/Makefile | 5 +-
drivers/gpu/drm/exynos/exynos_ddc.c | 63 -
drivers/gpu/drm/exynos/exynos_dp_core.c | 1281 ++++++++++++++++++++
drivers/gpu/drm/exynos/exynos_dp_core.h | 215 ++++
drivers/gpu/drm/exynos/exynos_dp_reg.c | 1245 +++++++++++++++++++
drivers/gpu/drm/exynos/exynos_dp_reg.h | 366 ++++++
drivers/gpu/drm/exynos/exynos_drm_connector.c | 92 +-
drivers/gpu/drm/exynos/exynos_drm_connector.h | 4 -
drivers/gpu/drm/exynos/exynos_drm_core.c | 181 ++-
drivers/gpu/drm/exynos/exynos_drm_crtc.c | 140 ++-
drivers/gpu/drm/exynos/exynos_drm_crtc.h | 20 +-
drivers/gpu/drm/exynos/exynos_drm_drv.c | 58 +-
drivers/gpu/drm/exynos/exynos_drm_drv.h | 147 ++-
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 356 +-----
drivers/gpu/drm/exynos/exynos_drm_encoder.h | 18 +-
drivers/gpu/drm/exynos/exynos_drm_fb.c | 4 +-
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 699 +++++------
drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 439 -------
drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 67 -
drivers/gpu/drm/exynos/exynos_drm_plane.c | 17 +-
drivers/gpu/drm/exynos/exynos_drm_plane.h | 2 +-
drivers/gpu/drm/exynos/exynos_drm_vidi.c | 97 +-
drivers/gpu/drm/exynos/exynos_hdmi.c | 169 +--
drivers/gpu/drm/exynos/exynos_hdmi.h | 23 -
drivers/gpu/drm/exynos/exynos_hdmiphy.c | 65 -
drivers/gpu/drm/exynos/exynos_mixer.c | 165 ++-
drivers/gpu/drm/exynos/exynos_mixer.h | 20 +
drivers/video/exynos/Kconfig | 7 -
drivers/video/exynos/Makefile | 1 -
drivers/video/exynos/exynos_dp_core.c | 1214 -------------------
drivers/video/exynos/exynos_dp_core.h | 210 ----
drivers/video/exynos/exynos_dp_reg.c | 1245 -------------------
drivers/video/exynos/exynos_dp_reg.h | 366 ------
40 files changed, 4162 insertions(+), 4893 deletions(-)
delete mode 100644 drivers/gpu/drm/exynos/exynos_ddc.c
create mode 100644 drivers/gpu/drm/exynos/exynos_dp_core.c
create mode 100644 drivers/gpu/drm/exynos/exynos_dp_core.h
create mode 100644 drivers/gpu/drm/exynos/exynos_dp_reg.c
create mode 100644 drivers/gpu/drm/exynos/exynos_dp_reg.h
delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.c
delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.h
delete mode 100644 drivers/gpu/drm/exynos/exynos_hdmi.h
delete mode 100644 drivers/gpu/drm/exynos/exynos_hdmiphy.c
create mode 100644 drivers/gpu/drm/exynos/exynos_mixer.h
delete mode 100644 drivers/video/exynos/exynos_dp_core.c
delete mode 100644 drivers/video/exynos/exynos_dp_core.h
delete mode 100644 drivers/video/exynos/exynos_dp_reg.c
delete mode 100644 drivers/video/exynos/exynos_dp_reg.h
--
1.8.4
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 01/23] drm/exynos: Remove useless slab.h include
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 02/23] drm/exynos: Merge overlay_ops into manager_ops Sean Paul
` (22 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
From: Stéphane Marchesin <marcheu@chromium.org>
Signed-off-by: Stéphane Marchesin <marcheu@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/video/exynos/exynos_dp_core.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index 12bbede..089ae22 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/slab.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
--
1.8.4
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 02/23] drm/exynos: Merge overlay_ops into manager_ops
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
2013-10-11 0:30 ` [PATCH 01/23] drm/exynos: Remove useless slab.h include Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 03/23] drm/exynos: Add an initialize function to manager and display Sean Paul
` (21 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch merges overlay_ops into manager_ops. In all cases,
overlay_ops is implemented in the same place as manager ops, it doesn't
serve a functional purpose, and doesn't make things more clear.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_drv.h | 29 +--
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 26 +-
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 363 ++++++++++++++--------------
drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 36 ++-
drivers/gpu/drm/exynos/exynos_drm_vidi.c | 29 +--
drivers/gpu/drm/exynos/exynos_mixer.c | 2 -
6 files changed, 229 insertions(+), 256 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index eaa1966..6f31839 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -54,22 +54,6 @@ enum exynos_drm_output_type {
};
/*
- * Exynos drm overlay ops structure.
- *
- * @mode_set: copy drm overlay info to hw specific overlay info.
- * @commit: apply hardware specific overlay data to registers.
- * @enable: enable hardware specific overlay.
- * @disable: disable hardware specific overlay.
- */
-struct exynos_drm_overlay_ops {
- void (*mode_set)(struct device *subdrv_dev,
- struct exynos_drm_overlay *overlay);
- void (*commit)(struct device *subdrv_dev, int zpos);
- void (*enable)(struct device *subdrv_dev, int zpos);
- void (*disable)(struct device *subdrv_dev, int zpos);
-};
-
-/*
* Exynos drm common overlay structure.
*
* @fb_x: offset x on a framebuffer to be displayed.
@@ -169,6 +153,10 @@ struct exynos_drm_display_ops {
* @disable_vblank: specific driver callback for disabling vblank interrupt.
* @wait_for_vblank: wait for vblank interrupt to make sure that
* hardware overlay is updated.
+ * @win_mode_set: copy drm overlay info to hw specific overlay info.
+ * @win_commit: apply hardware specific overlay data to registers.
+ * @win_enable: enable hardware specific overlay.
+ * @win_disable: disable hardware specific overlay.
*/
struct exynos_drm_manager_ops {
void (*dpms)(struct device *subdrv_dev, int mode);
@@ -184,6 +172,11 @@ struct exynos_drm_manager_ops {
int (*enable_vblank)(struct device *subdrv_dev);
void (*disable_vblank)(struct device *subdrv_dev);
void (*wait_for_vblank)(struct device *subdrv_dev);
+ void (*win_mode_set)(struct device *subdrv_dev,
+ struct exynos_drm_overlay *overlay);
+ void (*win_commit)(struct device *subdrv_dev, int zpos);
+ void (*win_enable)(struct device *subdrv_dev, int zpos);
+ void (*win_disable)(struct device *subdrv_dev, int zpos);
};
/*
@@ -195,9 +188,6 @@ struct exynos_drm_manager_ops {
* @ops: pointer to callbacks for exynos drm specific framebuffer.
* these callbacks should be set by specific drivers such fimd
* or hdmi driver and are used to control hardware global registers.
- * @overlay_ops: pointer to callbacks for exynos drm specific framebuffer.
- * these callbacks should be set by specific drivers such fimd
- * or hdmi driver and are used to control hardware overlay reigsters.
* @display: pointer to callbacks for exynos drm specific framebuffer.
* these callbacks should be set by specific drivers such fimd
* or hdmi driver and are used to control display devices such as
@@ -207,7 +197,6 @@ struct exynos_drm_manager {
struct device *dev;
int pipe;
struct exynos_drm_manager_ops *ops;
- struct exynos_drm_overlay_ops *overlay_ops;
struct exynos_drm_display_ops *display_ops;
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 06f1b2a..c255341 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -133,7 +133,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
*
* plane->funcs->disable_plane call checks
* if encoder->crtc is same as plane->crtc and if same
- * then overlay_ops->disable callback will be called
+ * then manager_ops->win_disable callback will be called
* to diasble current hw overlay so plane->crtc should
* have new_crtc because new_crtc was set to
* encoder->crtc in advance.
@@ -442,51 +442,51 @@ void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
{
struct exynos_drm_manager *manager =
to_exynos_encoder(encoder)->manager;
- struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+ struct exynos_drm_manager_ops *manager_ops = manager->ops;
struct exynos_drm_overlay *overlay = data;
- if (overlay_ops && overlay_ops->mode_set)
- overlay_ops->mode_set(manager->dev, overlay);
+ if (manager_ops && manager_ops->win_mode_set)
+ manager_ops->win_mode_set(manager->dev, overlay);
}
void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
{
struct exynos_drm_manager *manager =
to_exynos_encoder(encoder)->manager;
- struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+ struct exynos_drm_manager_ops *manager_ops = manager->ops;
int zpos = DEFAULT_ZPOS;
if (data)
zpos = *(int *)data;
- if (overlay_ops && overlay_ops->commit)
- overlay_ops->commit(manager->dev, zpos);
+ if (manager_ops && manager_ops->win_commit)
+ manager_ops->win_commit(manager->dev, zpos);
}
void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
{
struct exynos_drm_manager *manager =
to_exynos_encoder(encoder)->manager;
- struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+ struct exynos_drm_manager_ops *manager_ops = manager->ops;
int zpos = DEFAULT_ZPOS;
if (data)
zpos = *(int *)data;
- if (overlay_ops && overlay_ops->enable)
- overlay_ops->enable(manager->dev, zpos);
+ if (manager_ops && manager_ops->win_enable)
+ manager_ops->win_enable(manager->dev, zpos);
}
void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
{
struct exynos_drm_manager *manager =
to_exynos_encoder(encoder)->manager;
- struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+ struct exynos_drm_manager_ops *manager_ops = manager->ops;
int zpos = DEFAULT_ZPOS;
if (data)
zpos = *(int *)data;
- if (overlay_ops && overlay_ops->disable)
- overlay_ops->disable(manager->dev, zpos);
+ if (manager_ops && manager_ops->win_disable)
+ manager_ops->win_disable(manager->dev, zpos);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 868a14d..f271f22 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -181,185 +181,6 @@ static struct exynos_drm_display_ops fimd_display_ops = {
.power_on = fimd_display_power_on,
};
-static void fimd_dpms(struct device *subdrv_dev, int mode)
-{
- struct fimd_context *ctx = get_fimd_context(subdrv_dev);
-
- DRM_DEBUG_KMS("%d\n", mode);
-
- mutex_lock(&ctx->lock);
-
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- /*
- * enable fimd hardware only if suspended status.
- *
- * P.S. fimd_dpms function would be called at booting time so
- * clk_enable could be called double time.
- */
- if (ctx->suspended)
- pm_runtime_get_sync(subdrv_dev);
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
- if (!ctx->suspended)
- pm_runtime_put_sync(subdrv_dev);
- break;
- default:
- DRM_DEBUG_KMS("unspecified mode %d\n", mode);
- break;
- }
-
- mutex_unlock(&ctx->lock);
-}
-
-static void fimd_apply(struct device *subdrv_dev)
-{
- struct fimd_context *ctx = get_fimd_context(subdrv_dev);
- struct exynos_drm_manager *mgr = ctx->subdrv.manager;
- struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
- struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
- struct fimd_win_data *win_data;
- int i;
-
- for (i = 0; i < WINDOWS_NR; i++) {
- win_data = &ctx->win_data[i];
- if (win_data->enabled && (ovl_ops && ovl_ops->commit))
- ovl_ops->commit(subdrv_dev, i);
- }
-
- if (mgr_ops && mgr_ops->commit)
- mgr_ops->commit(subdrv_dev);
-}
-
-static void fimd_commit(struct device *dev)
-{
- struct fimd_context *ctx = get_fimd_context(dev);
- struct exynos_drm_panel_info *panel = &ctx->panel;
- struct videomode *vm = &panel->vm;
- struct fimd_driver_data *driver_data;
- u32 val;
-
- driver_data = ctx->driver_data;
- if (ctx->suspended)
- return;
-
- /* setup polarity values from machine code. */
- writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
-
- /* setup vertical timing values. */
- val = VIDTCON0_VBPD(vm->vback_porch - 1) |
- VIDTCON0_VFPD(vm->vfront_porch - 1) |
- VIDTCON0_VSPW(vm->vsync_len - 1);
- writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
-
- /* setup horizontal timing values. */
- val = VIDTCON1_HBPD(vm->hback_porch - 1) |
- VIDTCON1_HFPD(vm->hfront_porch - 1) |
- VIDTCON1_HSPW(vm->hsync_len - 1);
- writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
-
- /* setup horizontal and vertical display size. */
- val = VIDTCON2_LINEVAL(vm->vactive - 1) |
- VIDTCON2_HOZVAL(vm->hactive - 1) |
- VIDTCON2_LINEVAL_E(vm->vactive - 1) |
- VIDTCON2_HOZVAL_E(vm->hactive - 1);
- writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
-
- /* setup clock source, clock divider, enable dma. */
- val = ctx->vidcon0;
- val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
-
- if (ctx->driver_data->has_clksel) {
- val &= ~VIDCON0_CLKSEL_MASK;
- val |= VIDCON0_CLKSEL_LCD;
- }
-
- if (ctx->clkdiv > 1)
- val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
- else
- val &= ~VIDCON0_CLKDIR; /* 1:1 clock */
-
- /*
- * fields of register with prefix '_F' would be updated
- * at vsync(same as dma start)
- */
- val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
- writel(val, ctx->regs + VIDCON0);
-}
-
-static int fimd_enable_vblank(struct device *dev)
-{
- struct fimd_context *ctx = get_fimd_context(dev);
- u32 val;
-
- if (ctx->suspended)
- return -EPERM;
-
- if (!test_and_set_bit(0, &ctx->irq_flags)) {
- val = readl(ctx->regs + VIDINTCON0);
-
- val |= VIDINTCON0_INT_ENABLE;
- val |= VIDINTCON0_INT_FRAME;
-
- val &= ~VIDINTCON0_FRAMESEL0_MASK;
- val |= VIDINTCON0_FRAMESEL0_VSYNC;
- val &= ~VIDINTCON0_FRAMESEL1_MASK;
- val |= VIDINTCON0_FRAMESEL1_NONE;
-
- writel(val, ctx->regs + VIDINTCON0);
- }
-
- return 0;
-}
-
-static void fimd_disable_vblank(struct device *dev)
-{
- struct fimd_context *ctx = get_fimd_context(dev);
- u32 val;
-
- if (ctx->suspended)
- return;
-
- if (test_and_clear_bit(0, &ctx->irq_flags)) {
- val = readl(ctx->regs + VIDINTCON0);
-
- val &= ~VIDINTCON0_INT_FRAME;
- val &= ~VIDINTCON0_INT_ENABLE;
-
- writel(val, ctx->regs + VIDINTCON0);
- }
-}
-
-static void fimd_wait_for_vblank(struct device *dev)
-{
- struct fimd_context *ctx = get_fimd_context(dev);
-
- if (ctx->suspended)
- return;
-
- atomic_set(&ctx->wait_vsync_event, 1);
-
- /*
- * wait for FIMD to signal VSYNC interrupt or return after
- * timeout which is set to 50ms (refresh rate of 20).
- */
- if (!wait_event_timeout(ctx->wait_vsync_queue,
- !atomic_read(&ctx->wait_vsync_event),
- DRM_HZ/20))
- DRM_DEBUG_KMS("vblank wait timed out.\n");
-}
-
-static struct exynos_drm_manager_ops fimd_manager_ops = {
- .dpms = fimd_dpms,
- .apply = fimd_apply,
- .commit = fimd_commit,
- .enable_vblank = fimd_enable_vblank,
- .disable_vblank = fimd_disable_vblank,
- .wait_for_vblank = fimd_wait_for_vblank,
-};
-
static void fimd_win_mode_set(struct device *dev,
struct exynos_drm_overlay *overlay)
{
@@ -669,16 +490,190 @@ static void fimd_win_disable(struct device *dev, int zpos)
win_data->enabled = false;
}
-static struct exynos_drm_overlay_ops fimd_overlay_ops = {
- .mode_set = fimd_win_mode_set,
- .commit = fimd_win_commit,
- .disable = fimd_win_disable,
+static void fimd_dpms(struct device *subdrv_dev, int mode)
+{
+ struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+
+ DRM_DEBUG_KMS("%d\n", mode);
+
+ mutex_lock(&ctx->lock);
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ /*
+ * enable fimd hardware only if suspended status.
+ *
+ * P.S. fimd_dpms function would be called at booting time so
+ * clk_enable could be called double time.
+ */
+ if (ctx->suspended)
+ pm_runtime_get_sync(subdrv_dev);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ if (!ctx->suspended)
+ pm_runtime_put_sync(subdrv_dev);
+ break;
+ default:
+ DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+ break;
+ }
+
+ mutex_unlock(&ctx->lock);
+}
+
+static void fimd_apply(struct device *subdrv_dev)
+{
+ struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+ struct exynos_drm_manager *mgr = ctx->subdrv.manager;
+ struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
+ struct fimd_win_data *win_data;
+ int i;
+
+ for (i = 0; i < WINDOWS_NR; i++) {
+ win_data = &ctx->win_data[i];
+ if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
+ mgr_ops->win_commit(subdrv_dev, i);
+ }
+
+ if (mgr_ops && mgr_ops->commit)
+ mgr_ops->commit(subdrv_dev);
+}
+
+static void fimd_commit(struct device *dev)
+{
+ struct fimd_context *ctx = get_fimd_context(dev);
+ struct exynos_drm_panel_info *panel = &ctx->panel;
+ struct videomode *vm = &panel->vm;
+ struct fimd_driver_data *driver_data;
+ u32 val;
+
+ driver_data = ctx->driver_data;
+ if (ctx->suspended)
+ return;
+
+ /* setup polarity values from machine code. */
+ writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
+
+ /* setup vertical timing values. */
+ val = VIDTCON0_VBPD(vm->vback_porch - 1) |
+ VIDTCON0_VFPD(vm->vfront_porch - 1) |
+ VIDTCON0_VSPW(vm->vsync_len - 1);
+ writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
+
+ /* setup horizontal timing values. */
+ val = VIDTCON1_HBPD(vm->hback_porch - 1) |
+ VIDTCON1_HFPD(vm->hfront_porch - 1) |
+ VIDTCON1_HSPW(vm->hsync_len - 1);
+ writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
+
+ /* setup horizontal and vertical display size. */
+ val = VIDTCON2_LINEVAL(vm->vactive - 1) |
+ VIDTCON2_HOZVAL(vm->hactive - 1) |
+ VIDTCON2_LINEVAL_E(vm->vactive - 1) |
+ VIDTCON2_HOZVAL_E(vm->hactive - 1);
+ writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
+
+ /* setup clock source, clock divider, enable dma. */
+ val = ctx->vidcon0;
+ val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
+
+ if (ctx->driver_data->has_clksel) {
+ val &= ~VIDCON0_CLKSEL_MASK;
+ val |= VIDCON0_CLKSEL_LCD;
+ }
+
+ if (ctx->clkdiv > 1)
+ val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
+ else
+ val &= ~VIDCON0_CLKDIR; /* 1:1 clock */
+
+ /*
+ * fields of register with prefix '_F' would be updated
+ * at vsync(same as dma start)
+ */
+ val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+ writel(val, ctx->regs + VIDCON0);
+}
+
+static int fimd_enable_vblank(struct device *dev)
+{
+ struct fimd_context *ctx = get_fimd_context(dev);
+ u32 val;
+
+ if (ctx->suspended)
+ return -EPERM;
+
+ if (!test_and_set_bit(0, &ctx->irq_flags)) {
+ val = readl(ctx->regs + VIDINTCON0);
+
+ val |= VIDINTCON0_INT_ENABLE;
+ val |= VIDINTCON0_INT_FRAME;
+
+ val &= ~VIDINTCON0_FRAMESEL0_MASK;
+ val |= VIDINTCON0_FRAMESEL0_VSYNC;
+ val &= ~VIDINTCON0_FRAMESEL1_MASK;
+ val |= VIDINTCON0_FRAMESEL1_NONE;
+
+ writel(val, ctx->regs + VIDINTCON0);
+ }
+
+ return 0;
+}
+
+static void fimd_disable_vblank(struct device *dev)
+{
+ struct fimd_context *ctx = get_fimd_context(dev);
+ u32 val;
+
+ if (ctx->suspended)
+ return;
+
+ if (test_and_clear_bit(0, &ctx->irq_flags)) {
+ val = readl(ctx->regs + VIDINTCON0);
+
+ val &= ~VIDINTCON0_INT_FRAME;
+ val &= ~VIDINTCON0_INT_ENABLE;
+
+ writel(val, ctx->regs + VIDINTCON0);
+ }
+}
+
+static void fimd_wait_for_vblank(struct device *dev)
+{
+ struct fimd_context *ctx = get_fimd_context(dev);
+
+ if (ctx->suspended)
+ return;
+
+ atomic_set(&ctx->wait_vsync_event, 1);
+
+ /*
+ * wait for FIMD to signal VSYNC interrupt or return after
+ * timeout which is set to 50ms (refresh rate of 20).
+ */
+ if (!wait_event_timeout(ctx->wait_vsync_queue,
+ !atomic_read(&ctx->wait_vsync_event),
+ DRM_HZ/20))
+ DRM_DEBUG_KMS("vblank wait timed out.\n");
+}
+
+static struct exynos_drm_manager_ops fimd_manager_ops = {
+ .dpms = fimd_dpms,
+ .apply = fimd_apply,
+ .commit = fimd_commit,
+ .enable_vblank = fimd_enable_vblank,
+ .disable_vblank = fimd_disable_vblank,
+ .wait_for_vblank = fimd_wait_for_vblank,
+ .win_mode_set = fimd_win_mode_set,
+ .win_commit = fimd_win_commit,
+ .win_disable = fimd_win_disable,
};
static struct exynos_drm_manager fimd_manager = {
.pipe = -1,
.ops = &fimd_manager_ops,
- .overlay_ops = &fimd_overlay_ops,
.display_ops = &fimd_display_ops,
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 8548b97..a1ef3c9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -284,19 +284,7 @@ static void drm_hdmi_apply(struct device *subdrv_dev)
hdmi_ops->commit(ctx->hdmi_ctx->ctx);
}
-static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
- .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,
- .mode_fixup = drm_hdmi_mode_fixup,
- .mode_set = drm_hdmi_mode_set,
- .get_max_resol = drm_hdmi_get_max_resol,
- .commit = drm_hdmi_commit,
-};
-
-static void drm_mixer_mode_set(struct device *subdrv_dev,
+static void drm_mixer_win_mode_set(struct device *subdrv_dev,
struct exynos_drm_overlay *overlay)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -305,7 +293,7 @@ static void drm_mixer_mode_set(struct device *subdrv_dev,
mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
}
-static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
+static void drm_mixer_win_commit(struct device *subdrv_dev, int zpos)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
@@ -321,7 +309,7 @@ static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
ctx->enabled[win] = true;
}
-static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
+static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
@@ -337,16 +325,24 @@ static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
ctx->enabled[win] = false;
}
-static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
- .mode_set = drm_mixer_mode_set,
- .commit = drm_mixer_commit,
- .disable = drm_mixer_disable,
+static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
+ .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,
+ .mode_fixup = drm_hdmi_mode_fixup,
+ .mode_set = drm_hdmi_mode_set,
+ .get_max_resol = drm_hdmi_get_max_resol,
+ .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 = {
.pipe = -1,
.ops = &drm_hdmi_manager_ops,
- .overlay_ops = &drm_hdmi_overlay_ops,
.display_ops = &drm_hdmi_display_ops,
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 4400330..15a97ce 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -182,14 +182,13 @@ static void vidi_apply(struct device *subdrv_dev)
struct vidi_context *ctx = get_vidi_context(subdrv_dev);
struct exynos_drm_manager *mgr = ctx->subdrv.manager;
struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
- struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
struct vidi_win_data *win_data;
int i;
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
- if (win_data->enabled && (ovl_ops && ovl_ops->commit))
- ovl_ops->commit(subdrv_dev, i);
+ if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
+ mgr_ops->win_commit(subdrv_dev, i);
}
if (mgr_ops && mgr_ops->commit)
@@ -219,7 +218,7 @@ static int vidi_enable_vblank(struct device *dev)
/*
* in case of page flip request, vidi_finish_pageflip function
* will not be called because direct_vblank is true and then
- * that function will be called by overlay_ops->commit callback
+ * that function will be called by manager_ops->win_commit callback
*/
schedule_work(&ctx->work);
@@ -237,14 +236,6 @@ static void vidi_disable_vblank(struct device *dev)
ctx->vblank_on = false;
}
-static struct exynos_drm_manager_ops vidi_manager_ops = {
- .dpms = vidi_dpms,
- .apply = vidi_apply,
- .commit = vidi_commit,
- .enable_vblank = vidi_enable_vblank,
- .disable_vblank = vidi_disable_vblank,
-};
-
static void vidi_win_mode_set(struct device *dev,
struct exynos_drm_overlay *overlay)
{
@@ -341,16 +332,20 @@ static void vidi_win_disable(struct device *dev, int zpos)
/* TODO. */
}
-static struct exynos_drm_overlay_ops vidi_overlay_ops = {
- .mode_set = vidi_win_mode_set,
- .commit = vidi_win_commit,
- .disable = vidi_win_disable,
+static struct exynos_drm_manager_ops vidi_manager_ops = {
+ .dpms = vidi_dpms,
+ .apply = vidi_apply,
+ .commit = vidi_commit,
+ .enable_vblank = vidi_enable_vblank,
+ .disable_vblank = vidi_disable_vblank,
+ .win_mode_set = vidi_win_mode_set,
+ .win_commit = vidi_win_commit,
+ .win_disable = vidi_win_disable,
};
static struct exynos_drm_manager vidi_manager = {
.pipe = -1,
.ops = &vidi_manager_ops,
- .overlay_ops = &vidi_overlay_ops,
.display_ops = &vidi_display_ops,
};
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 63bc5f9..9634188 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -975,8 +975,6 @@ static struct exynos_mixer_ops mixer_ops = {
.disable_vblank = mixer_disable_vblank,
.wait_for_vblank = mixer_wait_for_vblank,
.dpms = mixer_dpms,
-
- /* overlay */
.win_mode_set = mixer_win_mode_set,
.win_commit = mixer_win_commit,
.win_disable = mixer_win_disable,
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 03/23] drm/exynos: Add an initialize function to manager and display
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
2013-10-11 0:30 ` [PATCH 01/23] drm/exynos: Remove useless slab.h include Sean Paul
2013-10-11 0:30 ` [PATCH 02/23] drm/exynos: Merge overlay_ops into manager_ops Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 04/23] drm/exynos: Use manager_op initialize in fimd Sean Paul
` (20 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch adds an initialize function to the manager and display
operations. This allows them to keep track of drm_device in their
local context, as well as adds an initialization hook right after
the encoder is created.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 +++++
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 21 +++++++++++++++++++++
2 files changed, 26 insertions(+)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 6f31839..09bfe60 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -123,6 +123,7 @@ struct exynos_drm_overlay {
* - this structure is common to analog tv, digital tv and lcd panel.
*
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @initialize: initializes the display with drm_dev
* @is_connected: check for that display is connected or not.
* @get_edid: get edid modes from display driver.
* @get_panel: get panel object from display driver.
@@ -131,6 +132,7 @@ struct exynos_drm_overlay {
*/
struct exynos_drm_display_ops {
enum exynos_drm_output_type type;
+ int (*initialize)(struct device *dev, struct drm_device *drm_dev);
bool (*is_connected)(struct device *dev);
struct edid *(*get_edid)(struct device *dev,
struct drm_connector *connector);
@@ -142,6 +144,7 @@ struct exynos_drm_display_ops {
/*
* Exynos drm manager ops
*
+ * @initialize: initializes the manager with drm_dev
* @dpms: control device power.
* @apply: set timing, vblank and overlay data to registers.
* @mode_fixup: fix mode data comparing to hw specific display mode.
@@ -159,6 +162,8 @@ struct exynos_drm_display_ops {
* @win_disable: disable hardware specific overlay.
*/
struct exynos_drm_manager_ops {
+ int (*initialize)(struct device *subdrv_dev,
+ struct drm_device *drm_dev);
void (*dpms)(struct device *subdrv_dev, int mode);
void (*apply)(struct device *subdrv_dev);
void (*mode_fixup)(struct device *subdrv_dev,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index c255341..a9eb2b0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -316,6 +316,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
{
struct drm_encoder *encoder;
struct exynos_drm_encoder *exynos_encoder;
+ int ret;
if (!manager || !possible_crtcs)
return NULL;
@@ -339,9 +340,29 @@ exynos_drm_encoder_create(struct drm_device *dev,
drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
+ if (manager->ops && manager->ops->initialize) {
+ ret = manager->ops->initialize(manager->dev, dev);
+ if (ret) {
+ DRM_ERROR("Manager initialize failed %d\n", ret);
+ goto error;
+ }
+ }
+
+ if (manager->display_ops && manager->display_ops->initialize) {
+ ret = manager->display_ops->initialize(manager->dev, dev);
+ if (ret) {
+ DRM_ERROR("Display initialize failed %d\n", ret);
+ goto error;
+ }
+ }
+
DRM_DEBUG_KMS("encoder has been created\n");
return encoder;
+
+error:
+ exynos_drm_encoder_destroy(&exynos_encoder->drm_encoder);
+ return NULL;
}
struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 04/23] drm/exynos: Use manager_op initialize in fimd
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (2 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 03/23] drm/exynos: Add an initialize function to manager and display Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 05/23] drm/exynos: hdmi: Implement initialize op for hdmi Sean Paul
` (19 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch implements the intitialize manager op in fimd.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index f271f22..90fcd6f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -106,6 +106,7 @@ struct fimd_win_data {
struct fimd_context {
struct exynos_drm_subdrv subdrv;
+ struct drm_device *drm_dev;
int irq;
struct drm_crtc *crtc;
struct clk *bus_clk;
@@ -490,6 +491,16 @@ static void fimd_win_disable(struct device *dev, int zpos)
win_data->enabled = false;
}
+static int fimd_mgr_initialize(struct device *subdrv_dev,
+ struct drm_device *drm_dev)
+{
+ struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+
+ ctx->drm_dev = drm_dev;
+
+ return 0;
+}
+
static void fimd_dpms(struct device *subdrv_dev, int mode)
{
struct fimd_context *ctx = get_fimd_context(subdrv_dev);
@@ -660,6 +671,7 @@ static void fimd_wait_for_vblank(struct device *dev)
}
static struct exynos_drm_manager_ops fimd_manager_ops = {
+ .initialize = fimd_mgr_initialize,
.dpms = fimd_dpms,
.apply = fimd_apply,
.commit = fimd_commit,
@@ -681,7 +693,6 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
{
struct fimd_context *ctx = (struct fimd_context *)dev_id;
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
- struct drm_device *drm_dev = subdrv->drm_dev;
struct exynos_drm_manager *manager = subdrv->manager;
u32 val;
@@ -692,11 +703,11 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
/* check the crtc is detached already from encoder */
- if (manager->pipe < 0)
+ if (manager->pipe < 0 || !ctx->drm_dev)
goto out;
- drm_handle_vblank(drm_dev, manager->pipe);
- exynos_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
+ drm_handle_vblank(ctx->drm_dev, manager->pipe);
+ exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 05/23] drm/exynos: hdmi: Implement initialize op for hdmi
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (3 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 04/23] drm/exynos: Use manager_op initialize in fimd Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev Sean Paul
` (18 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch implements the initialize callback in the hdmi and mixer
manager. This allows us to get rid of drm_dev in the drm_hdmi level and
track it in the mixer and hdmi drivers. This is one of the things
holding back the complete removal of the drm_hdmi layer.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 35 ++++++++++++++++++++++++++------
drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 3 ++-
drivers/gpu/drm/exynos/exynos_hdmi.c | 18 ++++++++++++----
drivers/gpu/drm/exynos/exynos_mixer.c | 35 +++++++++++++++++++-------------
4 files changed, 66 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index a1ef3c9..aebcc0e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -97,6 +97,18 @@ void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
mixer_ops = ops;
}
+static int drm_hdmi_display_initialize(struct device *dev,
+ struct drm_device *drm_dev)
+{
+ struct drm_hdmi_context *ctx = to_context(dev);
+
+ 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 device *dev)
{
struct drm_hdmi_context *ctx = to_context(dev);
@@ -153,6 +165,7 @@ static int drm_hdmi_power_on(struct device *dev, int mode)
static struct exynos_drm_display_ops drm_hdmi_display_ops = {
.type = EXYNOS_DISPLAY_TYPE_HDMI,
+ .initialize = drm_hdmi_display_initialize,
.is_connected = drm_hdmi_is_connected,
.get_edid = drm_hdmi_get_edid,
.check_mode = drm_hdmi_check_mode,
@@ -257,6 +270,21 @@ static void drm_hdmi_commit(struct device *subdrv_dev)
hdmi_ops->commit(ctx->hdmi_ctx->ctx);
}
+static int drm_hdmi_mgr_initialize(struct device *subdrv_dev,
+ struct drm_device *drm_dev)
+{
+ struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ int ret = 0;
+
+ 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_dpms(struct device *subdrv_dev, int mode)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -326,6 +354,7 @@ static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
}
static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
+ .initialize = drm_hdmi_mgr_initialize,
.dpms = drm_hdmi_dpms,
.apply = drm_hdmi_apply,
.enable_vblank = drm_hdmi_enable_vblank,
@@ -372,12 +401,6 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
ctx->hdmi_ctx = hdmi_ctx;
ctx->mixer_ctx = mixer_ctx;
- ctx->hdmi_ctx->drm_dev = drm_dev;
- ctx->mixer_ctx->drm_dev = drm_dev;
-
- if (mixer_ops->iommu_on)
- mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
-
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 724cab1..cf7b1da 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -23,12 +23,12 @@
* this context should be hdmi_context or mixer_context.
*/
struct exynos_drm_hdmi_context {
- struct drm_device *drm_dev;
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);
@@ -45,6 +45,7 @@ struct exynos_hdmi_ops {
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);
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index a0e10ae..a3fba8e 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -742,6 +742,15 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
}
}
+static int hdmi_initialize(void *ctx, struct drm_device *drm_dev)
+{
+ struct hdmi_context *hdata = ctx;
+
+ hdata->drm_dev = drm_dev;
+
+ return 0;
+}
+
static bool hdmi_is_connected(void *ctx)
{
struct hdmi_context *hdata = ctx;
@@ -1747,6 +1756,7 @@ static void hdmi_dpms(void *ctx, int mode)
static struct exynos_hdmi_ops hdmi_ops = {
/* display */
+ .initialize = hdmi_initialize,
.is_connected = hdmi_is_connected,
.get_edid = hdmi_get_edid,
.check_mode = hdmi_check_mode,
@@ -1767,8 +1777,8 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
hdata->hpd = gpio_get_value(hdata->hpd_gpio);
mutex_unlock(&hdata->hdmi_mutex);
- if (ctx->drm_dev)
- drm_helper_hpd_irq_event(ctx->drm_dev);
+ if (hdata->drm_dev)
+ drm_helper_hpd_irq_event(hdata->drm_dev);
return IRQ_HANDLED;
}
@@ -2026,8 +2036,8 @@ static int hdmi_suspend(struct device *dev)
disable_irq(hdata->irq);
hdata->hpd = false;
- if (ctx->drm_dev)
- drm_helper_hpd_irq_event(ctx->drm_dev);
+ if (hdata->drm_dev)
+ drm_helper_hpd_irq_event(hdata->drm_dev);
if (pm_runtime_suspended(dev)) {
DRM_DEBUG_KMS("Already suspended\n");
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 9634188..2f204c1 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -685,20 +685,25 @@ 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)
+{
+ struct mixer_context *mixer_ctx = ctx;
+
+ mixer_ctx->drm_dev = drm_dev;
+
+ return 0;
+}
+
static int mixer_iommu_on(void *ctx, bool enable)
{
- struct exynos_drm_hdmi_context *drm_hdmi_ctx;
struct mixer_context *mdata = ctx;
- struct drm_device *drm_dev;
-
- drm_hdmi_ctx = mdata->parent_ctx;
- drm_dev = drm_hdmi_ctx->drm_dev;
- if (is_drm_iommu_supported(drm_dev)) {
+ if (is_drm_iommu_supported(mdata->drm_dev)) {
if (enable)
- return drm_iommu_attach_device(drm_dev, mdata->dev);
+ return drm_iommu_attach_device(mdata->drm_dev,
+ mdata->dev);
- drm_iommu_detach_device(drm_dev, mdata->dev);
+ drm_iommu_detach_device(mdata->drm_dev, mdata->dev);
}
return 0;
}
@@ -970,6 +975,7 @@ static void mixer_dpms(void *ctx, int mode)
static struct exynos_mixer_ops mixer_ops = {
/* manager */
+ .initialize = mixer_initialize,
.iommu_on = mixer_iommu_on,
.enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank,
@@ -985,8 +991,7 @@ static struct exynos_mixer_ops mixer_ops = {
static irqreturn_t mixer_irq_handler(int irq, void *arg)
{
- struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
- struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+ struct mixer_context *ctx = arg;
struct mixer_resources *res = &ctx->mixer_res;
u32 val, base, shadow;
@@ -995,6 +1000,9 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
/* read interrupt status for handling and clearing flags for VSYNC */
val = mixer_reg_read(res, MXR_INT_STATUS);
+ if (!ctx->drm_dev)
+ goto out;
+
/* handling VSYNC */
if (val & MXR_INT_STATUS_VSYNC) {
/* interlace scan need to check shadow register */
@@ -1010,9 +1018,8 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
goto out;
}
- drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
- exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev,
- ctx->pipe);
+ drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+ exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
@@ -1077,7 +1084,7 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
}
ret = devm_request_irq(dev, res->start, mixer_irq_handler,
- 0, "drm_mixer", ctx);
+ 0, "drm_mixer", mixer_ctx);
if (ret) {
dev_err(dev, "request interrupt failed.\n");
return ret;
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (4 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 05/23] drm/exynos: hdmi: Implement initialize op for hdmi Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-12 6:44 ` Inki Dae
2013-10-14 12:42 ` Inki Dae
2013-10-11 0:30 ` [PATCH 07/23] drm/exynos: Pass context in display_ops " Sean Paul
` (17 subsequent siblings)
23 siblings, 2 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch changes the manager ops callbacks from accepting the subdrv
device pointer to taking a context pointer. This will allow us to move
closer to decoupling manager/display from subdrv, and subsequently
decoupling the crtc/plane from the encoder.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_connector.c | 2 +-
drivers/gpu/drm/exynos/exynos_drm_drv.h | 33 ++++++------
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 24 ++++-----
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 71 +++++++++++++------------
drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 75 +++++++++++++++------------
drivers/gpu/drm/exynos/exynos_drm_vidi.c | 49 ++++++++---------
6 files changed, 130 insertions(+), 124 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index e082efb..b70b123 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -198,7 +198,7 @@ static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
* resolution then get max width and height from that driver.
*/
if (ops && ops->get_max_resol)
- ops->get_max_resol(manager->dev, &width, &height);
+ ops->get_max_resol(manager->ctx, &width, &height);
return drm_helper_probe_single_connector_modes(connector, width,
height);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 09bfe60..0bd444f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -162,26 +162,23 @@ struct exynos_drm_display_ops {
* @win_disable: disable hardware specific overlay.
*/
struct exynos_drm_manager_ops {
- int (*initialize)(struct device *subdrv_dev,
- struct drm_device *drm_dev);
- void (*dpms)(struct device *subdrv_dev, int mode);
- void (*apply)(struct device *subdrv_dev);
- void (*mode_fixup)(struct device *subdrv_dev,
- struct drm_connector *connector,
+ int (*initialize)(void *ctx, struct drm_device *drm_dev);
+ void (*dpms)(void *ctx, int mode);
+ void (*apply)(void *ctx);
+ void (*mode_fixup)(void *ctx, struct drm_connector *connector,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
- void (*mode_set)(struct device *subdrv_dev, void *mode);
- void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
+ void (*mode_set)(void *ctx, void *mode);
+ void (*get_max_resol)(void *ctx, unsigned int *width,
unsigned int *height);
- void (*commit)(struct device *subdrv_dev);
- int (*enable_vblank)(struct device *subdrv_dev);
- void (*disable_vblank)(struct device *subdrv_dev);
- void (*wait_for_vblank)(struct device *subdrv_dev);
- void (*win_mode_set)(struct device *subdrv_dev,
- struct exynos_drm_overlay *overlay);
- void (*win_commit)(struct device *subdrv_dev, int zpos);
- void (*win_enable)(struct device *subdrv_dev, int zpos);
- void (*win_disable)(struct device *subdrv_dev, int zpos);
+ void (*commit)(void *ctx);
+ int (*enable_vblank)(void *ctx);
+ void (*disable_vblank)(void *ctx);
+ void (*wait_for_vblank)(void *ctx);
+ void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
+ void (*win_commit)(void *ctx, int zpos);
+ void (*win_enable)(void *ctx, int zpos);
+ void (*win_disable)(void *ctx, int zpos);
};
/*
@@ -197,12 +194,14 @@ struct exynos_drm_manager_ops {
* these callbacks should be set by specific drivers such fimd
* or hdmi driver and are used to control display devices such as
* analog tv, digital tv and lcd panel and also get timing data for them.
+ * @ctx: A pointer to the manager's implementation specific context
*/
struct exynos_drm_manager {
struct device *dev;
int pipe;
struct exynos_drm_manager_ops *ops;
struct exynos_drm_display_ops *display_ops;
+ void *ctx;
};
struct exynos_drm_g2d_private {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index a9eb2b0..24484ae 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -74,7 +74,7 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
case DRM_MODE_DPMS_ON:
if (manager_ops && manager_ops->apply)
if (!exynos_encoder->updated)
- manager_ops->apply(manager->dev);
+ manager_ops->apply(manager->ctx);
exynos_drm_connector_power(encoder, mode);
exynos_encoder->dpms = mode;
@@ -107,7 +107,7 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder == encoder)
if (manager_ops && manager_ops->mode_fixup)
- manager_ops->mode_fixup(manager->dev, connector,
+ manager_ops->mode_fixup(manager->ctx, connector,
mode, adjusted_mode);
}
@@ -175,7 +175,7 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
manager_ops = manager->ops;
if (manager_ops && manager_ops->mode_set)
- manager_ops->mode_set(manager->dev,
+ manager_ops->mode_set(manager->ctx,
adjusted_mode);
exynos_encoder->old_crtc = encoder->crtc;
@@ -195,7 +195,7 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
struct exynos_drm_manager_ops *manager_ops = manager->ops;
if (manager_ops && manager_ops->commit)
- manager_ops->commit(manager->dev);
+ manager_ops->commit(manager->ctx);
/*
* this will avoid one issue that overlay data is updated to
@@ -341,7 +341,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
if (manager->ops && manager->ops->initialize) {
- ret = manager->ops->initialize(manager->dev, dev);
+ ret = manager->ops->initialize(manager->ctx, dev);
if (ret) {
DRM_ERROR("Manager initialize failed %d\n", ret);
goto error;
@@ -408,7 +408,7 @@ void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
return;
if (manager_ops->enable_vblank)
- manager_ops->enable_vblank(manager->dev);
+ manager_ops->enable_vblank(manager->ctx);
}
void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
@@ -422,7 +422,7 @@ void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
return;
if (manager_ops->disable_vblank)
- manager_ops->disable_vblank(manager->dev);
+ manager_ops->disable_vblank(manager->ctx);
}
void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
@@ -433,7 +433,7 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
int mode = *(int *)data;
if (manager_ops && manager_ops->dpms)
- manager_ops->dpms(manager->dev, mode);
+ manager_ops->dpms(manager->ctx, mode);
/*
* if this condition is ok then it means that the crtc is already
@@ -467,7 +467,7 @@ void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
struct exynos_drm_overlay *overlay = data;
if (manager_ops && manager_ops->win_mode_set)
- manager_ops->win_mode_set(manager->dev, overlay);
+ manager_ops->win_mode_set(manager->ctx, overlay);
}
void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
@@ -481,7 +481,7 @@ void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
zpos = *(int *)data;
if (manager_ops && manager_ops->win_commit)
- manager_ops->win_commit(manager->dev, zpos);
+ manager_ops->win_commit(manager->ctx, zpos);
}
void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
@@ -495,7 +495,7 @@ void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
zpos = *(int *)data;
if (manager_ops && manager_ops->win_enable)
- manager_ops->win_enable(manager->dev, zpos);
+ manager_ops->win_enable(manager->ctx, zpos);
}
void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
@@ -509,5 +509,5 @@ void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
zpos = *(int *)data;
if (manager_ops && manager_ops->win_disable)
- manager_ops->win_disable(manager->dev, zpos);
+ manager_ops->win_disable(manager->ctx, zpos);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 90fcd6f..9c2720a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -106,6 +106,7 @@ struct fimd_win_data {
struct fimd_context {
struct exynos_drm_subdrv subdrv;
+ struct device *dev;
struct drm_device *drm_dev;
int irq;
struct drm_crtc *crtc;
@@ -182,16 +183,15 @@ static struct exynos_drm_display_ops fimd_display_ops = {
.power_on = fimd_display_power_on,
};
-static void fimd_win_mode_set(struct device *dev,
- struct exynos_drm_overlay *overlay)
+static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
{
- struct fimd_context *ctx = get_fimd_context(dev);
+ struct fimd_context *ctx = in_ctx;
struct fimd_win_data *win_data;
int win;
unsigned long offset;
if (!overlay) {
- dev_err(dev, "overlay is NULL\n");
+ DRM_ERROR("overlay is NULL\n");
return;
}
@@ -231,9 +231,8 @@ static void fimd_win_mode_set(struct device *dev,
overlay->fb_width, overlay->crtc_width);
}
-static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
+static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
{
- struct fimd_context *ctx = get_fimd_context(dev);
struct fimd_win_data *win_data = &ctx->win_data[win];
unsigned long val;
@@ -289,9 +288,8 @@ static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
writel(val, ctx->regs + WINCON(win));
}
-static void fimd_win_set_colkey(struct device *dev, unsigned int win)
+static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
{
- struct fimd_context *ctx = get_fimd_context(dev);
unsigned int keycon0 = 0, keycon1 = 0;
keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
@@ -330,9 +328,9 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
writel(val, ctx->regs + reg);
}
-static void fimd_win_commit(struct device *dev, int zpos)
+static void fimd_win_commit(void *in_ctx, int zpos)
{
- struct fimd_context *ctx = get_fimd_context(dev);
+ struct fimd_context *ctx = in_ctx;
struct fimd_win_data *win_data;
int win = zpos;
unsigned long val, alpha, size;
@@ -427,11 +425,11 @@ static void fimd_win_commit(struct device *dev, int zpos)
DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
}
- fimd_win_set_pixfmt(dev, win);
+ fimd_win_set_pixfmt(ctx, win);
/* hardware window 0 doesn't support color key. */
if (win != 0)
- fimd_win_set_colkey(dev, win);
+ fimd_win_set_colkey(ctx, win);
/* wincon */
val = readl(ctx->regs + WINCON(win));
@@ -450,9 +448,9 @@ static void fimd_win_commit(struct device *dev, int zpos)
win_data->enabled = true;
}
-static void fimd_win_disable(struct device *dev, int zpos)
+static void fimd_win_disable(void *in_ctx, int zpos)
{
- struct fimd_context *ctx = get_fimd_context(dev);
+ struct fimd_context *ctx = in_ctx;
struct fimd_win_data *win_data;
int win = zpos;
u32 val;
@@ -491,19 +489,18 @@ static void fimd_win_disable(struct device *dev, int zpos)
win_data->enabled = false;
}
-static int fimd_mgr_initialize(struct device *subdrv_dev,
- struct drm_device *drm_dev)
+static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
{
- struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+ struct fimd_context *ctx = in_ctx;
ctx->drm_dev = drm_dev;
return 0;
}
-static void fimd_dpms(struct device *subdrv_dev, int mode)
+static void fimd_dpms(void *in_ctx, int mode)
{
- struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+ struct fimd_context *ctx = in_ctx;
DRM_DEBUG_KMS("%d\n", mode);
@@ -518,13 +515,13 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
* clk_enable could be called double time.
*/
if (ctx->suspended)
- pm_runtime_get_sync(subdrv_dev);
+ pm_runtime_get_sync(ctx->dev);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
if (!ctx->suspended)
- pm_runtime_put_sync(subdrv_dev);
+ pm_runtime_put_sync(ctx->dev);
break;
default:
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
@@ -534,9 +531,9 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
mutex_unlock(&ctx->lock);
}
-static void fimd_apply(struct device *subdrv_dev)
+static void fimd_apply(void *in_ctx)
{
- struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+ struct fimd_context *ctx = in_ctx;
struct exynos_drm_manager *mgr = ctx->subdrv.manager;
struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
struct fimd_win_data *win_data;
@@ -545,16 +542,16 @@ static void fimd_apply(struct device *subdrv_dev)
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
- mgr_ops->win_commit(subdrv_dev, i);
+ mgr_ops->win_commit(ctx, i);
}
if (mgr_ops && mgr_ops->commit)
- mgr_ops->commit(subdrv_dev);
+ mgr_ops->commit(ctx);
}
-static void fimd_commit(struct device *dev)
+static void fimd_commit(void *in_ctx)
{
- struct fimd_context *ctx = get_fimd_context(dev);
+ struct fimd_context *ctx = in_ctx;
struct exynos_drm_panel_info *panel = &ctx->panel;
struct videomode *vm = &panel->vm;
struct fimd_driver_data *driver_data;
@@ -608,9 +605,9 @@ static void fimd_commit(struct device *dev)
writel(val, ctx->regs + VIDCON0);
}
-static int fimd_enable_vblank(struct device *dev)
+static int fimd_enable_vblank(void *in_ctx)
{
- struct fimd_context *ctx = get_fimd_context(dev);
+ struct fimd_context *ctx = in_ctx;
u32 val;
if (ctx->suspended)
@@ -633,9 +630,9 @@ static int fimd_enable_vblank(struct device *dev)
return 0;
}
-static void fimd_disable_vblank(struct device *dev)
+static void fimd_disable_vblank(void *in_ctx)
{
- struct fimd_context *ctx = get_fimd_context(dev);
+ struct fimd_context *ctx = in_ctx;
u32 val;
if (ctx->suspended)
@@ -651,9 +648,9 @@ static void fimd_disable_vblank(struct device *dev)
}
}
-static void fimd_wait_for_vblank(struct device *dev)
+static void fimd_wait_for_vblank(void *in_ctx)
{
- struct fimd_context *ctx = get_fimd_context(dev);
+ struct fimd_context *ctx = in_ctx;
if (ctx->suspended)
return;
@@ -845,9 +842,9 @@ static void fimd_window_suspend(struct device *dev)
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
win_data->resume = win_data->enabled;
- fimd_win_disable(dev, i);
+ fimd_win_disable(ctx, i);
}
- fimd_wait_for_vblank(dev);
+ fimd_wait_for_vblank(ctx);
}
static void fimd_window_resume(struct device *dev)
@@ -963,6 +960,8 @@ static int fimd_probe(struct platform_device *pdev)
DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
atomic_set(&ctx->wait_vsync_event, 0);
+ fimd_manager.ctx = ctx;
+
subdrv = &ctx->subdrv;
subdrv->dev = dev;
@@ -1042,7 +1041,7 @@ static int fimd_resume(struct device *dev)
* registers but in case of sleep wakeup, it's not.
* so fimd_apply function should be called at here.
*/
- fimd_apply(dev);
+ fimd_apply(ctx);
}
return 0;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index aebcc0e..cddb0c8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -129,11 +129,9 @@ static struct edid *drm_hdmi_get_edid(struct device *dev,
return NULL;
}
-
-static int drm_hdmi_check_mode(struct device *dev,
+static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
struct drm_display_mode *mode)
{
- struct drm_hdmi_context *ctx = to_context(dev);
int ret = 0;
/*
@@ -153,6 +151,14 @@ static int drm_hdmi_check_mode(struct device *dev,
return 0;
}
+static int drm_hdmi_check_mode(struct device *dev,
+ struct drm_display_mode *mode)
+{
+ struct drm_hdmi_context *ctx = to_context(dev);
+
+ return drm_hdmi_check_mode_ctx(ctx, mode);
+}
+
static int drm_hdmi_power_on(struct device *dev, int mode)
{
struct drm_hdmi_context *ctx = to_context(dev);
@@ -172,9 +178,9 @@ static struct exynos_drm_display_ops drm_hdmi_display_ops = {
.power_on = drm_hdmi_power_on,
};
-static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
+static int drm_hdmi_enable_vblank(void *in_ctx)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_hdmi_context *ctx = in_ctx;
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
struct exynos_drm_manager *manager = subdrv->manager;
@@ -185,33 +191,33 @@ static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
return 0;
}
-static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
+static void drm_hdmi_disable_vblank(void *in_ctx)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_hdmi_context *ctx = in_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 device *subdrv_dev)
+static void drm_hdmi_wait_for_vblank(void *in_ctx)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ 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_mode_fixup(struct device *subdrv_dev,
- struct drm_connector *connector,
+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(subdrv_dev, adjusted_mode);
+ mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode);
/* just return if user desired mode exists. */
if (mode_ok == 0)
@@ -222,7 +228,7 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
* to adjusted_mode.
*/
list_for_each_entry(m, &connector->modes, head) {
- mode_ok = drm_hdmi_check_mode(subdrv_dev, m);
+ mode_ok = drm_hdmi_check_mode_ctx(ctx, m);
if (mode_ok == 0) {
struct drm_mode_object base;
@@ -245,35 +251,34 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
}
}
-static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
+static void drm_hdmi_mode_set(void *in_ctx, void *mode)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_hdmi_context *ctx = in_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 device *subdrv_dev,
- unsigned int *width, unsigned int *height)
+static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
+ unsigned int *height)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_hdmi_context *ctx = in_ctx;
if (hdmi_ops && hdmi_ops->get_max_resol)
hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
}
-static void drm_hdmi_commit(struct device *subdrv_dev)
+static void drm_hdmi_commit(void *in_ctx)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ 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(struct device *subdrv_dev,
- struct drm_device *drm_dev)
+static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_hdmi_context *ctx = in_ctx;
int ret = 0;
if (mixer_ops && mixer_ops->initialize)
@@ -285,9 +290,9 @@ static int drm_hdmi_mgr_initialize(struct device *subdrv_dev,
return ret;
}
-static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
+static void drm_hdmi_dpms(void *in_ctx, int mode)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_hdmi_context *ctx = in_ctx;
if (mixer_ops && mixer_ops->dpms)
mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
@@ -296,9 +301,9 @@ static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
}
-static void drm_hdmi_apply(struct device *subdrv_dev)
+static void drm_hdmi_apply(void *in_ctx)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_hdmi_context *ctx = in_ctx;
int i;
for (i = 0; i < MIXER_WIN_NR; i++) {
@@ -312,18 +317,18 @@ static void drm_hdmi_apply(struct device *subdrv_dev)
hdmi_ops->commit(ctx->hdmi_ctx->ctx);
}
-static void drm_mixer_win_mode_set(struct device *subdrv_dev,
- struct exynos_drm_overlay *overlay)
+static void drm_mixer_win_mode_set(void *in_ctx,
+ struct exynos_drm_overlay *overlay)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ 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(struct device *subdrv_dev, int zpos)
+static void drm_mixer_win_commit(void *in_ctx, int zpos)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_hdmi_context *ctx = in_ctx;
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
if (win < 0 || win >= MIXER_WIN_NR) {
@@ -337,9 +342,9 @@ static void drm_mixer_win_commit(struct device *subdrv_dev, int zpos)
ctx->enabled[win] = true;
}
-static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
+static void drm_mixer_win_disable(void *in_ctx, int zpos)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_hdmi_context *ctx = in_ctx;
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
if (win < 0 || win >= MIXER_WIN_NR) {
@@ -425,6 +430,8 @@ static int exynos_drm_hdmi_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
+ hdmi_manager.ctx = ctx;
+
subdrv = &ctx->subdrv;
subdrv->dev = dev;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 15a97ce..a583a74 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -152,9 +152,9 @@ static struct exynos_drm_display_ops vidi_display_ops = {
.power_on = vidi_display_power_on,
};
-static void vidi_dpms(struct device *subdrv_dev, int mode)
+static void vidi_dpms(void *in_ctx, int mode)
{
- struct vidi_context *ctx = get_vidi_context(subdrv_dev);
+ struct vidi_context *ctx = in_ctx;
DRM_DEBUG_KMS("%d\n", mode);
@@ -177,9 +177,9 @@ static void vidi_dpms(struct device *subdrv_dev, int mode)
mutex_unlock(&ctx->lock);
}
-static void vidi_apply(struct device *subdrv_dev)
+static void vidi_apply(void *in_ctx)
{
- struct vidi_context *ctx = get_vidi_context(subdrv_dev);
+ struct vidi_context *ctx = in_ctx;
struct exynos_drm_manager *mgr = ctx->subdrv.manager;
struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
struct vidi_win_data *win_data;
@@ -188,24 +188,24 @@ static void vidi_apply(struct device *subdrv_dev)
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
- mgr_ops->win_commit(subdrv_dev, i);
+ mgr_ops->win_commit(ctx, i);
}
if (mgr_ops && mgr_ops->commit)
- mgr_ops->commit(subdrv_dev);
+ mgr_ops->commit(ctx);
}
-static void vidi_commit(struct device *dev)
+static void vidi_commit(void *in_ctx)
{
- struct vidi_context *ctx = get_vidi_context(dev);
+ struct vidi_context *ctx = in_ctx;
if (ctx->suspended)
return;
}
-static int vidi_enable_vblank(struct device *dev)
+static int vidi_enable_vblank(void *in_ctx)
{
- struct vidi_context *ctx = get_vidi_context(dev);
+ struct vidi_context *ctx = in_ctx;
if (ctx->suspended)
return -EPERM;
@@ -225,9 +225,9 @@ static int vidi_enable_vblank(struct device *dev)
return 0;
}
-static void vidi_disable_vblank(struct device *dev)
+static void vidi_disable_vblank(void *in_ctx)
{
- struct vidi_context *ctx = get_vidi_context(dev);
+ struct vidi_context *ctx = in_ctx;
if (ctx->suspended)
return;
@@ -236,16 +236,15 @@ static void vidi_disable_vblank(struct device *dev)
ctx->vblank_on = false;
}
-static void vidi_win_mode_set(struct device *dev,
- struct exynos_drm_overlay *overlay)
+static void vidi_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
{
- struct vidi_context *ctx = get_vidi_context(dev);
+ struct vidi_context *ctx = in_ctx;
struct vidi_win_data *win_data;
int win;
unsigned long offset;
if (!overlay) {
- dev_err(dev, "overlay is NULL\n");
+ DRM_ERROR("overlay is NULL\n");
return;
}
@@ -289,9 +288,9 @@ static void vidi_win_mode_set(struct device *dev,
overlay->fb_width, overlay->crtc_width);
}
-static void vidi_win_commit(struct device *dev, int zpos)
+static void vidi_win_commit(void *in_ctx, int zpos)
{
- struct vidi_context *ctx = get_vidi_context(dev);
+ struct vidi_context *ctx = in_ctx;
struct vidi_win_data *win_data;
int win = zpos;
@@ -314,9 +313,9 @@ static void vidi_win_commit(struct device *dev, int zpos)
schedule_work(&ctx->work);
}
-static void vidi_win_disable(struct device *dev, int zpos)
+static void vidi_win_disable(void *in_ctx, int zpos)
{
- struct vidi_context *ctx = get_vidi_context(dev);
+ struct vidi_context *ctx = in_ctx;
struct vidi_win_data *win_data;
int win = zpos;
@@ -405,17 +404,19 @@ static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
static int vidi_power_on(struct vidi_context *ctx, bool enable)
{
- struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
- struct device *dev = subdrv->dev;
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ if (enable != false && enable != true)
+ return -EINVAL;
if (enable) {
ctx->suspended = false;
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags))
- vidi_enable_vblank(dev);
+ vidi_enable_vblank(ctx);
- vidi_apply(dev);
+ vidi_apply(ctx);
} else {
ctx->suspended = true;
}
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 07/23] drm/exynos: Pass context in display_ops instead of dev
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (5 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 08/23] drm/exynos: Remove dpms link between encoder/connector Sean Paul
` (16 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch changes the argument of the display_ops from subdrv device to
context. This will allow us to decouple manager and display from subdrv,
as well as decouple crtc from encoder.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_connector.c | 8 +++----
drivers/gpu/drm/exynos/exynos_drm_drv.h | 13 +++++-----
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 2 +-
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 10 ++++----
drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 34 ++++++++++-----------------
drivers/gpu/drm/exynos/exynos_drm_vidi.c | 15 ++++++------
6 files changed, 36 insertions(+), 46 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index b70b123..830fa3d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -53,7 +53,7 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
* because lcd panel has only one mode.
*/
if (display_ops->get_edid) {
- edid = display_ops->get_edid(manager->dev, connector);
+ edid = display_ops->get_edid(manager->ctx, connector);
if (IS_ERR_OR_NULL(edid)) {
ret = PTR_ERR(edid);
edid = NULL;
@@ -77,7 +77,7 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
}
if (display_ops->get_panel)
- panel = display_ops->get_panel(manager->dev);
+ panel = display_ops->get_panel(manager->ctx);
else {
drm_mode_destroy(connector->dev, mode);
return 0;
@@ -113,7 +113,7 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
DRM_DEBUG_KMS("%s\n", __FILE__);
if (display_ops && display_ops->check_mode)
- if (!display_ops->check_mode(manager->dev, mode))
+ if (!display_ops->check_mode(manager->ctx, mode))
ret = MODE_OK;
return ret;
@@ -216,7 +216,7 @@ exynos_drm_connector_detect(struct drm_connector *connector, bool force)
enum drm_connector_status status = connector_status_disconnected;
if (display_ops && display_ops->is_connected) {
- if (display_ops->is_connected(manager->dev))
+ if (display_ops->is_connected(manager->ctx))
status = connector_status_connected;
else
status = connector_status_disconnected;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 0bd444f..cbf8fcf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -132,13 +132,12 @@ struct exynos_drm_overlay {
*/
struct exynos_drm_display_ops {
enum exynos_drm_output_type type;
- int (*initialize)(struct device *dev, struct drm_device *drm_dev);
- bool (*is_connected)(struct device *dev);
- struct edid *(*get_edid)(struct device *dev,
- struct drm_connector *connector);
- void *(*get_panel)(struct device *dev);
- int (*check_mode)(struct device *dev, struct drm_display_mode *mode);
- int (*power_on)(struct device *dev, int mode);
+ int (*initialize)(void *ctx, struct drm_device *drm_dev);
+ bool (*is_connected)(void *ctx);
+ struct edid *(*get_edid)(void *ctx, struct drm_connector *connector);
+ void *(*get_panel)(void *ctx);
+ int (*check_mode)(void *ctx, struct drm_display_mode *mode);
+ int (*power_on)(void *ctx, int mode);
};
/*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 24484ae..e0c50a8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -349,7 +349,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
}
if (manager->display_ops && manager->display_ops->initialize) {
- ret = manager->display_ops->initialize(manager->dev, dev);
+ ret = manager->display_ops->initialize(manager->ctx, dev);
if (ret) {
DRM_ERROR("Display initialize failed %d\n", ret);
goto error;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 9c2720a..a8f9772 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -147,28 +147,28 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
return (struct fimd_driver_data *)of_id->data;
}
-static bool fimd_display_is_connected(struct device *dev)
+static bool fimd_display_is_connected(void *in_ctx)
{
/* TODO. */
return true;
}
-static void *fimd_get_panel(struct device *dev)
+static void *fimd_get_panel(void *in_ctx)
{
- struct fimd_context *ctx = get_fimd_context(dev);
+ struct fimd_context *ctx = in_ctx;
return &ctx->panel;
}
-static int fimd_check_mode(struct device *dev, struct drm_display_mode *mode)
+static int fimd_check_mode(void *in_ctx, struct drm_display_mode *mode)
{
/* TODO. */
return 0;
}
-static int fimd_display_power_on(struct device *dev, int mode)
+static int fimd_display_power_on(void *in_ctx, int mode)
{
/* TODO */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index cddb0c8..689758d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -97,10 +97,9 @@ void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
mixer_ops = ops;
}
-static int drm_hdmi_display_initialize(struct device *dev,
- struct drm_device *drm_dev)
+static int drm_hdmi_display_initialize(void *in_ctx, struct drm_device *drm_dev)
{
- struct drm_hdmi_context *ctx = to_context(dev);
+ struct drm_hdmi_context *ctx = in_ctx;
if (hdmi_ops && hdmi_ops->initialize)
return hdmi_ops->initialize(ctx->hdmi_ctx->ctx, drm_dev);
@@ -109,9 +108,9 @@ static int drm_hdmi_display_initialize(struct device *dev,
}
-static bool drm_hdmi_is_connected(struct device *dev)
+static bool drm_hdmi_is_connected(void *in_ctx)
{
- struct drm_hdmi_context *ctx = to_context(dev);
+ struct drm_hdmi_context *ctx = in_ctx;
if (hdmi_ops && hdmi_ops->is_connected)
return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
@@ -119,19 +118,20 @@ static bool drm_hdmi_is_connected(struct device *dev)
return false;
}
-static struct edid *drm_hdmi_get_edid(struct device *dev,
+static struct edid *drm_hdmi_get_edid(void *in_ctx,
struct drm_connector *connector)
{
- struct drm_hdmi_context *ctx = to_context(dev);
+ 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 int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
- struct drm_display_mode *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;
/*
@@ -151,17 +151,9 @@ static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
return 0;
}
-static int drm_hdmi_check_mode(struct device *dev,
- struct drm_display_mode *mode)
+static int drm_hdmi_power_on(void *in_ctx, int mode)
{
- struct drm_hdmi_context *ctx = to_context(dev);
-
- return drm_hdmi_check_mode_ctx(ctx, mode);
-}
-
-static int drm_hdmi_power_on(struct device *dev, int mode)
-{
- struct drm_hdmi_context *ctx = to_context(dev);
+ struct drm_hdmi_context *ctx = in_ctx;
if (hdmi_ops && hdmi_ops->power_on)
return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
@@ -217,7 +209,7 @@ static void drm_hdmi_mode_fixup(void *in_ctx, struct drm_connector *connector,
drm_mode_set_crtcinfo(adjusted_mode, 0);
- mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode);
+ mode_ok = drm_hdmi_check_mode(ctx, adjusted_mode);
/* just return if user desired mode exists. */
if (mode_ok == 0)
@@ -228,7 +220,7 @@ static void drm_hdmi_mode_fixup(void *in_ctx, struct drm_connector *connector,
* to adjusted_mode.
*/
list_for_each_entry(m, &connector->modes, head) {
- mode_ok = drm_hdmi_check_mode_ctx(ctx, m);
+ mode_ok = drm_hdmi_check_mode(ctx, m);
if (mode_ok == 0) {
struct drm_mode_object base;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index a583a74..1220937 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -85,9 +85,9 @@ static const char fake_edid_info[] = {
0x00, 0x00, 0x00, 0x06
};
-static bool vidi_display_is_connected(struct device *dev)
+static bool vidi_display_is_connected(void *in_ctx)
{
- struct vidi_context *ctx = get_vidi_context(dev);
+ struct vidi_context *ctx = in_ctx;
/*
* connection request would come from user side
@@ -96,10 +96,9 @@ static bool vidi_display_is_connected(struct device *dev)
return ctx->connected ? true : false;
}
-static struct edid *vidi_get_edid(struct device *dev,
- struct drm_connector *connector)
+static struct edid *vidi_get_edid(void *in_ctx, struct drm_connector *connector)
{
- struct vidi_context *ctx = get_vidi_context(dev);
+ struct vidi_context *ctx = in_ctx;
struct edid *edid;
int edid_len;
@@ -122,21 +121,21 @@ static struct edid *vidi_get_edid(struct device *dev,
return edid;
}
-static void *vidi_get_panel(struct device *dev)
+static void *vidi_get_panel(void *in_ctx)
{
/* TODO. */
return NULL;
}
-static int vidi_check_mode(struct device *dev, struct drm_display_mode *mode)
+static int vidi_check_mode(void *in_ctx, struct drm_display_mode *mode)
{
/* TODO. */
return 0;
}
-static int vidi_display_power_on(struct device *dev, int mode)
+static int vidi_display_power_on(void *in_ctx, int mode)
{
/* TODO */
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 08/23] drm/exynos: Remove dpms link between encoder/connector
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (6 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 07/23] drm/exynos: Pass context in display_ops " Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 09/23] drm/exynos: Rename display_op power_on to dpms Sean Paul
` (15 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch removes the call from encoder dpms into connector dpms (which
will then call back into encoder dpms through the helper function). The
callback is likely to keep connector->dpms in the right state when
initiating dpms from crtc or encoder, but this isn't the right way to do
it. This patch is the first step towards rationalizing power management
in the exynos drm driver.
This patch also removes the apply() callback from the dpms path. It's
incorrect to assume apply should be called from dpms. If it's a
requirement for the individual hardware drivers, they should call it
internally.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_connector.c | 42 ++-------------------
drivers/gpu/drm/exynos/exynos_drm_connector.h | 4 --
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 53 ++-------------------------
3 files changed, 7 insertions(+), 92 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 830fa3d..2a5639a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -26,7 +26,6 @@ struct exynos_drm_connector {
struct drm_connector drm_connector;
uint32_t encoder_id;
struct exynos_drm_manager *manager;
- uint32_t dpms;
};
static int exynos_drm_connector_get_modes(struct drm_connector *connector)
@@ -119,7 +118,8 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
return ret;
}
-struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
+static struct drm_encoder *exynos_drm_best_encoder(
+ struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct exynos_drm_connector *exynos_connector =
@@ -146,41 +146,6 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
.best_encoder = exynos_drm_best_encoder,
};
-void exynos_drm_display_power(struct drm_connector *connector, int mode)
-{
- struct drm_encoder *encoder = exynos_drm_best_encoder(connector);
- struct exynos_drm_connector *exynos_connector;
- struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
- struct exynos_drm_display_ops *display_ops = manager->display_ops;
-
- exynos_connector = to_exynos_connector(connector);
-
- if (exynos_connector->dpms == mode) {
- DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
- return;
- }
-
- if (display_ops && display_ops->power_on)
- display_ops->power_on(manager->dev, mode);
-
- exynos_connector->dpms = mode;
-}
-
-static void exynos_drm_connector_dpms(struct drm_connector *connector,
- int mode)
-{
- /*
- * in case that drm_crtc_helper_set_mode() is called,
- * encoder/crtc->funcs->dpms() will be just returned
- * because they already were DRM_MODE_DPMS_ON so only
- * exynos_drm_display_power() will be called.
- */
- drm_helper_connector_dpms(connector, mode);
-
- exynos_drm_display_power(connector, mode);
-
-}
-
static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
unsigned int max_width, unsigned int max_height)
{
@@ -236,7 +201,7 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector)
}
static struct drm_connector_funcs exynos_connector_funcs = {
- .dpms = exynos_drm_connector_dpms,
+ .dpms = drm_helper_connector_dpms,
.fill_modes = exynos_drm_connector_fill_modes,
.detect = exynos_drm_connector_detect,
.destroy = exynos_drm_connector_destroy,
@@ -281,7 +246,6 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
exynos_connector->encoder_id = encoder->base.id;
exynos_connector->manager = manager;
- exynos_connector->dpms = DRM_MODE_DPMS_OFF;
connector->dpms = DRM_MODE_DPMS_OFF;
connector->encoder = encoder;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h
index 547c6b5..4eb20d7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.h
@@ -17,8 +17,4 @@
struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
struct drm_encoder *encoder);
-struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector);
-
-void exynos_drm_display_power(struct drm_connector *connector, int mode);
-
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index e0c50a8..f701d3e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -29,37 +29,20 @@
* @manager: specific encoder has its own manager to control a hardware
* appropriately and we can access a hardware drawing on this manager.
* @dpms: store the encoder dpms value.
- * @updated: indicate whether overlay data updating is needed or not.
*/
struct exynos_drm_encoder {
struct drm_crtc *old_crtc;
struct drm_encoder drm_encoder;
struct exynos_drm_manager *manager;
int dpms;
- bool updated;
};
-static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode)
-{
- struct drm_device *dev = encoder->dev;
- struct drm_connector *connector;
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (exynos_drm_best_encoder(connector) == encoder) {
- DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
- connector->base.id, mode);
-
- exynos_drm_display_power(connector, mode);
- }
- }
-}
-
static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+ struct exynos_drm_display_ops *display_ops = manager->display_ops;
DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
@@ -68,30 +51,10 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
return;
}
- mutex_lock(&dev->struct_mutex);
-
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- if (manager_ops && manager_ops->apply)
- if (!exynos_encoder->updated)
- manager_ops->apply(manager->ctx);
-
- exynos_drm_connector_power(encoder, mode);
- exynos_encoder->dpms = mode;
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
- exynos_drm_connector_power(encoder, mode);
- exynos_encoder->dpms = mode;
- exynos_encoder->updated = false;
- break;
- default:
- DRM_ERROR("unspecified mode %d\n", mode);
- break;
- }
+ if (display_ops && display_ops->power_on)
+ display_ops->power_on(manager->ctx, mode);
- mutex_unlock(&dev->struct_mutex);
+ exynos_encoder->dpms = mode;
}
static bool
@@ -198,14 +161,6 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
manager_ops->commit(manager->ctx);
/*
- * this will avoid one issue that overlay data is updated to
- * real hardware two times.
- * And this variable will be used to check if the data was
- * already updated or not by exynos_drm_encoder_dpms function.
- */
- exynos_encoder->updated = true;
-
- /*
* In case of setcrtc, there is no way to update encoder's dpms
* so update it here.
*/
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 09/23] drm/exynos: Rename display_op power_on to dpms
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (7 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 08/23] drm/exynos: Remove dpms link between encoder/connector Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 10/23] drm/exynos: Don't keep dpms state in encoder Sean Paul
` (14 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch renames the display_op power_on to dpms to accurately reflect
what the function does.
The side-effect of this patch is that the new hdmi dpms callback is now
invoked twice in the dpms path. This is safe and will be dealt with when
the exynos_drm shim goes away.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_drv.h | 4 ++--
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 4 ++--
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 8 --------
drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 10 ++++------
drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 3 +--
drivers/gpu/drm/exynos/exynos_drm_vidi.c | 8 --------
drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +-
7 files changed, 10 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index cbf8fcf..be3d352 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -128,7 +128,7 @@ struct exynos_drm_overlay {
* @get_edid: get edid modes from display driver.
* @get_panel: get panel object from display driver.
* @check_mode: check if mode is valid or not.
- * @power_on: display device on or off.
+ * @dpms: display device on or off.
*/
struct exynos_drm_display_ops {
enum exynos_drm_output_type type;
@@ -137,7 +137,7 @@ struct exynos_drm_display_ops {
struct edid *(*get_edid)(void *ctx, struct drm_connector *connector);
void *(*get_panel)(void *ctx);
int (*check_mode)(void *ctx, struct drm_display_mode *mode);
- int (*power_on)(void *ctx, int mode);
+ void (*dpms)(void *ctx, int mode);
};
/*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index f701d3e..7206114 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -51,8 +51,8 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
return;
}
- if (display_ops && display_ops->power_on)
- display_ops->power_on(manager->ctx, mode);
+ if (display_ops && display_ops->dpms)
+ display_ops->dpms(manager->ctx, mode);
exynos_encoder->dpms = mode;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index a8f9772..838c47d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -168,19 +168,11 @@ static int fimd_check_mode(void *in_ctx, struct drm_display_mode *mode)
return 0;
}
-static int fimd_display_power_on(void *in_ctx, int mode)
-{
- /* TODO */
-
- return 0;
-}
-
static struct exynos_drm_display_ops fimd_display_ops = {
.type = EXYNOS_DISPLAY_TYPE_LCD,
.is_connected = fimd_display_is_connected,
.get_panel = fimd_get_panel,
.check_mode = fimd_check_mode,
- .power_on = fimd_display_power_on,
};
static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 689758d..8173e44 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -151,14 +151,12 @@ static int drm_hdmi_check_mode(void *in_ctx, struct drm_display_mode *mode)
return 0;
}
-static int drm_hdmi_power_on(void *in_ctx, int mode)
+static void drm_hdmi_display_dpms(void *in_ctx, int mode)
{
struct drm_hdmi_context *ctx = in_ctx;
- if (hdmi_ops && hdmi_ops->power_on)
- return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
-
- return 0;
+ if (hdmi_ops && hdmi_ops->dpms)
+ hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
}
static struct exynos_drm_display_ops drm_hdmi_display_ops = {
@@ -167,7 +165,7 @@ static struct exynos_drm_display_ops drm_hdmi_display_ops = {
.is_connected = drm_hdmi_is_connected,
.get_edid = drm_hdmi_get_edid,
.check_mode = drm_hdmi_check_mode,
- .power_on = drm_hdmi_power_on,
+ .dpms = drm_hdmi_display_dpms,
};
static int drm_hdmi_enable_vblank(void *in_ctx)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index cf7b1da..923239b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -33,14 +33,13 @@ struct exynos_hdmi_ops {
struct edid *(*get_edid)(void *ctx,
struct drm_connector *connector);
int (*check_mode)(void *ctx, struct drm_display_mode *mode);
- int (*power_on)(void *ctx, int 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);
- void (*dpms)(void *ctx, int mode);
};
struct exynos_mixer_ops {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 1220937..35ee49b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -135,20 +135,12 @@ static int vidi_check_mode(void *in_ctx, struct drm_display_mode *mode)
return 0;
}
-static int vidi_display_power_on(void *in_ctx, int mode)
-{
- /* TODO */
-
- return 0;
-}
-
static struct exynos_drm_display_ops vidi_display_ops = {
.type = EXYNOS_DISPLAY_TYPE_VIDI,
.is_connected = vidi_display_is_connected,
.get_edid = vidi_get_edid,
.get_panel = vidi_get_panel,
.check_mode = vidi_check_mode,
- .power_on = vidi_display_power_on,
};
static void vidi_dpms(void *in_ctx, int mode)
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index a3fba8e..037c6fe 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1760,12 +1760,12 @@ static struct exynos_hdmi_ops hdmi_ops = {
.is_connected = hdmi_is_connected,
.get_edid = hdmi_get_edid,
.check_mode = hdmi_check_mode,
+ .dpms = hdmi_dpms,
/* manager */
.mode_set = hdmi_mode_set,
.get_max_resol = hdmi_get_max_resol,
.commit = hdmi_commit,
- .dpms = hdmi_dpms,
};
static irqreturn_t hdmi_irq_thread(int irq, void *arg)
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 10/23] drm/exynos: Don't keep dpms state in encoder
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (8 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 09/23] drm/exynos: Rename display_op power_on to dpms Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 11/23] drm/exynos: Use unsigned long for possible_crtcs Sean Paul
` (13 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch removes the dpms state tracking in encoder. This
state is at best confusing and at worst incorrect since the display
drivers can turn on and off without propagating the value.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 7206114..11d2567 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -28,33 +28,22 @@
* @drm_encoder: encoder object.
* @manager: specific encoder has its own manager to control a hardware
* appropriately and we can access a hardware drawing on this manager.
- * @dpms: store the encoder dpms value.
*/
struct exynos_drm_encoder {
struct drm_crtc *old_crtc;
struct drm_encoder drm_encoder;
struct exynos_drm_manager *manager;
- int dpms;
};
static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
{
- struct drm_device *dev = encoder->dev;
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
- struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display_ops *display_ops = manager->display_ops;
DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
- if (exynos_encoder->dpms == mode) {
- DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
- return;
- }
-
if (display_ops && display_ops->dpms)
display_ops->dpms(manager->ctx, mode);
-
- exynos_encoder->dpms = mode;
}
static bool
@@ -159,12 +148,6 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
if (manager_ops && manager_ops->commit)
manager_ops->commit(manager->ctx);
-
- /*
- * In case of setcrtc, there is no way to update encoder's dpms
- * so update it here.
- */
- exynos_encoder->dpms = DRM_MODE_DPMS_ON;
}
void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
@@ -283,7 +266,6 @@ exynos_drm_encoder_create(struct drm_device *dev,
if (!exynos_encoder)
return NULL;
- exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
exynos_encoder->manager = manager;
encoder = &exynos_encoder->drm_encoder;
encoder->possible_crtcs = possible_crtcs;
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 11/23] drm/exynos: Use unsigned long for possible_crtcs
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (9 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 10/23] drm/exynos: Don't keep dpms state in encoder Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 12/23] drm/exynos: Split manager/display/subdrv Sean Paul
` (12 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
Change all instances of possible_crtcs in the exynos drm driver to be
unsigned long. This matches the type used in the drm layer.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_drv.c | 2 +-
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 2 +-
drivers/gpu/drm/exynos/exynos_drm_encoder.h | 2 +-
drivers/gpu/drm/exynos/exynos_drm_plane.c | 2 +-
drivers/gpu/drm/exynos/exynos_drm_plane.h | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index bb82ef7..617748e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -84,7 +84,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
for (nr = 0; nr < MAX_PLANE; nr++) {
struct drm_plane *plane;
- unsigned int possible_crtcs = (1 << MAX_CRTC) - 1;
+ unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
plane = exynos_plane_init(dev, possible_crtcs, false);
if (!plane)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 11d2567..c417c90 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -250,7 +250,7 @@ void exynos_drm_encoder_setup(struct drm_device *dev)
struct drm_encoder *
exynos_drm_encoder_create(struct drm_device *dev,
struct exynos_drm_manager *manager,
- unsigned int possible_crtcs)
+ unsigned long possible_crtcs)
{
struct drm_encoder *encoder;
struct exynos_drm_encoder *exynos_encoder;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
index 89e2fb0..0f3e5e2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
@@ -19,7 +19,7 @@ struct exynos_drm_manager;
void exynos_drm_encoder_setup(struct drm_device *dev);
struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
struct exynos_drm_manager *mgr,
- unsigned int possible_crtcs);
+ unsigned long possible_crtcs);
struct exynos_drm_manager *
exynos_drm_get_manager(struct drm_encoder *encoder);
void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index fcb0652..cff3aed 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -259,7 +259,7 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
}
struct drm_plane *exynos_plane_init(struct drm_device *dev,
- unsigned int possible_crtcs, bool priv)
+ unsigned long possible_crtcs, bool priv)
{
struct exynos_plane *exynos_plane;
int err;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h
index 8831245..84d464c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h
@@ -17,4 +17,4 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
void exynos_plane_commit(struct drm_plane *plane);
void exynos_plane_dpms(struct drm_plane *plane, int mode);
struct drm_plane *exynos_plane_init(struct drm_device *dev,
- unsigned int possible_crtcs, bool priv);
+ unsigned long possible_crtcs, bool priv);
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (10 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 11/23] drm/exynos: Use unsigned long for possible_crtcs Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-12 0:42 ` Inki Dae
2013-10-14 15:24 ` Inki Dae
2013-10-11 0:30 ` [PATCH 13/23] drm/exynos: hdmi: remove the i2c drivers and use devtree Sean Paul
` (11 subsequent siblings)
23 siblings, 2 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch splits display and manager from subdrv. The result is that
crtc functions can directly call into manager callbacks and encoder
functions can directly call into display callbacks. This will allow
us to remove the exynos_drm_hdmi shim and support mixer/hdmi & fimd/dp
with common code.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_connector.c | 50 ++---
drivers/gpu/drm/exynos/exynos_drm_core.c | 181 +++++++++++++-----
drivers/gpu/drm/exynos/exynos_drm_crtc.c | 115 +++++++++---
drivers/gpu/drm/exynos/exynos_drm_crtc.h | 20 +-
drivers/gpu/drm/exynos/exynos_drm_drv.c | 29 +--
drivers/gpu/drm/exynos/exynos_drm_drv.h | 87 +++++----
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 257 ++++----------------------
drivers/gpu/drm/exynos/exynos_drm_encoder.h | 18 +-
drivers/gpu/drm/exynos/exynos_drm_fb.c | 4 +-
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 153 +++++++--------
drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 218 ++++++++++------------
drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 2 +
drivers/gpu/drm/exynos/exynos_drm_plane.c | 15 +-
13 files changed, 547 insertions(+), 602 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 2a5639a..782a9e1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -23,26 +23,20 @@
drm_connector)
struct exynos_drm_connector {
- struct drm_connector drm_connector;
- uint32_t encoder_id;
- struct exynos_drm_manager *manager;
+ struct drm_connector drm_connector;
+ uint32_t encoder_id;
+ struct exynos_drm_display *display;
};
static int exynos_drm_connector_get_modes(struct drm_connector *connector)
{
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
- struct exynos_drm_manager *manager = exynos_connector->manager;
- struct exynos_drm_display_ops *display_ops = manager->display_ops;
+ struct exynos_drm_display *display = exynos_connector->display;
struct edid *edid = NULL;
unsigned int count = 0;
int ret;
- if (!display_ops) {
- DRM_DEBUG_KMS("display_ops is null.\n");
- return 0;
- }
-
/*
* if get_edid() exists then get_edid() callback of hdmi side
* is called to get edid data through i2c interface else
@@ -51,8 +45,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
* P.S. in case of lcd panel, count is always 1 if success
* because lcd panel has only one mode.
*/
- if (display_ops->get_edid) {
- edid = display_ops->get_edid(manager->ctx, connector);
+ if (display->ops->get_edid) {
+ edid = display->ops->get_edid(display->ctx, connector);
if (IS_ERR_OR_NULL(edid)) {
ret = PTR_ERR(edid);
edid = NULL;
@@ -75,8 +69,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
return 0;
}
- if (display_ops->get_panel)
- panel = display_ops->get_panel(manager->ctx);
+ if (display->ops->get_panel)
+ panel = display->ops->get_panel(display->ctx);
else {
drm_mode_destroy(connector->dev, mode);
return 0;
@@ -105,14 +99,13 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
{
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
- struct exynos_drm_manager *manager = exynos_connector->manager;
- struct exynos_drm_display_ops *display_ops = manager->display_ops;
+ struct exynos_drm_display *display = exynos_connector->display;
int ret = MODE_BAD;
DRM_DEBUG_KMS("%s\n", __FILE__);
- if (display_ops && display_ops->check_mode)
- if (!display_ops->check_mode(manager->ctx, mode))
+ if (display->ops->check_mode)
+ if (!display->ops->check_mode(display->ctx, mode))
ret = MODE_OK;
return ret;
@@ -151,8 +144,7 @@ static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
{
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
- struct exynos_drm_manager *manager = exynos_connector->manager;
- struct exynos_drm_manager_ops *ops = manager->ops;
+ struct exynos_drm_display *display = exynos_connector->display;
unsigned int width, height;
width = max_width;
@@ -162,8 +154,8 @@ static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
* if specific driver want to find desired_mode using maxmum
* resolution then get max width and height from that driver.
*/
- if (ops && ops->get_max_resol)
- ops->get_max_resol(manager->ctx, &width, &height);
+ if (display->ops->get_max_resol)
+ display->ops->get_max_resol(display->ctx, &width, &height);
return drm_helper_probe_single_connector_modes(connector, width,
height);
@@ -175,13 +167,11 @@ exynos_drm_connector_detect(struct drm_connector *connector, bool force)
{
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
- struct exynos_drm_manager *manager = exynos_connector->manager;
- struct exynos_drm_display_ops *display_ops =
- manager->display_ops;
+ struct exynos_drm_display *display = exynos_connector->display;
enum drm_connector_status status = connector_status_disconnected;
- if (display_ops && display_ops->is_connected) {
- if (display_ops->is_connected(manager->ctx))
+ if (display->ops->is_connected) {
+ if (display->ops->is_connected(display->ctx))
status = connector_status_connected;
else
status = connector_status_disconnected;
@@ -211,7 +201,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
struct drm_encoder *encoder)
{
struct exynos_drm_connector *exynos_connector;
- struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
+ struct exynos_drm_display *display = exynos_drm_get_display(encoder);
struct drm_connector *connector;
int type;
int err;
@@ -222,7 +212,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
connector = &exynos_connector->drm_connector;
- switch (manager->display_ops->type) {
+ switch (display->type) {
case EXYNOS_DISPLAY_TYPE_HDMI:
type = DRM_MODE_CONNECTOR_HDMIA;
connector->interlace_allowed = true;
@@ -245,7 +235,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
goto err_connector;
exynos_connector->encoder_id = encoder->base.id;
- exynos_connector->manager = manager;
+ exynos_connector->display = display;
connector->dpms = DRM_MODE_DPMS_OFF;
connector->encoder = encoder;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index 08ca4f9..12e60f2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -16,11 +16,14 @@
#include <drm/drmP.h>
#include <drm/bridge/ptn3460.h>
#include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_connector.h"
#include "exynos_drm_fbdev.h"
static LIST_HEAD(exynos_drm_subdrv_list);
+static LIST_HEAD(exynos_drm_manager_list);
+static LIST_HEAD(exynos_drm_display_list);
struct bridge_init {
struct i2c_client *client;
@@ -57,24 +60,28 @@ static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
}
static int exynos_drm_create_enc_conn(struct drm_device *dev,
- struct exynos_drm_subdrv *subdrv)
+ struct exynos_drm_display *display)
{
struct drm_encoder *encoder;
struct drm_connector *connector;
+ struct exynos_drm_manager *manager;
int ret;
+ unsigned long possible_crtcs = 0;
- subdrv->manager->dev = subdrv->dev;
+ /* Find possible crtcs for this display */
+ list_for_each_entry(manager, &exynos_drm_manager_list, list)
+ if (manager->type == display->type)
+ possible_crtcs |= 1 << manager->pipe;
/* create and initialize a encoder for this sub driver. */
- encoder = exynos_drm_encoder_create(dev, subdrv->manager,
- (1 << MAX_CRTC) - 1);
+ encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
if (!encoder) {
DRM_ERROR("failed to create encoder\n");
return -EFAULT;
}
- subdrv->encoder = encoder;
+ display->encoder = encoder;
- if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) {
+ if (display->type == EXYNOS_DISPLAY_TYPE_LCD) {
ret = exynos_drm_attach_lcd_bridge(dev, encoder);
if (ret)
return 0;
@@ -91,7 +98,7 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev,
goto err_destroy_encoder;
}
- subdrv->connector = connector;
+ display->connector = connector;
return 0;
@@ -100,21 +107,6 @@ err_destroy_encoder:
return ret;
}
-static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv)
-{
- if (subdrv->encoder) {
- struct drm_encoder *encoder = subdrv->encoder;
- encoder->funcs->destroy(encoder);
- subdrv->encoder = NULL;
- }
-
- if (subdrv->connector) {
- struct drm_connector *connector = subdrv->connector;
- connector->funcs->destroy(connector);
- subdrv->connector = NULL;
- }
-}
-
static int exynos_drm_subdrv_probe(struct drm_device *dev,
struct exynos_drm_subdrv *subdrv)
{
@@ -146,10 +138,98 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev,
subdrv->remove(dev, subdrv->dev);
}
+int exynos_drm_initialize_managers(struct drm_device *dev)
+{
+ struct exynos_drm_manager *manager, *n;
+ int ret, pipe = 0;
+
+ list_for_each_entry(manager, &exynos_drm_manager_list, list) {
+ if (manager->ops->initialize) {
+ ret = manager->ops->initialize(manager->ctx, dev, pipe);
+ if (ret) {
+ DRM_ERROR("Mgr init [%d] failed with %d\n",
+ manager->type, ret);
+ goto err;
+ }
+ }
+
+ manager->drm_dev = dev;
+ manager->pipe = pipe++;
+
+ ret = exynos_drm_crtc_create(manager);
+ if (ret) {
+ DRM_ERROR("CRTC create [%d] failed with %d\n",
+ manager->type, ret);
+ goto err;
+ }
+ }
+ return 0;
+
+err:
+ list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) {
+ if (pipe-- > 0)
+ exynos_drm_manager_unregister(manager);
+ else
+ list_del(&manager->list);
+ }
+ return ret;
+}
+
+void exynos_drm_remove_managers(struct drm_device *dev)
+{
+ struct exynos_drm_manager *manager, *n;
+
+ list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list)
+ exynos_drm_manager_unregister(manager);
+}
+
+int exynos_drm_initialize_displays(struct drm_device *dev)
+{
+ struct exynos_drm_display *display, *n;
+ int ret, initialized = 0;
+
+ list_for_each_entry(display, &exynos_drm_display_list, list) {
+ if (display->ops->initialize) {
+ ret = display->ops->initialize(display->ctx, dev);
+ if (ret) {
+ DRM_ERROR("Display init [%d] failed with %d\n",
+ display->type, ret);
+ goto err;
+ }
+ }
+
+ initialized++;
+
+ ret = exynos_drm_create_enc_conn(dev, display);
+ if (ret) {
+ DRM_ERROR("Encoder create [%d] failed with %d\n",
+ display->type, ret);
+ goto err;
+ }
+ }
+ return 0;
+
+err:
+ list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) {
+ if (initialized-- > 0)
+ exynos_drm_display_unregister(display);
+ else
+ list_del(&display->list);
+ }
+ return ret;
+}
+
+void exynos_drm_remove_displays(struct drm_device *dev)
+{
+ struct exynos_drm_display *display, *n;
+
+ list_for_each_entry_safe(display, n, &exynos_drm_display_list, list)
+ exynos_drm_display_unregister(display);
+}
+
int exynos_drm_device_register(struct drm_device *dev)
{
struct exynos_drm_subdrv *subdrv, *n;
- unsigned int fine_cnt = 0;
int err;
if (!dev)
@@ -162,30 +242,8 @@ int exynos_drm_device_register(struct drm_device *dev)
list_del(&subdrv->list);
continue;
}
-
- /*
- * if manager is null then it means that this sub driver
- * doesn't need encoder and connector.
- */
- if (!subdrv->manager) {
- fine_cnt++;
- continue;
- }
-
- err = exynos_drm_create_enc_conn(dev, subdrv);
- if (err) {
- DRM_DEBUG("failed to create encoder and connector.\n");
- exynos_drm_subdrv_remove(dev, subdrv);
- list_del(&subdrv->list);
- continue;
- }
-
- fine_cnt++;
}
- if (!fine_cnt)
- return -EINVAL;
-
return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_device_register);
@@ -201,13 +259,44 @@ int exynos_drm_device_unregister(struct drm_device *dev)
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
exynos_drm_subdrv_remove(dev, subdrv);
- exynos_drm_destroy_enc_conn(subdrv);
}
return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
+int exynos_drm_manager_register(struct exynos_drm_manager *manager)
+{
+ BUG_ON(!manager->ops);
+ list_add_tail(&manager->list, &exynos_drm_manager_list);
+ return 0;
+}
+
+int exynos_drm_manager_unregister(struct exynos_drm_manager *manager)
+{
+ if (manager->ops->remove)
+ manager->ops->remove(manager->ctx);
+
+ list_del(&manager->list);
+ return 0;
+}
+
+int exynos_drm_display_register(struct exynos_drm_display *display)
+{
+ BUG_ON(!display->ops);
+ list_add_tail(&display->list, &exynos_drm_display_list);
+ return 0;
+}
+
+int exynos_drm_display_unregister(struct exynos_drm_display *display)
+{
+ if (display->ops->remove)
+ display->ops->remove(display->ctx);
+
+ list_del(&display->list);
+ return 0;
+}
+
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
{
if (!subdrv)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index ebc0150..9f6ada4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -33,6 +33,7 @@ enum exynos_crtc_mode {
*
* @drm_crtc: crtc object.
* @drm_plane: pointer of private plane object for this crtc
+ * @manager: the manager associated with this crtc
* @pipe: a crtc index created at load() with a new crtc object creation
* and the crtc object would be set to private->crtc array
* to get a crtc object corresponding to this pipe from private->crtc
@@ -46,6 +47,7 @@ enum exynos_crtc_mode {
struct exynos_drm_crtc {
struct drm_crtc drm_crtc;
struct drm_plane *plane;
+ struct exynos_drm_manager *manager;
unsigned int pipe;
unsigned int dpms;
enum exynos_crtc_mode mode;
@@ -56,6 +58,7 @@ struct exynos_drm_crtc {
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+ struct exynos_drm_manager *manager = exynos_crtc->manager;
DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
@@ -71,7 +74,9 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
drm_vblank_off(crtc->dev, exynos_crtc->pipe);
}
- exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms);
+ if (manager->ops->dpms)
+ manager->ops->dpms(manager->ctx, mode);
+
exynos_crtc->dpms = mode;
}
@@ -83,9 +88,15 @@ static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+ struct exynos_drm_manager *manager = exynos_crtc->manager;
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+
exynos_plane_commit(exynos_crtc->plane);
+
+ if (manager->ops->commit)
+ manager->ops->commit(manager->ctx);
+
exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
}
@@ -107,7 +118,6 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_plane *plane = exynos_crtc->plane;
unsigned int crtc_w;
unsigned int crtc_h;
- int pipe = exynos_crtc->pipe;
int ret;
/*
@@ -127,8 +137,6 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
plane->crtc = crtc;
plane->fb = crtc->fb;
- exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
-
return 0;
}
@@ -318,21 +326,24 @@ static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
drm_object_attach_property(&crtc->base, prop, 0);
}
-int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
+int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
{
struct exynos_drm_crtc *exynos_crtc;
- struct exynos_drm_private *private = dev->dev_private;
+ struct exynos_drm_private *private = manager->drm_dev->dev_private;
struct drm_crtc *crtc;
exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
if (!exynos_crtc)
return -ENOMEM;
- exynos_crtc->pipe = nr;
- exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
init_waitqueue_head(&exynos_crtc->pending_flip_queue);
atomic_set(&exynos_crtc->pending_flip, 0);
- exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
+
+ exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
+ exynos_crtc->manager = manager;
+ exynos_crtc->pipe = manager->pipe;
+ exynos_crtc->plane = exynos_plane_init(manager->drm_dev,
+ 1 << manager->pipe, true);
if (!exynos_crtc->plane) {
kfree(exynos_crtc);
return -ENOMEM;
@@ -340,9 +351,9 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
crtc = &exynos_crtc->drm_crtc;
- private->crtc[nr] = crtc;
+ private->crtc[manager->pipe] = crtc;
- drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
+ drm_crtc_init(manager->drm_dev, crtc, &exynos_crtc_funcs);
drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
exynos_drm_crtc_attach_mode_property(crtc);
@@ -350,39 +361,41 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
return 0;
}
-int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
+int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
{
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
- to_exynos_crtc(private->crtc[crtc]);
+ to_exynos_crtc(private->crtc[pipe]);
+ struct exynos_drm_manager *manager = exynos_crtc->manager;
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return -EPERM;
- exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
- exynos_drm_enable_vblank);
+ if (manager->ops->enable_vblank)
+ manager->ops->enable_vblank(manager->ctx);
return 0;
}
-void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
+void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
{
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
- to_exynos_crtc(private->crtc[crtc]);
+ to_exynos_crtc(private->crtc[pipe]);
+ struct exynos_drm_manager *manager = exynos_crtc->manager;
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return;
- exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
- exynos_drm_disable_vblank);
+ if (manager->ops->disable_vblank)
+ manager->ops->disable_vblank(manager->ctx);
}
-void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
{
struct exynos_drm_private *dev_priv = dev->dev_private;
struct drm_pending_vblank_event *e, *t;
- struct drm_crtc *drm_crtc = dev_priv->crtc[crtc];
+ struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
unsigned long flags;
@@ -391,15 +404,71 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
base.link) {
/* if event's pipe isn't same as crtc then ignore it. */
- if (crtc != e->pipe)
+ if (pipe != e->pipe)
continue;
list_del(&e->base.link);
drm_send_vblank_event(dev, -1, e);
- drm_vblank_put(dev, crtc);
+ drm_vblank_put(dev, pipe);
atomic_set(&exynos_crtc->pending_flip, 0);
wake_up(&exynos_crtc->pending_flip_queue);
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
+
+void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+ struct exynos_drm_overlay *overlay)
+{
+ struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+ if (manager->ops->win_mode_set)
+ manager->ops->win_mode_set(manager->ctx, overlay);
+}
+
+void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos)
+{
+ struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+ if (manager->ops->win_commit)
+ manager->ops->win_commit(manager->ctx, zpos);
+}
+
+void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos)
+{
+ struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+ if (manager->ops->win_enable)
+ manager->ops->win_enable(manager->ctx, zpos);
+}
+
+void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos)
+{
+ struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+ if (manager->ops->win_disable)
+ manager->ops->win_disable(manager->ctx, zpos);
+}
+
+void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
+{
+ struct exynos_drm_manager *manager;
+ struct drm_device *dev = fb->dev;
+ struct drm_crtc *crtc;
+
+ /*
+ * make sure that overlay data are updated to real hardware
+ * for all encoders.
+ */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ manager = to_exynos_crtc(crtc)->manager;
+
+ /*
+ * wait for vblank interrupt
+ * - this makes sure that overlay data are updated to
+ * real hardware.
+ */
+ if (manager->ops->wait_for_vblank)
+ manager->ops->wait_for_vblank(manager->ctx);
+ }
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index 3e197e6..c27b66c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -15,9 +15,21 @@
#ifndef _EXYNOS_DRM_CRTC_H_
#define _EXYNOS_DRM_CRTC_H_
-int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
-int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
-void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
-void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc);
+struct drm_device;
+struct drm_crtc;
+struct exynos_drm_manager;
+struct exynos_drm_overlay;
+
+int exynos_drm_crtc_create(struct exynos_drm_manager *manager);
+int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
+
+void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+ struct exynos_drm_overlay *overlay);
+void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
+void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
+void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 617748e..250903c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -72,15 +72,9 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
exynos_drm_mode_config_init(dev);
- /*
- * EXYNOS4 is enough to have two CRTCs and each crtc would be used
- * without dependency of hardware.
- */
- for (nr = 0; nr < MAX_CRTC; nr++) {
- ret = exynos_drm_crtc_create(dev, nr);
- if (ret)
- goto err_release_iommu_mapping;
- }
+ ret = exynos_drm_initialize_managers(dev);
+ if (ret)
+ goto err_mode_config_cleanup;
for (nr = 0; nr < MAX_PLANE; nr++) {
struct drm_plane *plane;
@@ -88,12 +82,16 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
plane = exynos_plane_init(dev, possible_crtcs, false);
if (!plane)
- goto err_release_iommu_mapping;
+ goto err_manager_cleanup;
}
+ ret = exynos_drm_initialize_displays(dev);
+ if (ret)
+ goto err_manager_cleanup;
+
ret = drm_vblank_init(dev, MAX_CRTC);
if (ret)
- goto err_release_iommu_mapping;
+ goto err_display_cleanup;
/*
* probe sub drivers such as display controller and hdmi driver,
@@ -125,7 +123,12 @@ err_drm_device:
exynos_drm_device_unregister(dev);
err_vblank:
drm_vblank_cleanup(dev);
-err_release_iommu_mapping:
+err_display_cleanup:
+ exynos_drm_remove_displays(dev);
+err_manager_cleanup:
+ exynos_drm_remove_managers(dev);
+err_mode_config_cleanup:
+ drm_mode_config_cleanup(dev);
drm_release_iommu_mapping(dev);
err_crtc:
drm_mode_config_cleanup(dev);
@@ -140,6 +143,8 @@ static int exynos_drm_unload(struct drm_device *dev)
exynos_drm_device_unregister(dev);
drm_vblank_cleanup(dev);
drm_kms_helper_poll_fini(dev);
+ exynos_drm_remove_displays(dev);
+ exynos_drm_remove_managers(dev);
drm_mode_config_cleanup(dev);
drm_release_iommu_mapping(dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index be3d352..e82234e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -122,34 +122,62 @@ struct exynos_drm_overlay {
* Exynos DRM Display Structure.
* - this structure is common to analog tv, digital tv and lcd panel.
*
- * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
* @initialize: initializes the display with drm_dev
+ * @remove: cleans up the display for removal
* @is_connected: check for that display is connected or not.
+ * @get_max_resol: get maximum resolution to specific hardware.
* @get_edid: get edid modes from display driver.
* @get_panel: get panel object from display driver.
+ * @mode_fixup: fix mode data comparing to hw specific display mode.
+ * @mode_set: convert drm_display_mode to hw specific display mode and
+ * would be called by encoder->mode_set().
* @check_mode: check if mode is valid or not.
* @dpms: display device on or off.
+ * @commit: apply changes to hw
*/
struct exynos_drm_display_ops {
- enum exynos_drm_output_type type;
int (*initialize)(void *ctx, struct drm_device *drm_dev);
+ void (*remove)(void *ctx);
bool (*is_connected)(void *ctx);
+ void (*get_max_resol)(void *ctx, unsigned int *width,
+ unsigned int *height);
struct edid *(*get_edid)(void *ctx, struct drm_connector *connector);
void *(*get_panel)(void *ctx);
+ void (*mode_fixup)(void *ctx, struct drm_connector *connector,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+ void (*mode_set)(void *ctx, struct drm_display_mode *mode);
int (*check_mode)(void *ctx, struct drm_display_mode *mode);
void (*dpms)(void *ctx, int mode);
+ void (*commit)(void *ctx);
+};
+
+/*
+ * Exynos drm display structure, maps 1:1 with an encoder/connector
+ *
+ * @list: the list entry for this manager
+ * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @encoder: encoder object this display maps to
+ * @connector: connector object this display maps to
+ * @ops: pointer to callbacks for exynos drm specific functionality
+ * @ctx: A pointer to the display's implementation specific context
+ */
+struct exynos_drm_display {
+ struct list_head list;
+ enum exynos_drm_output_type type;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ struct exynos_drm_display_ops *ops;
+ void *ctx;
};
/*
* Exynos drm manager ops
*
* @initialize: initializes the manager with drm_dev
+ * @remove: cleans up the manager for removal
* @dpms: control device power.
* @apply: set timing, vblank and overlay data to registers.
- * @mode_fixup: fix mode data comparing to hw specific display mode.
- * @mode_set: convert drm_display_mode to hw specific display mode and
- * would be called by encoder->mode_set().
- * @get_max_resol: get maximum resolution to specific hardware.
* @commit: set current hw specific display mode to hw.
* @enable_vblank: specific driver callback for enabling vblank interrupt.
* @disable_vblank: specific driver callback for disabling vblank interrupt.
@@ -161,15 +189,10 @@ struct exynos_drm_display_ops {
* @win_disable: disable hardware specific overlay.
*/
struct exynos_drm_manager_ops {
- int (*initialize)(void *ctx, struct drm_device *drm_dev);
+ int (*initialize)(void *ctx, struct drm_device *drm_dev, int pipe);
+ void (*remove)(void *ctx);
void (*dpms)(void *ctx, int mode);
void (*apply)(void *ctx);
- void (*mode_fixup)(void *ctx, struct drm_connector *connector,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
- void (*mode_set)(void *ctx, void *mode);
- void (*get_max_resol)(void *ctx, unsigned int *width,
- unsigned int *height);
void (*commit)(void *ctx);
int (*enable_vblank)(void *ctx);
void (*disable_vblank)(void *ctx);
@@ -181,25 +204,21 @@ struct exynos_drm_manager_ops {
};
/*
- * Exynos drm common manager structure.
+ * Exynos drm common manager structure, maps 1:1 with a crtc
*
- * @dev: pointer to device object for subdrv device driver.
- * sub drivers such as display controller or hdmi driver,
- * have their own device object.
- * @ops: pointer to callbacks for exynos drm specific framebuffer.
- * these callbacks should be set by specific drivers such fimd
- * or hdmi driver and are used to control hardware global registers.
- * @display: pointer to callbacks for exynos drm specific framebuffer.
- * these callbacks should be set by specific drivers such fimd
- * or hdmi driver and are used to control display devices such as
- * analog tv, digital tv and lcd panel and also get timing data for them.
+ * @list: the list entry for this manager
+ * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @drm_dev: pointer to the drm device
+ * @pipe: the pipe number for this crtc/manager
+ * @ops: pointer to callbacks for exynos drm specific functionality
* @ctx: A pointer to the manager's implementation specific context
*/
struct exynos_drm_manager {
- struct device *dev;
+ struct list_head list;
+ enum exynos_drm_output_type type;
+ struct drm_device *drm_dev;
int pipe;
struct exynos_drm_manager_ops *ops;
- struct exynos_drm_display_ops *display_ops;
void *ctx;
};
@@ -264,14 +283,11 @@ struct exynos_drm_private {
* by probe callback.
* @open: this would be called with drm device file open.
* @close: this would be called with drm device file close.
- * @encoder: encoder object owned by this sub driver.
- * @connector: connector object owned by this sub driver.
*/
struct exynos_drm_subdrv {
struct list_head list;
struct device *dev;
struct drm_device *drm_dev;
- struct exynos_drm_manager *manager;
int (*probe)(struct drm_device *drm_dev, struct device *dev);
void (*remove)(struct drm_device *drm_dev, struct device *dev);
@@ -279,9 +295,6 @@ struct exynos_drm_subdrv {
struct drm_file *file);
void (*close)(struct drm_device *drm_dev, struct device *dev,
struct drm_file *file);
-
- struct drm_encoder *encoder;
- struct drm_connector *connector;
};
/*
@@ -296,6 +309,16 @@ int exynos_drm_device_register(struct drm_device *dev);
*/
int exynos_drm_device_unregister(struct drm_device *dev);
+int exynos_drm_initialize_managers(struct drm_device *dev);
+void exynos_drm_remove_managers(struct drm_device *dev);
+int exynos_drm_initialize_displays(struct drm_device *dev);
+void exynos_drm_remove_displays(struct drm_device *dev);
+
+int exynos_drm_manager_register(struct exynos_drm_manager *manager);
+int exynos_drm_manager_unregister(struct exynos_drm_manager *manager);
+int exynos_drm_display_register(struct exynos_drm_display *display);
+int exynos_drm_display_unregister(struct exynos_drm_display *display);
+
/*
* this function would be called by sub drivers such as display controller
* or hdmi driver to register this sub driver object to exynos drm driver
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index c417c90..ba63c72 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -26,24 +26,23 @@
* exynos specific encoder structure.
*
* @drm_encoder: encoder object.
- * @manager: specific encoder has its own manager to control a hardware
- * appropriately and we can access a hardware drawing on this manager.
+ * @display: the display structure that maps to this encoder
*/
struct exynos_drm_encoder {
struct drm_crtc *old_crtc;
struct drm_encoder drm_encoder;
- struct exynos_drm_manager *manager;
+ struct exynos_drm_display *display;
};
static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
{
- struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
- struct exynos_drm_display_ops *display_ops = manager->display_ops;
+ struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+ struct exynos_drm_display *display = exynos_encoder->display;
DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
- if (display_ops && display_ops->dpms)
- display_ops->dpms(manager->ctx, mode);
+ if (display->ops->dpms)
+ display->ops->dpms(display->ctx, mode);
}
static bool
@@ -52,15 +51,17 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = encoder->dev;
+ struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+ struct exynos_drm_display *display = exynos_encoder->display;
struct drm_connector *connector;
- struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder)
- if (manager_ops && manager_ops->mode_fixup)
- manager_ops->mode_fixup(manager->ctx, connector,
- mode, adjusted_mode);
+ if (connector->encoder != encoder)
+ continue;
+
+ if (display->ops->mode_fixup)
+ display->ops->mode_fixup(display->ctx, connector, mode,
+ adjusted_mode);
}
return true;
@@ -102,8 +103,7 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
{
struct drm_device *dev = encoder->dev;
struct drm_connector *connector;
- struct exynos_drm_manager *manager;
- struct exynos_drm_manager_ops *manager_ops;
+ struct exynos_drm_display *display;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder == encoder) {
@@ -123,11 +123,10 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
encoder->crtc);
}
- manager = exynos_drm_get_manager(encoder);
- manager_ops = manager->ops;
+ display = exynos_encoder->display;
- if (manager_ops && manager_ops->mode_set)
- manager_ops->mode_set(manager->ctx,
+ if (display->ops->mode_set)
+ display->ops->mode_set(display->ctx,
adjusted_mode);
exynos_encoder->old_crtc = encoder->crtc;
@@ -143,39 +142,15 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
- struct exynos_drm_manager *manager = exynos_encoder->manager;
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
-
- if (manager_ops && manager_ops->commit)
- manager_ops->commit(manager->ctx);
-}
+ struct exynos_drm_display *display = exynos_encoder->display;
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
-{
- struct exynos_drm_encoder *exynos_encoder;
- struct exynos_drm_manager_ops *ops;
- struct drm_device *dev = fb->dev;
- struct drm_encoder *encoder;
+ if (display->ops->dpms)
+ display->ops->dpms(display->ctx, DRM_MODE_DPMS_ON);
- /*
- * make sure that overlay data are updated to real hardware
- * for all encoders.
- */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- exynos_encoder = to_exynos_encoder(encoder);
- ops = exynos_encoder->manager->ops;
-
- /*
- * wait for vblank interrupt
- * - this makes sure that overlay data are updated to
- * real hardware.
- */
- if (ops->wait_for_vblank)
- ops->wait_for_vblank(exynos_encoder->manager->dev);
- }
+ if (display->ops->commit)
+ display->ops->commit(display->ctx);
}
-
static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
{
struct drm_plane *plane;
@@ -201,10 +176,7 @@ static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
{
- struct exynos_drm_encoder *exynos_encoder =
- to_exynos_encoder(encoder);
-
- exynos_encoder->manager->pipe = -1;
+ struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
drm_encoder_cleanup(encoder);
kfree(exynos_encoder);
@@ -219,13 +191,12 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
struct drm_encoder *clone;
struct drm_device *dev = encoder->dev;
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
- struct exynos_drm_display_ops *display_ops =
- exynos_encoder->manager->display_ops;
+ struct exynos_drm_display *display = exynos_encoder->display;
unsigned int clone_mask = 0;
int cnt = 0;
list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
- switch (display_ops->type) {
+ switch (display->type) {
case EXYNOS_DISPLAY_TYPE_LCD:
case EXYNOS_DISPLAY_TYPE_HDMI:
case EXYNOS_DISPLAY_TYPE_VIDI:
@@ -249,24 +220,20 @@ void exynos_drm_encoder_setup(struct drm_device *dev)
struct drm_encoder *
exynos_drm_encoder_create(struct drm_device *dev,
- struct exynos_drm_manager *manager,
+ struct exynos_drm_display *display,
unsigned long possible_crtcs)
{
struct drm_encoder *encoder;
struct exynos_drm_encoder *exynos_encoder;
- int ret;
- if (!manager || !possible_crtcs)
- return NULL;
-
- if (!manager->dev)
+ if (!possible_crtcs)
return NULL;
exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
if (!exynos_encoder)
return NULL;
- exynos_encoder->manager = manager;
+ exynos_encoder->display = display;
encoder = &exynos_encoder->drm_encoder;
encoder->possible_crtcs = possible_crtcs;
@@ -277,174 +244,12 @@ exynos_drm_encoder_create(struct drm_device *dev,
drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
- if (manager->ops && manager->ops->initialize) {
- ret = manager->ops->initialize(manager->ctx, dev);
- if (ret) {
- DRM_ERROR("Manager initialize failed %d\n", ret);
- goto error;
- }
- }
-
- if (manager->display_ops && manager->display_ops->initialize) {
- ret = manager->display_ops->initialize(manager->ctx, dev);
- if (ret) {
- DRM_ERROR("Display initialize failed %d\n", ret);
- goto error;
- }
- }
-
DRM_DEBUG_KMS("encoder has been created\n");
return encoder;
-
-error:
- exynos_drm_encoder_destroy(&exynos_encoder->drm_encoder);
- return NULL;
}
-struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
+struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
{
- return to_exynos_encoder(encoder)->manager;
-}
-
-void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
- void (*fn)(struct drm_encoder *, void *))
-{
- struct drm_device *dev = crtc->dev;
- struct drm_encoder *encoder;
- struct exynos_drm_private *private = dev->dev_private;
- struct exynos_drm_manager *manager;
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- /*
- * if crtc is detached from encoder, check pipe,
- * otherwise check crtc attached to encoder
- */
- if (!encoder->crtc) {
- manager = to_exynos_encoder(encoder)->manager;
- if (manager->pipe < 0 ||
- private->crtc[manager->pipe] != crtc)
- continue;
- } else {
- if (encoder->crtc != crtc)
- continue;
- }
-
- fn(encoder, data);
- }
-}
-
-void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
-{
- struct exynos_drm_manager *manager =
- to_exynos_encoder(encoder)->manager;
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
- int crtc = *(int *)data;
-
- if (manager->pipe != crtc)
- return;
-
- if (manager_ops->enable_vblank)
- manager_ops->enable_vblank(manager->ctx);
-}
-
-void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
-{
- struct exynos_drm_manager *manager =
- to_exynos_encoder(encoder)->manager;
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
- int crtc = *(int *)data;
-
- if (manager->pipe != crtc)
- return;
-
- if (manager_ops->disable_vblank)
- manager_ops->disable_vblank(manager->ctx);
-}
-
-void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
-{
- struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
- struct exynos_drm_manager *manager = exynos_encoder->manager;
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
- int mode = *(int *)data;
-
- if (manager_ops && manager_ops->dpms)
- manager_ops->dpms(manager->ctx, mode);
-
- /*
- * if this condition is ok then it means that the crtc is already
- * detached from encoder and last function for detaching is properly
- * done, so clear pipe from manager to prevent repeated call.
- */
- if (mode > DRM_MODE_DPMS_ON) {
- if (!encoder->crtc)
- manager->pipe = -1;
- }
-}
-
-void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
-{
- struct exynos_drm_manager *manager =
- to_exynos_encoder(encoder)->manager;
- int pipe = *(int *)data;
-
- /*
- * when crtc is detached from encoder, this pipe is used
- * to select manager operation
- */
- manager->pipe = pipe;
-}
-
-void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
-{
- struct exynos_drm_manager *manager =
- to_exynos_encoder(encoder)->manager;
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
- struct exynos_drm_overlay *overlay = data;
-
- if (manager_ops && manager_ops->win_mode_set)
- manager_ops->win_mode_set(manager->ctx, overlay);
-}
-
-void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
-{
- struct exynos_drm_manager *manager =
- to_exynos_encoder(encoder)->manager;
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
- int zpos = DEFAULT_ZPOS;
-
- if (data)
- zpos = *(int *)data;
-
- if (manager_ops && manager_ops->win_commit)
- manager_ops->win_commit(manager->ctx, zpos);
-}
-
-void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
-{
- struct exynos_drm_manager *manager =
- to_exynos_encoder(encoder)->manager;
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
- int zpos = DEFAULT_ZPOS;
-
- if (data)
- zpos = *(int *)data;
-
- if (manager_ops && manager_ops->win_enable)
- manager_ops->win_enable(manager->ctx, zpos);
-}
-
-void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
-{
- struct exynos_drm_manager *manager =
- to_exynos_encoder(encoder)->manager;
- struct exynos_drm_manager_ops *manager_ops = manager->ops;
- int zpos = DEFAULT_ZPOS;
-
- if (data)
- zpos = *(int *)data;
-
- if (manager_ops && manager_ops->win_disable)
- manager_ops->win_disable(manager->ctx, zpos);
+ return to_exynos_encoder(encoder)->display;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
index 0f3e5e2..b7a1620 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
@@ -18,20 +18,8 @@ struct exynos_drm_manager;
void exynos_drm_encoder_setup(struct drm_device *dev);
struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
- struct exynos_drm_manager *mgr,
- unsigned long possible_crtcs);
-struct exynos_drm_manager *
-exynos_drm_get_manager(struct drm_encoder *encoder);
-void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
- void (*fn)(struct drm_encoder *, void *));
-void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb);
+ struct exynos_drm_display *mgr,
+ unsigned long possible_crtcs);
+struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder);
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index ea39e0e..c7c08d0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -22,7 +22,7 @@
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_iommu.h"
-#include "exynos_drm_encoder.h"
+#include "exynos_drm_crtc.h"
#define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb)
@@ -71,7 +71,7 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
unsigned int i;
/* make sure that overlay data are updated before relesing fb. */
- exynos_drm_encoder_complete_scanout(fb);
+ exynos_drm_crtc_complete_scanout(fb);
drm_framebuffer_cleanup(fb);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 838c47d..f3dc808 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -105,7 +105,6 @@ struct fimd_win_data {
};
struct fimd_context {
- struct exynos_drm_subdrv subdrv;
struct device *dev;
struct drm_device *drm_dev;
int irq;
@@ -120,6 +119,7 @@ struct fimd_context {
u32 vidcon0;
u32 vidcon1;
bool suspended;
+ int pipe;
struct mutex lock;
wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event;
@@ -169,12 +169,16 @@ static int fimd_check_mode(void *in_ctx, struct drm_display_mode *mode)
}
static struct exynos_drm_display_ops fimd_display_ops = {
- .type = EXYNOS_DISPLAY_TYPE_LCD,
.is_connected = fimd_display_is_connected,
.get_panel = fimd_get_panel,
.check_mode = fimd_check_mode,
};
+static struct exynos_drm_display fimd_display = {
+ .type = EXYNOS_DISPLAY_TYPE_LCD,
+ .ops = &fimd_display_ops,
+};
+
static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
{
struct fimd_context *ctx = in_ctx;
@@ -481,15 +485,46 @@ static void fimd_win_disable(void *in_ctx, int zpos)
win_data->enabled = false;
}
-static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
+static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev,
+ int pipe)
{
struct fimd_context *ctx = in_ctx;
ctx->drm_dev = drm_dev;
+ ctx->pipe = pipe;
+
+ /*
+ * enable drm irq mode.
+ * - with irq_enabled = 1, we can use the vblank feature.
+ *
+ * P.S. note that we wouldn't use drm irq handler but
+ * just specific driver own one instead because
+ * drm framework supports only one irq handler.
+ */
+ ctx->drm_dev->irq_enabled = 1;
+
+ /*
+ * with vblank_disable_allowed = 1, vblank interrupt will be disabled
+ * by drm timer once a current process gives up ownership of
+ * vblank event.(after drm_vblank_put function is called)
+ */
+ drm_dev->vblank_disable_allowed = 1;
+
+ /* attach this sub driver to iommu mapping if supported. */
+ if (is_drm_iommu_supported(ctx->drm_dev))
+ drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
return 0;
}
+static void fimd_mgr_remove(void *in_ctx)
+{
+ struct fimd_context *ctx = in_ctx;
+
+ if (is_drm_iommu_supported(ctx->drm_dev))
+ drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+}
+
static void fimd_dpms(void *in_ctx, int mode)
{
struct fimd_context *ctx = in_ctx;
@@ -523,24 +558,6 @@ static void fimd_dpms(void *in_ctx, int mode)
mutex_unlock(&ctx->lock);
}
-static void fimd_apply(void *in_ctx)
-{
- struct fimd_context *ctx = in_ctx;
- struct exynos_drm_manager *mgr = ctx->subdrv.manager;
- struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
- struct fimd_win_data *win_data;
- int i;
-
- for (i = 0; i < WINDOWS_NR; i++) {
- win_data = &ctx->win_data[i];
- if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
- mgr_ops->win_commit(ctx, i);
- }
-
- if (mgr_ops && mgr_ops->commit)
- mgr_ops->commit(ctx);
-}
-
static void fimd_commit(void *in_ctx)
{
struct fimd_context *ctx = in_ctx;
@@ -597,6 +614,21 @@ static void fimd_commit(void *in_ctx)
writel(val, ctx->regs + VIDCON0);
}
+static void fimd_apply(void *in_ctx)
+{
+ struct fimd_context *ctx = in_ctx;
+ struct fimd_win_data *win_data;
+ int i;
+
+ for (i = 0; i < WINDOWS_NR; i++) {
+ win_data = &ctx->win_data[i];
+ if (win_data->enabled)
+ fimd_win_commit(ctx, i);
+ }
+
+ fimd_commit(ctx);
+}
+
static int fimd_enable_vblank(void *in_ctx)
{
struct fimd_context *ctx = in_ctx;
@@ -661,6 +693,7 @@ static void fimd_wait_for_vblank(void *in_ctx)
static struct exynos_drm_manager_ops fimd_manager_ops = {
.initialize = fimd_mgr_initialize,
+ .remove = fimd_mgr_remove,
.dpms = fimd_dpms,
.apply = fimd_apply,
.commit = fimd_commit,
@@ -673,16 +706,13 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
};
static struct exynos_drm_manager fimd_manager = {
- .pipe = -1,
- .ops = &fimd_manager_ops,
- .display_ops = &fimd_display_ops,
+ .type = EXYNOS_DISPLAY_TYPE_LCD,
+ .ops = &fimd_manager_ops,
};
static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
{
struct fimd_context *ctx = (struct fimd_context *)dev_id;
- struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
- struct exynos_drm_manager *manager = subdrv->manager;
u32 val;
val = readl(ctx->regs + VIDINTCON1);
@@ -692,11 +722,11 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
/* check the crtc is detached already from encoder */
- if (manager->pipe < 0 || !ctx->drm_dev)
+ if (ctx->pipe < 0 || !ctx->drm_dev)
goto out;
- drm_handle_vblank(ctx->drm_dev, manager->pipe);
- exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
+ drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+ exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
@@ -707,39 +737,6 @@ out:
return IRQ_HANDLED;
}
-static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
-{
- /*
- * enable drm irq mode.
- * - with irq_enabled = 1, we can use the vblank feature.
- *
- * P.S. note that we wouldn't use drm irq handler but
- * just specific driver own one instead because
- * drm framework supports only one irq handler.
- */
- drm_dev->irq_enabled = 1;
-
- /*
- * with vblank_disable_allowed = 1, vblank interrupt will be disabled
- * by drm timer once a current process gives up ownership of
- * vblank event.(after drm_vblank_put function is called)
- */
- drm_dev->vblank_disable_allowed = 1;
-
- /* attach this sub driver to iommu mapping if supported. */
- if (is_drm_iommu_supported(drm_dev))
- drm_iommu_attach_device(drm_dev, dev);
-
- return 0;
-}
-
-static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
- /* detach this sub driver from iommu mapping if supported. */
- if (is_drm_iommu_supported(drm_dev))
- drm_iommu_detach_device(drm_dev, dev);
-}
-
static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
{
struct videomode *vm = &ctx->panel.vm;
@@ -825,9 +822,8 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
return 0;
}
-static void fimd_window_suspend(struct device *dev)
+static void fimd_window_suspend(struct fimd_context *ctx)
{
- struct fimd_context *ctx = get_fimd_context(dev);
struct fimd_win_data *win_data;
int i;
@@ -839,9 +835,8 @@ static void fimd_window_suspend(struct device *dev)
fimd_wait_for_vblank(ctx);
}
-static void fimd_window_resume(struct device *dev)
+static void fimd_window_resume(struct fimd_context *ctx)
{
- struct fimd_context *ctx = get_fimd_context(dev);
struct fimd_win_data *win_data;
int i;
@@ -854,7 +849,6 @@ static void fimd_window_resume(struct device *dev)
static int fimd_activate(struct fimd_context *ctx, bool enable)
{
- struct device *dev = ctx->subdrv.dev;
if (enable) {
int ret;
@@ -866,11 +860,11 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags))
- fimd_enable_vblank(dev);
+ fimd_enable_vblank(ctx);
- fimd_window_resume(dev);
+ fimd_window_resume(ctx);
} else {
- fimd_window_suspend(dev);
+ fimd_window_suspend(ctx);
fimd_clock(ctx, false);
ctx->suspended = true;
@@ -907,7 +901,6 @@ static int fimd_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fimd_context *ctx;
- struct exynos_drm_subdrv *subdrv;
struct resource *res;
int win;
int ret = -EINVAL;
@@ -952,15 +945,6 @@ static int fimd_probe(struct platform_device *pdev)
DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
atomic_set(&ctx->wait_vsync_event, 0);
- fimd_manager.ctx = ctx;
-
- subdrv = &ctx->subdrv;
-
- subdrv->dev = dev;
- subdrv->manager = &fimd_manager;
- subdrv->probe = fimd_subdrv_probe;
- subdrv->remove = fimd_subdrv_remove;
-
mutex_init(&ctx->lock);
platform_set_drvdata(pdev, ctx);
@@ -971,7 +955,11 @@ static int fimd_probe(struct platform_device *pdev)
for (win = 0; win < WINDOWS_NR; win++)
fimd_clear_win(ctx, win);
- exynos_drm_subdrv_register(subdrv);
+ fimd_manager.ctx = ctx;
+ exynos_drm_manager_register(&fimd_manager);
+
+ fimd_display.ctx = ctx;
+ exynos_drm_display_register(&fimd_display);
return 0;
}
@@ -981,7 +969,8 @@ static int fimd_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct fimd_context *ctx = platform_get_drvdata(pdev);
- exynos_drm_subdrv_unregister(&ctx->subdrv);
+ exynos_drm_display_unregister(&fimd_display);
+ exynos_drm_manager_unregister(&fimd_manager);
if (ctx->suspended)
goto out;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 8173e44..8fc9d6d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -24,14 +24,11 @@
#include "exynos_drm_hdmi.h"
#define to_context(dev) platform_get_drvdata(to_platform_device(dev))
-#define to_subdrv(dev) to_context(dev)
-#define get_ctx_from_subdrv(subdrv) container_of(subdrv,\
- struct drm_hdmi_context, subdrv);
/* 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.
+/* 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;
@@ -41,7 +38,6 @@ static struct exynos_hdmi_ops *hdmi_ops;
static struct exynos_mixer_ops *mixer_ops;
struct drm_hdmi_context {
- struct exynos_drm_subdrv subdrv;
struct exynos_drm_hdmi_context *hdmi_ctx;
struct exynos_drm_hdmi_context *mixer_ctx;
@@ -101,6 +97,12 @@ 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);
@@ -118,6 +120,17 @@ static bool drm_hdmi_is_connected(void *in_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)
{
@@ -129,6 +142,16 @@ static struct edid *drm_hdmi_get_edid(void *in_ctx,
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;
@@ -151,52 +174,6 @@ static int drm_hdmi_check_mode(void *in_ctx, struct drm_display_mode *mode)
return 0;
}
-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 = {
- .type = EXYNOS_DISPLAY_TYPE_HDMI,
- .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,
-};
-
-static int drm_hdmi_enable_vblank(void *in_ctx)
-{
- struct drm_hdmi_context *ctx = in_ctx;
- struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
- struct exynos_drm_manager *manager = subdrv->manager;
-
- if (mixer_ops && mixer_ops->enable_vblank)
- return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
- manager->pipe);
-
- return 0;
-}
-
-static void drm_hdmi_disable_vblank(void *in_ctx)
-{
- struct drm_hdmi_context *ctx = in_ctx;
-
- 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_mode_fixup(void *in_ctx, struct drm_connector *connector,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -241,21 +218,57 @@ static void drm_hdmi_mode_fixup(void *in_ctx, struct drm_connector *connector,
}
}
-static void drm_hdmi_mode_set(void *in_ctx, void *mode)
+static void drm_hdmi_display_dpms(void *in_ctx, int mode)
{
struct drm_hdmi_context *ctx = in_ctx;
- if (hdmi_ops && hdmi_ops->mode_set)
- hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
+ if (hdmi_ops && hdmi_ops->dpms)
+ hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
}
-static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
- unsigned int *height)
+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 (hdmi_ops && hdmi_ops->get_max_resol)
- hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
+ 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)
@@ -266,11 +279,19 @@ static void drm_hdmi_commit(void *in_ctx)
hdmi_ops->commit(ctx->hdmi_ctx->ctx);
}
-static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
+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);
@@ -280,6 +301,14 @@ static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
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;
@@ -350,14 +379,12 @@ static void drm_mixer_win_disable(void *in_ctx, int zpos)
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,
- .mode_fixup = drm_hdmi_mode_fixup,
- .mode_set = drm_hdmi_mode_set,
- .get_max_resol = drm_hdmi_get_max_resol,
.commit = drm_hdmi_commit,
.win_mode_set = drm_mixer_win_mode_set,
.win_commit = drm_mixer_win_commit,
@@ -365,82 +392,33 @@ static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
};
static struct exynos_drm_manager hdmi_manager = {
- .pipe = -1,
- .ops = &drm_hdmi_manager_ops,
- .display_ops = &drm_hdmi_display_ops,
+ .type = EXYNOS_DISPLAY_TYPE_HDMI,
+ .ops = &drm_hdmi_manager_ops,
};
-static int hdmi_subdrv_probe(struct drm_device *drm_dev,
- struct device *dev)
-{
- struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
- struct drm_hdmi_context *ctx;
-
- 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 = get_ctx_from_subdrv(subdrv);
-
- if (!ctx) {
- DRM_ERROR("no drm hdmi context.\n");
- return -EFAULT;
- }
-
- ctx->hdmi_ctx = hdmi_ctx;
- ctx->mixer_ctx = mixer_ctx;
-
- return 0;
-}
-
-static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
- struct drm_hdmi_context *ctx;
- struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
-
- ctx = get_ctx_from_subdrv(subdrv);
-
- if (mixer_ops->iommu_on)
- mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
-}
-
static int exynos_drm_hdmi_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct exynos_drm_subdrv *subdrv;
struct drm_hdmi_context *ctx;
- ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
hdmi_manager.ctx = ctx;
+ exynos_drm_manager_register(&hdmi_manager);
- subdrv = &ctx->subdrv;
-
- subdrv->dev = dev;
- subdrv->manager = &hdmi_manager;
- subdrv->probe = hdmi_subdrv_probe;
- subdrv->remove = hdmi_subdrv_remove;
+ hdmi_display.ctx = ctx;
+ exynos_drm_display_register(&hdmi_display);
- platform_set_drvdata(pdev, subdrv);
-
- exynos_drm_subdrv_register(subdrv);
+ platform_set_drvdata(pdev, ctx);
return 0;
}
static int exynos_drm_hdmi_remove(struct platform_device *pdev)
{
- struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
-
- exynos_drm_subdrv_unregister(&ctx->subdrv);
+ exynos_drm_display_unregister(&hdmi_display);
+ exynos_drm_manager_unregister(&hdmi_manager);
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 923239b..37059ea 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -19,10 +19,12 @@
* 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;
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index cff3aed..e0db2b3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -13,7 +13,7 @@
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
+#include "exynos_drm_crtc.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_plane.h"
@@ -139,7 +139,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
overlay->crtc_x, overlay->crtc_y,
overlay->crtc_width, overlay->crtc_height);
- exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);
+ exynos_drm_crtc_plane_mode_set(crtc, overlay);
return 0;
}
@@ -149,8 +149,7 @@ void exynos_plane_commit(struct drm_plane *plane)
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
- exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
- exynos_drm_encoder_plane_commit);
+ exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
}
void exynos_plane_dpms(struct drm_plane *plane, int mode)
@@ -162,17 +161,13 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
if (exynos_plane->enabled)
return;
- exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
- exynos_drm_encoder_plane_enable);
-
+ exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
exynos_plane->enabled = true;
} else {
if (!exynos_plane->enabled)
return;
- exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
- exynos_drm_encoder_plane_disable);
-
+ exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
exynos_plane->enabled = false;
}
}
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 13/23] drm/exynos: hdmi: remove the i2c drivers and use devtree
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (11 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 12/23] drm/exynos: Split manager/display/subdrv Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 14/23] drm/exynos: Remove exynos_drm_hdmi shim Sean Paul
` (10 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
From: Daniel Kurtz <djkurtz@chromium.org>
The i2c client was previously being passed into the hdmi driver via a
dedicated i2c driver, and then a global variable. This patch removes all
of that and just uses the device tree to get the i2c_client. This patch
also properly references the client so we don't lose it before we're
done with it.
Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/Makefile | 1 -
drivers/gpu/drm/exynos/exynos_ddc.c | 63 --------------------------------
drivers/gpu/drm/exynos/exynos_hdmi.c | 57 +++++++++++++----------------
drivers/gpu/drm/exynos/exynos_hdmi.h | 23 ------------
drivers/gpu/drm/exynos/exynos_hdmiphy.c | 65 ---------------------------------
5 files changed, 25 insertions(+), 184 deletions(-)
delete mode 100644 drivers/gpu/drm/exynos/exynos_ddc.c
delete mode 100644 drivers/gpu/drm/exynos/exynos_hdmi.h
delete mode 100644 drivers/gpu/drm/exynos/exynos_hdmiphy.c
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 639b49e..819961a 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -12,7 +12,6 @@ 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_ddc.o exynos_hdmiphy.o \
exynos_drm_hdmi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c
deleted file mode 100644
index 6a8c84e..0000000
--- a/drivers/gpu/drm/exynos/exynos_ddc.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * Authors:
- * Seung-Woo Kim <sw0312.kim@samsung.com>
- * Inki Dae <inki.dae@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/i2c.h>
-#include <linux/of.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_hdmi.h"
-
-static int s5p_ddc_probe(struct i2c_client *client,
- const struct i2c_device_id *dev_id)
-{
- hdmi_attach_ddc_client(client);
-
- dev_info(&client->adapter->dev,
- "attached %s into i2c adapter successfully\n",
- client->name);
-
- return 0;
-}
-
-static int s5p_ddc_remove(struct i2c_client *client)
-{
- dev_info(&client->adapter->dev,
- "detached %s from i2c adapter successfully\n",
- client->name);
-
- return 0;
-}
-
-static struct of_device_id hdmiddc_match_types[] = {
- {
- .compatible = "samsung,exynos5-hdmiddc",
- }, {
- .compatible = "samsung,exynos4210-hdmiddc",
- }, {
- /* end node */
- }
-};
-
-struct i2c_driver ddc_driver = {
- .driver = {
- .name = "exynos-hdmiddc",
- .owner = THIS_MODULE,
- .of_match_table = hdmiddc_match_types,
- },
- .probe = s5p_ddc_probe,
- .remove = s5p_ddc_remove,
- .command = NULL,
-};
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 037c6fe..c6df564 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -33,6 +33,7 @@
#include <linux/regulator/consumer.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_i2c.h>
#include <linux/of_gpio.h>
#include <drm/exynos_drm.h>
@@ -40,8 +41,6 @@
#include "exynos_drm_drv.h"
#include "exynos_drm_hdmi.h"
-#include "exynos_hdmi.h"
-
#include <linux/gpio.h>
#include <media/s5p_hdmi.h>
@@ -1854,20 +1853,6 @@ fail:
return -ENODEV;
}
-static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
-
-void hdmi_attach_ddc_client(struct i2c_client *ddc)
-{
- if (ddc)
- hdmi_ddc = ddc;
-}
-
-void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
-{
- if (hdmiphy)
- hdmi_hdmiphy = hdmiphy;
-}
-
static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
(struct device *dev)
{
@@ -1912,6 +1897,7 @@ static int hdmi_probe(struct platform_device *pdev)
struct s5p_hdmi_platform_data *pdata;
struct resource *res;
const struct of_device_id *match;
+ struct device_node *ddc_node, *phy_node;
int ret;
if (!dev->of_node)
@@ -1962,21 +1948,30 @@ static int hdmi_probe(struct platform_device *pdev)
}
/* DDC i2c driver */
- if (i2c_add_driver(&ddc_driver)) {
- DRM_ERROR("failed to register ddc i2c driver\n");
- return -ENOENT;
+ ddc_node = of_find_node_by_name(NULL, "hdmiddc");
+ if (!ddc_node) {
+ DRM_ERROR("Failed to find ddc node in device tree\n");
+ return -ENODEV;
+ }
+ hdata->ddc_port = of_find_i2c_device_by_node(ddc_node);
+ if (!hdata->ddc_port) {
+ DRM_ERROR("Failed to get ddc i2c client by node\n");
+ return -ENODEV;
}
-
- hdata->ddc_port = hdmi_ddc;
/* hdmiphy i2c driver */
- if (i2c_add_driver(&hdmiphy_driver)) {
- DRM_ERROR("failed to register hdmiphy i2c driver\n");
- ret = -ENOENT;
+ phy_node = of_find_node_by_name(NULL, "hdmiphy");
+ if (!phy_node) {
+ DRM_ERROR("Failed to find hdmiphy node in device tree\n");
+ ret = -ENODEV;
+ goto err_ddc;
+ }
+ hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
+ if (!hdata->hdmiphy_port) {
+ DRM_ERROR("Failed to get hdmi phy i2c client from node\n");
+ ret = -ENODEV;
goto err_ddc;
}
-
- hdata->hdmiphy_port = hdmi_hdmiphy;
hdata->irq = gpio_to_irq(hdata->hpd_gpio);
if (hdata->irq < 0) {
@@ -2007,9 +2002,9 @@ static int hdmi_probe(struct platform_device *pdev)
return 0;
err_hdmiphy:
- i2c_del_driver(&hdmiphy_driver);
+ put_device(&hdata->hdmiphy_port->dev);
err_ddc:
- i2c_del_driver(&ddc_driver);
+ put_device(&hdata->ddc_port->dev);
return ret;
}
@@ -2019,10 +2014,8 @@ static int hdmi_remove(struct platform_device *pdev)
pm_runtime_disable(dev);
- /* hdmiphy i2c driver */
- i2c_del_driver(&hdmiphy_driver);
- /* DDC i2c driver */
- i2c_del_driver(&ddc_driver);
+ put_device(&hdata->hdmiphy_port->dev);
+ put_device(&hdata->ddc_port->dev);
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.h b/drivers/gpu/drm/exynos/exynos_hdmi.h
deleted file mode 100644
index 0ddf395..0000000
--- a/drivers/gpu/drm/exynos/exynos_hdmi.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- * Inki Dae <inki.dae@samsung.com>
- * Seung-Woo Kim <sw0312.kim@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_HDMI_H_
-#define _EXYNOS_HDMI_H_
-
-void hdmi_attach_ddc_client(struct i2c_client *ddc);
-void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy);
-
-extern struct i2c_driver hdmiphy_driver;
-extern struct i2c_driver ddc_driver;
-
-#endif
diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
deleted file mode 100644
index 59abb14..0000000
--- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * Authors:
- * Seung-Woo Kim <sw0312.kim@samsung.com>
- * Inki Dae <inki.dae@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/i2c.h>
-#include <linux/of.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_hdmi.h"
-
-
-static int hdmiphy_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- hdmi_attach_hdmiphy_client(client);
-
- dev_info(&client->adapter->dev, "attached s5p_hdmiphy "
- "into i2c adapter successfully\n");
-
- return 0;
-}
-
-static int hdmiphy_remove(struct i2c_client *client)
-{
- dev_info(&client->adapter->dev, "detached s5p_hdmiphy "
- "from i2c adapter successfully\n");
-
- return 0;
-}
-
-static struct of_device_id hdmiphy_match_types[] = {
- {
- .compatible = "samsung,exynos5-hdmiphy",
- }, {
- .compatible = "samsung,exynos4210-hdmiphy",
- }, {
- .compatible = "samsung,exynos4212-hdmiphy",
- }, {
- /* end node */
- }
-};
-
-struct i2c_driver hdmiphy_driver = {
- .driver = {
- .name = "exynos-hdmiphy",
- .owner = THIS_MODULE,
- .of_match_table = hdmiphy_match_types,
- },
- .probe = hdmiphy_probe,
- .remove = hdmiphy_remove,
- .command = NULL,
-};
-EXPORT_SYMBOL(hdmiphy_driver);
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 14/23] drm/exynos: Remove exynos_drm_hdmi shim
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (12 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 13/23] drm/exynos: hdmi: remove the i2c drivers and use devtree Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 15/23] drm/exynos: Use drm_mode_copy to copy modes Sean Paul
` (9 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
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@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@samsung.com>
- * Seung-Woo Kim <sw0312.kim@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@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
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 15/23] drm/exynos: Use drm_mode_copy to copy modes
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (13 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 14/23] drm/exynos: Remove exynos_drm_hdmi shim Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 16/23] drm/exynos: Disable unused crtc planes from crtc Sean Paul
` (8 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch changes the manual copying of mode to adjusted_mode in
mode_fixup to use drm_mode_copy instead of handling things manually.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_hdmi.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index d95df28..c975a56 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -843,21 +843,13 @@ static void hdmi_mode_fixup(void *in_ctx, struct drm_connector *connector,
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;
+ drm_mode_copy(adjusted_mode, m);
break;
}
}
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 16/23] drm/exynos: Disable unused crtc planes from crtc
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (14 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 15/23] drm/exynos: Use drm_mode_copy to copy modes Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 17/23] drm/exynos: Add mode_set manager operation Sean Paul
` (7 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch moves the code which disables unused crtc planes from the
encoder to the crtc. Since there is a 1:1 encoder/crtc mapping in
exynos, the only valid crtc change the pre-existing code could catch is
disconnecting an active crtc from the encoder. Thus it is functionally
equivalent to just disable all planes attached to a crtc when the crtc
is disabled.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_crtc.c | 13 +++++-
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 65 ++---------------------------
2 files changed, 15 insertions(+), 63 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 9f6ada4..517a3b2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -176,10 +176,19 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
{
- struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+ struct drm_plane *plane;
+ int ret;
- exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF);
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+ list_for_each_entry(plane, &crtc->dev->mode_config.plane_list, head) {
+ if (plane->crtc != crtc)
+ continue;
+
+ ret = plane->funcs->disable_plane(plane);
+ if (ret)
+ DRM_ERROR("Failed to disable plane %d\n", ret);
+ }
}
static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index ba63c72..e50f563 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -29,7 +29,6 @@
* @display: the display structure that maps to this encoder
*/
struct exynos_drm_encoder {
- struct drm_crtc *old_crtc;
struct drm_encoder drm_encoder;
struct exynos_drm_display *display;
};
@@ -67,71 +66,15 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
return true;
}
-static void disable_plane_to_crtc(struct drm_device *dev,
- struct drm_crtc *old_crtc,
- struct drm_crtc *new_crtc)
-{
- struct drm_plane *plane;
-
- /*
- * if old_crtc isn't same as encoder->crtc then it means that
- * user changed crtc id to another one so the plane to old_crtc
- * should be disabled and plane->crtc should be set to new_crtc
- * (encoder->crtc)
- */
- list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
- if (plane->crtc == old_crtc) {
- /*
- * do not change below call order.
- *
- * plane->funcs->disable_plane call checks
- * if encoder->crtc is same as plane->crtc and if same
- * then manager_ops->win_disable callback will be called
- * to diasble current hw overlay so plane->crtc should
- * have new_crtc because new_crtc was set to
- * encoder->crtc in advance.
- */
- plane->crtc = new_crtc;
- plane->funcs->disable_plane(plane);
- }
- }
-}
-
static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct drm_device *dev = encoder->dev;
- struct drm_connector *connector;
- struct exynos_drm_display *display;
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder) {
- struct exynos_drm_encoder *exynos_encoder;
-
- exynos_encoder = to_exynos_encoder(encoder);
-
- if (exynos_encoder->old_crtc != encoder->crtc &&
- exynos_encoder->old_crtc) {
-
- /*
- * disable a plane to old crtc and change
- * crtc of the plane to new one.
- */
- disable_plane_to_crtc(dev,
- exynos_encoder->old_crtc,
- encoder->crtc);
- }
-
- display = exynos_encoder->display;
-
- if (display->ops->mode_set)
- display->ops->mode_set(display->ctx,
- adjusted_mode);
+ struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+ struct exynos_drm_display *display = exynos_encoder->display;
- exynos_encoder->old_crtc = encoder->crtc;
- }
- }
+ if (display->ops->mode_set)
+ display->ops->mode_set(display->ctx, adjusted_mode);
}
static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 17/23] drm/exynos: Add mode_set manager operation
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (15 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 16/23] drm/exynos: Disable unused crtc planes from crtc Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 18/23] drm/exynos: Implement mode_fixup " Sean Paul
` (6 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch adds a mode_set callback to the manager operations which
sets the crtc's current mode to the manager driver.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_crtc.c | 4 ++++
drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 ++
2 files changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 517a3b2..576754d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -115,6 +115,7 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_framebuffer *old_fb)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+ struct exynos_drm_manager *manager = exynos_crtc->manager;
struct drm_plane *plane = exynos_crtc->plane;
unsigned int crtc_w;
unsigned int crtc_h;
@@ -129,6 +130,9 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
crtc_w = crtc->fb->width - x;
crtc_h = crtc->fb->height - y;
+ if (manager->ops->mode_set)
+ manager->ops->mode_set(manager->ctx, &crtc->mode);
+
ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
x, y, crtc_w, crtc_h);
if (ret)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index e82234e..3a86473 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -178,6 +178,7 @@ struct exynos_drm_display {
* @remove: cleans up the manager for removal
* @dpms: control device power.
* @apply: set timing, vblank and overlay data to registers.
+ * @mode_set: set the given mode to the manager
* @commit: set current hw specific display mode to hw.
* @enable_vblank: specific driver callback for enabling vblank interrupt.
* @disable_vblank: specific driver callback for disabling vblank interrupt.
@@ -193,6 +194,7 @@ struct exynos_drm_manager_ops {
void (*remove)(void *ctx);
void (*dpms)(void *ctx, int mode);
void (*apply)(void *ctx);
+ void (*mode_set)(void *ctx, const struct drm_display_mode *mode);
void (*commit)(void *ctx);
int (*enable_vblank)(void *ctx);
void (*disable_vblank)(void *ctx);
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 18/23] drm/exynos: Implement mode_fixup manager operation
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (16 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 17/23] drm/exynos: Add mode_set manager operation Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 19/23] drm/exynos: Use mode_set to configure fimd Sean Paul
` (5 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch adds a new manager callback for mode_fixup and pipes it
through exynos_drm_crtc.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_crtc.c | 8 +++++++-
drivers/gpu/drm/exynos/exynos_drm_drv.h | 3 +++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 576754d..083e1e3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -105,7 +105,13 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- /* drm framework doesn't check NULL */
+ struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+ struct exynos_drm_manager *manager = exynos_crtc->manager;
+
+ if (manager->ops->mode_fixup)
+ return manager->ops->mode_fixup(manager->ctx, mode,
+ adjusted_mode);
+
return true;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 3a86473..0a956d0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -178,6 +178,7 @@ struct exynos_drm_display {
* @remove: cleans up the manager for removal
* @dpms: control device power.
* @apply: set timing, vblank and overlay data to registers.
+ * @mode_fixup: fix mode data before applying it
* @mode_set: set the given mode to the manager
* @commit: set current hw specific display mode to hw.
* @enable_vblank: specific driver callback for enabling vblank interrupt.
@@ -194,6 +195,8 @@ struct exynos_drm_manager_ops {
void (*remove)(void *ctx);
void (*dpms)(void *ctx, int mode);
void (*apply)(void *ctx);
+ bool (*mode_fixup)(void *ctx, const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
void (*mode_set)(void *ctx, const struct drm_display_mode *mode);
void (*commit)(void *ctx);
int (*enable_vblank)(void *ctx);
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 19/23] drm/exynos: Use mode_set to configure fimd
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (17 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 18/23] drm/exynos: Implement mode_fixup " Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 20/23] drm/exynos: Remove unused/useless fimd_context members Sean Paul
` (4 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch uses the mode passed into mode_set to configure fimd instead
of directly using the panel from context. This will allow us to move
the exynos_drm_display implementation from fimd into the DP driver
where it belongs.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 157 ++++++++++++++++++-------------
1 file changed, 89 insertions(+), 68 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index f3dc808..1b128cf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -104,6 +104,20 @@ struct fimd_win_data {
bool resume;
};
+struct fimd_mode_data {
+ unsigned vtotal;
+ unsigned vdisplay;
+ unsigned vsync_len;
+ unsigned vbpd;
+ unsigned vfpd;
+ unsigned htotal;
+ unsigned hdisplay;
+ unsigned hsync_len;
+ unsigned hbpd;
+ unsigned hfpd;
+ u32 clkdiv;
+};
+
struct fimd_context {
struct device *dev;
struct drm_device *drm_dev;
@@ -112,8 +126,8 @@ struct fimd_context {
struct clk *bus_clk;
struct clk *lcd_clk;
void __iomem *regs;
+ struct fimd_mode_data mode;
struct fimd_win_data win_data[WINDOWS_NR];
- unsigned int clkdiv;
unsigned int default_win;
unsigned long irq_flags;
u32 vidcon0;
@@ -558,11 +572,54 @@ static void fimd_dpms(void *in_ctx, int mode)
mutex_unlock(&ctx->lock);
}
+static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
+ const struct drm_display_mode *mode)
+{
+ unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
+ u32 clkdiv;
+
+ /* Find the clock divider value that gets us closest to ideal_clk */
+ clkdiv = DIV_ROUND_CLOSEST(clk_get_rate(ctx->lcd_clk), ideal_clk);
+
+ return (clkdiv < 0x100) ? clkdiv : 0xff;
+}
+
+static bool fimd_mode_fixup(void *in_ctx, const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ if (adjusted_mode->vrefresh == 0)
+ adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE;
+
+ return true;
+}
+
+static void fimd_mode_set(void *in_ctx, const struct drm_display_mode *in_mode)
+{
+ struct fimd_context *ctx = in_ctx;
+ struct fimd_mode_data *mode = &ctx->mode;
+ int hblank, vblank;
+
+ vblank = in_mode->crtc_vblank_end - in_mode->crtc_vblank_start;
+ mode->vtotal = in_mode->crtc_vtotal;
+ mode->vdisplay = in_mode->crtc_vdisplay;
+ mode->vsync_len = in_mode->crtc_vsync_end - in_mode->crtc_vsync_start;
+ mode->vbpd = (vblank - mode->vsync_len) / 2;
+ mode->vfpd = vblank - mode->vsync_len - mode->vbpd;
+
+ hblank = in_mode->crtc_hblank_end - in_mode->crtc_hblank_start;
+ mode->htotal = in_mode->crtc_htotal;
+ mode->hdisplay = in_mode->crtc_hdisplay;
+ mode->hsync_len = in_mode->crtc_hsync_end - in_mode->crtc_hsync_start;
+ mode->hbpd = (hblank - mode->hsync_len) / 2;
+ mode->hfpd = hblank - mode->hsync_len - mode->hbpd;
+
+ mode->clkdiv = fimd_calc_clkdiv(ctx, in_mode);
+}
+
static void fimd_commit(void *in_ctx)
{
struct fimd_context *ctx = in_ctx;
- struct exynos_drm_panel_info *panel = &ctx->panel;
- struct videomode *vm = &panel->vm;
+ struct fimd_mode_data *mode = &ctx->mode;
struct fimd_driver_data *driver_data;
u32 val;
@@ -570,26 +627,30 @@ static void fimd_commit(void *in_ctx)
if (ctx->suspended)
return;
+ /* nothing to do if we haven't set the mode yet */
+ if (mode->htotal == 0 || mode->vtotal == 0)
+ return;
+
/* setup polarity values from machine code. */
writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
/* setup vertical timing values. */
- val = VIDTCON0_VBPD(vm->vback_porch - 1) |
- VIDTCON0_VFPD(vm->vfront_porch - 1) |
- VIDTCON0_VSPW(vm->vsync_len - 1);
+ val = VIDTCON0_VBPD(mode->vbpd - 1) |
+ VIDTCON0_VFPD(mode->vfpd - 1) |
+ VIDTCON0_VSPW(mode->vsync_len - 1);
writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
/* setup horizontal timing values. */
- val = VIDTCON1_HBPD(vm->hback_porch - 1) |
- VIDTCON1_HFPD(vm->hfront_porch - 1) |
- VIDTCON1_HSPW(vm->hsync_len - 1);
+ val = VIDTCON1_HBPD(mode->hbpd - 1) |
+ VIDTCON1_HFPD(mode->hfpd - 1) |
+ VIDTCON1_HSPW(mode->hsync_len - 1);
writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
/* setup horizontal and vertical display size. */
- val = VIDTCON2_LINEVAL(vm->vactive - 1) |
- VIDTCON2_HOZVAL(vm->hactive - 1) |
- VIDTCON2_LINEVAL_E(vm->vactive - 1) |
- VIDTCON2_HOZVAL_E(vm->hactive - 1);
+ val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
+ VIDTCON2_HOZVAL(mode->hdisplay - 1) |
+ VIDTCON2_LINEVAL_E(mode->vdisplay - 1) |
+ VIDTCON2_HOZVAL_E(mode->hdisplay - 1);
writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
/* setup clock source, clock divider, enable dma. */
@@ -601,8 +662,8 @@ static void fimd_commit(void *in_ctx)
val |= VIDCON0_CLKSEL_LCD;
}
- if (ctx->clkdiv > 1)
- val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
+ if (mode->clkdiv > 1)
+ val |= VIDCON0_CLKVAL_F(mode->clkdiv - 1) | VIDCON0_CLKDIR;
else
val &= ~VIDCON0_CLKDIR; /* 1:1 clock */
@@ -696,6 +757,8 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
.remove = fimd_mgr_remove,
.dpms = fimd_dpms,
.apply = fimd_apply,
+ .mode_fixup = fimd_mode_fixup,
+ .mode_set = fimd_mode_set,
.commit = fimd_commit,
.enable_vblank = fimd_enable_vblank,
.disable_vblank = fimd_disable_vblank,
@@ -737,56 +800,6 @@ out:
return IRQ_HANDLED;
}
-static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
-{
- struct videomode *vm = &ctx->panel.vm;
- unsigned long clk;
-
- ctx->bus_clk = devm_clk_get(dev, "fimd");
- if (IS_ERR(ctx->bus_clk)) {
- dev_err(dev, "failed to get bus clock\n");
- return PTR_ERR(ctx->bus_clk);
- }
-
- ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
- if (IS_ERR(ctx->lcd_clk)) {
- dev_err(dev, "failed to get lcd clock\n");
- return PTR_ERR(ctx->lcd_clk);
- }
-
- clk = clk_get_rate(ctx->lcd_clk);
- if (clk == 0) {
- dev_err(dev, "error getting sclk_fimd clock rate\n");
- return -EINVAL;
- }
-
- if (vm->pixelclock == 0) {
- unsigned long c;
- c = vm->hactive + vm->hback_porch + vm->hfront_porch +
- vm->hsync_len;
- c *= vm->vactive + vm->vback_porch + vm->vfront_porch +
- vm->vsync_len;
- vm->pixelclock = c * FIMD_DEFAULT_FRAMERATE;
- if (vm->pixelclock == 0) {
- dev_err(dev, "incorrect display timings\n");
- return -EINVAL;
- }
- dev_warn(dev, "pixel clock recalculated to %luHz (%dHz frame rate)\n",
- vm->pixelclock, FIMD_DEFAULT_FRAMERATE);
- }
- ctx->clkdiv = DIV_ROUND_UP(clk, vm->pixelclock);
- if (ctx->clkdiv > 256) {
- dev_warn(dev, "calculated pixel clock divider too high (%u), lowered to 256\n",
- ctx->clkdiv);
- ctx->clkdiv = 256;
- }
- vm->pixelclock = clk / ctx->clkdiv;
- DRM_DEBUG_KMS("pixel clock = %lu, clkdiv = %d\n", vm->pixelclock,
- ctx->clkdiv);
-
- return 0;
-}
-
static void fimd_clear_win(struct fimd_context *ctx, int win)
{
writel(0, ctx->regs + WINCON(win));
@@ -916,9 +929,17 @@ static int fimd_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = fimd_configure_clocks(ctx, dev);
- if (ret)
- return ret;
+ ctx->bus_clk = devm_clk_get(dev, "fimd");
+ if (IS_ERR(ctx->bus_clk)) {
+ dev_err(dev, "failed to get bus clock\n");
+ return PTR_ERR(ctx->bus_clk);
+ }
+
+ ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
+ if (IS_ERR(ctx->lcd_clk)) {
+ dev_err(dev, "failed to get lcd clock\n");
+ return PTR_ERR(ctx->lcd_clk);
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 20/23] drm/exynos: Remove unused/useless fimd_context members
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (18 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 19/23] drm/exynos: Use mode_set to configure fimd Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 21/23] drm/exynos: Move dp driver from video/ to drm/ Sean Paul
` (3 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch removes a few fimd_context members which are either entirely
unused or unneeded.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 1b128cf..f2d7058 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -121,8 +121,6 @@ struct fimd_mode_data {
struct fimd_context {
struct device *dev;
struct drm_device *drm_dev;
- int irq;
- struct drm_crtc *crtc;
struct clk *bus_clk;
struct clk *lcd_clk;
void __iomem *regs;
@@ -134,7 +132,6 @@ struct fimd_context {
u32 vidcon1;
bool suspended;
int pipe;
- struct mutex lock;
wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event;
@@ -545,8 +542,6 @@ static void fimd_dpms(void *in_ctx, int mode)
DRM_DEBUG_KMS("%d\n", mode);
- mutex_lock(&ctx->lock);
-
switch (mode) {
case DRM_MODE_DPMS_ON:
/*
@@ -568,8 +563,6 @@ static void fimd_dpms(void *in_ctx, int mode)
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
break;
}
-
- mutex_unlock(&ctx->lock);
}
static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
@@ -953,9 +946,7 @@ static int fimd_probe(struct platform_device *pdev)
return -ENXIO;
}
- ctx->irq = res->start;
-
- ret = devm_request_irq(dev, ctx->irq, fimd_irq_handler,
+ ret = devm_request_irq(dev, res->start, fimd_irq_handler,
0, "drm_fimd", ctx);
if (ret) {
dev_err(dev, "irq request failed.\n");
@@ -966,8 +957,6 @@ static int fimd_probe(struct platform_device *pdev)
DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
atomic_set(&ctx->wait_vsync_event, 0);
- mutex_init(&ctx->lock);
-
platform_set_drvdata(pdev, ctx);
pm_runtime_enable(dev);
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 21/23] drm/exynos: Move dp driver from video/ to drm/
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (19 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 20/23] drm/exynos: Remove unused/useless fimd_context members Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 22/23] drm/exynos: Move display implementation into dp Sean Paul
` (2 subsequent siblings)
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch moves the code from video/ to drm/
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
drivers/gpu/drm/exynos/Kconfig | 7 +
drivers/gpu/drm/exynos/Makefile | 1 +
drivers/gpu/drm/exynos/exynos_dp_core.c | 1213 ++++++++++++++++++++++++++++++
drivers/gpu/drm/exynos/exynos_dp_core.h | 210 ++++++
drivers/gpu/drm/exynos/exynos_dp_reg.c | 1245 +++++++++++++++++++++++++++++++
drivers/gpu/drm/exynos/exynos_dp_reg.h | 366 +++++++++
drivers/video/exynos/Kconfig | 7 -
drivers/video/exynos/Makefile | 1 -
drivers/video/exynos/exynos_dp_core.c | 1213 ------------------------------
drivers/video/exynos/exynos_dp_core.h | 210 ------
drivers/video/exynos/exynos_dp_reg.c | 1245 -------------------------------
drivers/video/exynos/exynos_dp_reg.h | 366 ---------
12 files changed, 3042 insertions(+), 3042 deletions(-)
create mode 100644 drivers/gpu/drm/exynos/exynos_dp_core.c
create mode 100644 drivers/gpu/drm/exynos/exynos_dp_core.h
create mode 100644 drivers/gpu/drm/exynos/exynos_dp_reg.c
create mode 100644 drivers/gpu/drm/exynos/exynos_dp_reg.h
delete mode 100644 drivers/video/exynos/exynos_dp_core.c
delete mode 100644 drivers/video/exynos/exynos_dp_core.h
delete mode 100644 drivers/video/exynos/exynos_dp_reg.c
delete mode 100644 drivers/video/exynos/exynos_dp_reg.h
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 45b6ef5..3ace74f 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -30,6 +30,13 @@ config DRM_EXYNOS_FIMD
help
Choose this option if you want to use Exynos FIMD for DRM.
+config DRM_EXYNOS_DP
+ bool "EXYNOS DRM DP driver support"
+ depends on ARCH_EXYNOS
+ default n
+ help
+ This enables support for DP device.
+
config DRM_EXYNOS_HDMI
bool "Exynos DRM HDMI"
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index afbe499..fc8555c 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -11,6 +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_DP) += exynos_dp_core.o exynos_dp_reg.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
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
new file mode 100644
index 0000000..089ae22
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -0,0 +1,1213 @@
+/*
+ * Samsung SoC DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@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 <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+
+#include <video/exynos_dp.h>
+
+#include "exynos_dp_core.h"
+
+static int exynos_dp_init_dp(struct exynos_dp_device *dp)
+{
+ exynos_dp_reset(dp);
+
+ exynos_dp_swreset(dp);
+
+ exynos_dp_init_analog_param(dp);
+ exynos_dp_init_interrupt(dp);
+
+ /* SW defined function Normal operation */
+ exynos_dp_enable_sw_function(dp);
+
+ exynos_dp_config_interrupt(dp);
+ exynos_dp_init_analog_func(dp);
+
+ exynos_dp_init_hpd(dp);
+ exynos_dp_init_aux(dp);
+
+ return 0;
+}
+
+static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
+{
+ int timeout_loop = 0;
+
+ while (exynos_dp_get_plug_in_status(dp) != 0) {
+ timeout_loop++;
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "failed to get hpd plug status\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(10, 11);
+ }
+
+ return 0;
+}
+
+static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
+{
+ int i;
+ unsigned char sum = 0;
+
+ for (i = 0; i < EDID_BLOCK_LENGTH; i++)
+ sum = sum + edid_data[i];
+
+ return sum;
+}
+
+static int exynos_dp_read_edid(struct exynos_dp_device *dp)
+{
+ unsigned char edid[EDID_BLOCK_LENGTH * 2];
+ unsigned int extend_block = 0;
+ unsigned char sum;
+ unsigned char test_vector;
+ int retval;
+
+ /*
+ * EDID device address is 0x50.
+ * However, if necessary, you must have set upper address
+ * into E-EDID in I2C device, 0x30.
+ */
+
+ /* Read Extension Flag, Number of 128-byte EDID extension blocks */
+ retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+ EDID_EXTENSION_FLAG,
+ &extend_block);
+ if (retval)
+ return retval;
+
+ if (extend_block > 0) {
+ dev_dbg(dp->dev, "EDID data includes a single extension!\n");
+
+ /* Read EDID data */
+ retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+ EDID_HEADER_PATTERN,
+ EDID_BLOCK_LENGTH,
+ &edid[EDID_HEADER_PATTERN]);
+ if (retval != 0) {
+ dev_err(dp->dev, "EDID Read failed!\n");
+ return -EIO;
+ }
+ sum = exynos_dp_calc_edid_check_sum(edid);
+ if (sum != 0) {
+ dev_err(dp->dev, "EDID bad checksum!\n");
+ return -EIO;
+ }
+
+ /* Read additional EDID data */
+ retval = exynos_dp_read_bytes_from_i2c(dp,
+ I2C_EDID_DEVICE_ADDR,
+ EDID_BLOCK_LENGTH,
+ EDID_BLOCK_LENGTH,
+ &edid[EDID_BLOCK_LENGTH]);
+ if (retval != 0) {
+ dev_err(dp->dev, "EDID Read failed!\n");
+ return -EIO;
+ }
+ sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
+ if (sum != 0) {
+ dev_err(dp->dev, "EDID bad checksum!\n");
+ return -EIO;
+ }
+
+ exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
+ &test_vector);
+ if (test_vector & DPCD_TEST_EDID_READ) {
+ exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TEST_EDID_CHECKSUM,
+ edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
+ exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TEST_RESPONSE,
+ DPCD_TEST_EDID_CHECKSUM_WRITE);
+ }
+ } else {
+ dev_info(dp->dev, "EDID data does not include any extensions.\n");
+
+ /* Read EDID data */
+ retval = exynos_dp_read_bytes_from_i2c(dp,
+ I2C_EDID_DEVICE_ADDR,
+ EDID_HEADER_PATTERN,
+ EDID_BLOCK_LENGTH,
+ &edid[EDID_HEADER_PATTERN]);
+ if (retval != 0) {
+ dev_err(dp->dev, "EDID Read failed!\n");
+ return -EIO;
+ }
+ sum = exynos_dp_calc_edid_check_sum(edid);
+ if (sum != 0) {
+ dev_err(dp->dev, "EDID bad checksum!\n");
+ return -EIO;
+ }
+
+ exynos_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_TEST_REQUEST,
+ &test_vector);
+ if (test_vector & DPCD_TEST_EDID_READ) {
+ exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TEST_EDID_CHECKSUM,
+ edid[EDID_CHECKSUM]);
+ exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TEST_RESPONSE,
+ DPCD_TEST_EDID_CHECKSUM_WRITE);
+ }
+ }
+
+ dev_err(dp->dev, "EDID Read success!\n");
+ return 0;
+}
+
+static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
+{
+ u8 buf[12];
+ int i;
+ int retval;
+
+ /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
+ retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV,
+ 12, buf);
+ if (retval)
+ return retval;
+
+ /* Read EDID */
+ for (i = 0; i < 3; i++) {
+ retval = exynos_dp_read_edid(dp);
+ if (!retval)
+ break;
+ }
+
+ return retval;
+}
+
+static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
+ bool enable)
+{
+ u8 data;
+
+ exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
+
+ if (enable)
+ exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
+ DPCD_ENHANCED_FRAME_EN |
+ DPCD_LANE_COUNT_SET(data));
+ else
+ exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
+ DPCD_LANE_COUNT_SET(data));
+}
+
+static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
+{
+ u8 data;
+ int retval;
+
+ exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+ retval = DPCD_ENHANCED_FRAME_CAP(data);
+
+ return retval;
+}
+
+static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
+{
+ u8 data;
+
+ data = exynos_dp_is_enhanced_mode_available(dp);
+ exynos_dp_enable_rx_to_enhanced_mode(dp, data);
+ exynos_dp_enable_enhanced_mode(dp, data);
+}
+
+static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
+{
+ exynos_dp_set_training_pattern(dp, DP_NONE);
+
+ exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ DPCD_TRAINING_PATTERN_DISABLED);
+}
+
+static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
+ int pre_emphasis, int lane)
+{
+ switch (lane) {
+ case 0:
+ exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
+ break;
+ case 1:
+ exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
+ break;
+
+ case 2:
+ exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
+ break;
+
+ case 3:
+ exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
+ break;
+ }
+}
+
+static int exynos_dp_link_start(struct exynos_dp_device *dp)
+{
+ u8 buf[4];
+ int lane, lane_count, pll_tries, retval;
+
+ lane_count = dp->link_train.lane_count;
+
+ dp->link_train.lt_state = CLOCK_RECOVERY;
+ dp->link_train.eq_loop = 0;
+
+ for (lane = 0; lane < lane_count; lane++)
+ dp->link_train.cr_loop[lane] = 0;
+
+ /* Set link rate and count as you want to establish*/
+ exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
+ exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
+
+ /* Setup RX configuration */
+ buf[0] = dp->link_train.link_rate;
+ buf[1] = dp->link_train.lane_count;
+ retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
+ 2, buf);
+ if (retval)
+ return retval;
+
+ /* Set TX pre-emphasis to minimum */
+ for (lane = 0; lane < lane_count; lane++)
+ exynos_dp_set_lane_lane_pre_emphasis(dp,
+ PRE_EMPHASIS_LEVEL_0, lane);
+
+ /* Wait for PLL lock */
+ pll_tries = 0;
+ while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+ if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
+ dev_err(dp->dev, "Wait for PLL lock timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ pll_tries++;
+ usleep_range(90, 120);
+ }
+
+ /* Set training pattern 1 */
+ exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
+
+ /* Set RX training pattern */
+ retval = exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
+ if (retval)
+ return retval;
+
+ for (lane = 0; lane < lane_count; lane++)
+ buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
+ DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
+
+ retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
+ lane_count, buf);
+
+ return retval;
+}
+
+static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
+{
+ int shift = (lane & 1) * 4;
+ u8 link_value = link_status[lane>>1];
+
+ return (link_value >> shift) & 0xf;
+}
+
+static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
+{
+ int lane;
+ u8 lane_status;
+
+ for (lane = 0; lane < lane_count; lane++) {
+ lane_status = exynos_dp_get_lane_status(link_status, lane);
+ if ((lane_status & DPCD_LANE_CR_DONE) == 0)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
+ int lane_count)
+{
+ int lane;
+ u8 lane_status;
+
+ if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
+ return -EINVAL;
+
+ for (lane = 0; lane < lane_count; lane++) {
+ lane_status = exynos_dp_get_lane_status(link_status, lane);
+ lane_status &= DPCD_CHANNEL_EQ_BITS;
+ if (lane_status != DPCD_CHANNEL_EQ_BITS)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
+ int lane)
+{
+ int shift = (lane & 1) * 4;
+ u8 link_value = adjust_request[lane>>1];
+
+ return (link_value >> shift) & 0x3;
+}
+
+static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
+ u8 adjust_request[2],
+ int lane)
+{
+ int shift = (lane & 1) * 4;
+ u8 link_value = adjust_request[lane>>1];
+
+ return ((link_value >> shift) & 0xc) >> 2;
+}
+
+static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
+ u8 training_lane_set, int lane)
+{
+ switch (lane) {
+ case 0:
+ exynos_dp_set_lane0_link_training(dp, training_lane_set);
+ break;
+ case 1:
+ exynos_dp_set_lane1_link_training(dp, training_lane_set);
+ break;
+
+ case 2:
+ exynos_dp_set_lane2_link_training(dp, training_lane_set);
+ break;
+
+ case 3:
+ exynos_dp_set_lane3_link_training(dp, training_lane_set);
+ break;
+ }
+}
+
+static unsigned int exynos_dp_get_lane_link_training(
+ struct exynos_dp_device *dp,
+ int lane)
+{
+ u32 reg;
+
+ switch (lane) {
+ case 0:
+ reg = exynos_dp_get_lane0_link_training(dp);
+ break;
+ case 1:
+ reg = exynos_dp_get_lane1_link_training(dp);
+ break;
+ case 2:
+ reg = exynos_dp_get_lane2_link_training(dp);
+ break;
+ case 3:
+ reg = exynos_dp_get_lane3_link_training(dp);
+ break;
+ default:
+ WARN_ON(1);
+ return 0;
+ }
+
+ return reg;
+}
+
+static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
+{
+ exynos_dp_training_pattern_dis(dp);
+ exynos_dp_set_enhanced_mode(dp);
+
+ dp->link_train.lt_state = FAILED;
+}
+
+static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
+ u8 adjust_request[2])
+{
+ int lane, lane_count;
+ u8 voltage_swing, pre_emphasis, training_lane;
+
+ lane_count = dp->link_train.lane_count;
+ for (lane = 0; lane < lane_count; lane++) {
+ voltage_swing = exynos_dp_get_adjust_request_voltage(
+ adjust_request, lane);
+ pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+ adjust_request, lane);
+ training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+ DPCD_PRE_EMPHASIS_SET(pre_emphasis);
+
+ if (voltage_swing == VOLTAGE_LEVEL_3)
+ training_lane |= DPCD_MAX_SWING_REACHED;
+ if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
+ training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
+
+ dp->link_train.training_lane[lane] = training_lane;
+ }
+}
+
+static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
+{
+ int lane, lane_count, retval;
+ u8 voltage_swing, pre_emphasis, training_lane;
+ u8 link_status[2], adjust_request[2];
+
+ usleep_range(100, 101);
+
+ lane_count = dp->link_train.lane_count;
+
+ retval = exynos_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
+ if (retval)
+ return retval;
+
+ retval = exynos_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
+ if (retval)
+ return retval;
+
+ if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
+ /* set training pattern 2 for EQ */
+ exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
+
+ retval = exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ DPCD_SCRAMBLING_DISABLED |
+ DPCD_TRAINING_PATTERN_2);
+ if (retval)
+ return retval;
+
+ dev_info(dp->dev, "Link Training Clock Recovery success\n");
+ dp->link_train.lt_state = EQUALIZER_TRAINING;
+ } else {
+ for (lane = 0; lane < lane_count; lane++) {
+ training_lane = exynos_dp_get_lane_link_training(
+ dp, lane);
+ voltage_swing = exynos_dp_get_adjust_request_voltage(
+ adjust_request, lane);
+ pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+ adjust_request, lane);
+
+ if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
+ voltage_swing &&
+ DPCD_PRE_EMPHASIS_GET(training_lane) ==
+ pre_emphasis)
+ dp->link_train.cr_loop[lane]++;
+
+ if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
+ voltage_swing == VOLTAGE_LEVEL_3 ||
+ pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
+ dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
+ dp->link_train.cr_loop[lane],
+ voltage_swing, pre_emphasis);
+ exynos_dp_reduce_link_rate(dp);
+ return -EIO;
+ }
+ }
+ }
+
+ exynos_dp_get_adjust_training_lane(dp, adjust_request);
+
+ for (lane = 0; lane < lane_count; lane++)
+ exynos_dp_set_lane_link_training(dp,
+ dp->link_train.training_lane[lane], lane);
+
+ retval = exynos_dp_write_bytes_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
+ dp->link_train.training_lane);
+ if (retval)
+ return retval;
+
+ return retval;
+}
+
+static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
+{
+ int lane, lane_count, retval;
+ u32 reg;
+ u8 link_align, link_status[2], adjust_request[2];
+
+ usleep_range(400, 401);
+
+ lane_count = dp->link_train.lane_count;
+
+ retval = exynos_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
+ if (retval)
+ return retval;
+
+ if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
+ exynos_dp_reduce_link_rate(dp);
+ return -EIO;
+ }
+
+ retval = exynos_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
+ if (retval)
+ return retval;
+
+ retval = exynos_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
+ if (retval)
+ return retval;
+
+ exynos_dp_get_adjust_training_lane(dp, adjust_request);
+
+ if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
+ /* traing pattern Set to Normal */
+ exynos_dp_training_pattern_dis(dp);
+
+ dev_info(dp->dev, "Link Training success!\n");
+
+ exynos_dp_get_link_bandwidth(dp, ®);
+ dp->link_train.link_rate = reg;
+ dev_dbg(dp->dev, "final bandwidth = %.2x\n",
+ dp->link_train.link_rate);
+
+ exynos_dp_get_lane_count(dp, ®);
+ dp->link_train.lane_count = reg;
+ dev_dbg(dp->dev, "final lane count = %.2x\n",
+ dp->link_train.lane_count);
+
+ /* set enhanced mode if available */
+ exynos_dp_set_enhanced_mode(dp);
+ dp->link_train.lt_state = FINISHED;
+
+ return 0;
+ }
+
+ /* not all locked */
+ dp->link_train.eq_loop++;
+
+ if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
+ dev_err(dp->dev, "EQ Max loop\n");
+ exynos_dp_reduce_link_rate(dp);
+ return -EIO;
+ }
+
+ for (lane = 0; lane < lane_count; lane++)
+ exynos_dp_set_lane_link_training(dp,
+ dp->link_train.training_lane[lane], lane);
+
+ retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
+ lane_count, dp->link_train.training_lane);
+
+ return retval;
+}
+
+static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
+ u8 *bandwidth)
+{
+ u8 data;
+
+ /*
+ * For DP rev.1.1, Maximum link rate of Main Link lanes
+ * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
+ */
+ exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
+ *bandwidth = data;
+}
+
+static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
+ u8 *lane_count)
+{
+ u8 data;
+
+ /*
+ * For DP rev.1.1, Maximum number of Main Link lanes
+ * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
+ */
+ exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+ *lane_count = DPCD_MAX_LANE_COUNT(data);
+}
+
+static void exynos_dp_init_training(struct exynos_dp_device *dp,
+ enum link_lane_count_type max_lane,
+ enum link_rate_type max_rate)
+{
+ /*
+ * MACRO_RST must be applied after the PLL_LOCK to avoid
+ * the DP inter pair skew issue for at least 10 us
+ */
+ exynos_dp_reset_macro(dp);
+
+ /* Initialize by reading RX's DPCD */
+ exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
+ exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
+
+ if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
+ (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
+ dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
+ dp->link_train.link_rate);
+ dp->link_train.link_rate = LINK_RATE_1_62GBPS;
+ }
+
+ if (dp->link_train.lane_count == 0) {
+ dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
+ dp->link_train.lane_count);
+ dp->link_train.lane_count = (u8)LANE_COUNT1;
+ }
+
+ /* Setup TX lane count & rate */
+ if (dp->link_train.lane_count > max_lane)
+ dp->link_train.lane_count = max_lane;
+ if (dp->link_train.link_rate > max_rate)
+ dp->link_train.link_rate = max_rate;
+
+ /* All DP analog module power up */
+ exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
+}
+
+static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
+{
+ int retval = 0, training_finished = 0;
+
+ dp->link_train.lt_state = START;
+
+ /* Process here */
+ while (!retval && !training_finished) {
+ switch (dp->link_train.lt_state) {
+ case START:
+ retval = exynos_dp_link_start(dp);
+ if (retval)
+ dev_err(dp->dev, "LT link start failed!\n");
+ break;
+ case CLOCK_RECOVERY:
+ retval = exynos_dp_process_clock_recovery(dp);
+ if (retval)
+ dev_err(dp->dev, "LT CR failed!\n");
+ break;
+ case EQUALIZER_TRAINING:
+ retval = exynos_dp_process_equalizer_training(dp);
+ if (retval)
+ dev_err(dp->dev, "LT EQ failed!\n");
+ break;
+ case FINISHED:
+ training_finished = 1;
+ break;
+ case FAILED:
+ return -EREMOTEIO;
+ }
+ }
+ if (retval)
+ dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
+
+ return retval;
+}
+
+static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
+ u32 count,
+ u32 bwtype)
+{
+ int i;
+ int retval;
+
+ for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
+ exynos_dp_init_training(dp, count, bwtype);
+ retval = exynos_dp_sw_link_training(dp);
+ if (retval == 0)
+ break;
+
+ usleep_range(100, 110);
+ }
+
+ return retval;
+}
+
+static int exynos_dp_config_video(struct exynos_dp_device *dp)
+{
+ int retval = 0;
+ int timeout_loop = 0;
+ int done_count = 0;
+
+ exynos_dp_config_video_slave_mode(dp);
+
+ exynos_dp_set_video_color_format(dp);
+
+ if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+ dev_err(dp->dev, "PLL is not locked yet.\n");
+ return -EINVAL;
+ }
+
+ for (;;) {
+ timeout_loop++;
+ if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
+ break;
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "Timeout of video streamclk ok\n");
+ return -ETIMEDOUT;
+ }
+
+ usleep_range(1, 2);
+ }
+
+ /* Set to use the register calculated M/N video */
+ exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
+
+ /* For video bist, Video timing must be generated by register */
+ exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
+
+ /* Disable video mute */
+ exynos_dp_enable_video_mute(dp, 0);
+
+ /* Configure video slave mode */
+ exynos_dp_enable_video_master(dp, 0);
+
+ /* Enable video */
+ exynos_dp_start_video(dp);
+
+ timeout_loop = 0;
+
+ for (;;) {
+ timeout_loop++;
+ if (exynos_dp_is_video_stream_on(dp) == 0) {
+ done_count++;
+ if (done_count > 10)
+ break;
+ } else if (done_count) {
+ done_count = 0;
+ }
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "Timeout of video streamclk ok\n");
+ return -ETIMEDOUT;
+ }
+
+ usleep_range(1000, 1001);
+ }
+
+ if (retval != 0)
+ dev_err(dp->dev, "Video stream is not detected!\n");
+
+ return retval;
+}
+
+static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
+{
+ u8 data;
+
+ if (enable) {
+ exynos_dp_enable_scrambling(dp);
+
+ exynos_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ &data);
+ exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ (u8)(data & ~DPCD_SCRAMBLING_DISABLED));
+ } else {
+ exynos_dp_disable_scrambling(dp);
+
+ exynos_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ &data);
+ exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ (u8)(data | DPCD_SCRAMBLING_DISABLED));
+ }
+}
+
+static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
+{
+ struct exynos_dp_device *dp = arg;
+
+ enum dp_irq_type irq_type;
+
+ irq_type = exynos_dp_get_irq_type(dp);
+ switch (irq_type) {
+ case DP_IRQ_TYPE_HP_CABLE_IN:
+ dev_dbg(dp->dev, "Received irq - cable in\n");
+ schedule_work(&dp->hotplug_work);
+ exynos_dp_clear_hotplug_interrupts(dp);
+ break;
+ case DP_IRQ_TYPE_HP_CABLE_OUT:
+ dev_dbg(dp->dev, "Received irq - cable out\n");
+ exynos_dp_clear_hotplug_interrupts(dp);
+ break;
+ case DP_IRQ_TYPE_HP_CHANGE:
+ /*
+ * We get these change notifications once in a while, but there
+ * is nothing we can do with them. Just ignore it for now and
+ * only handle cable changes.
+ */
+ dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
+ exynos_dp_clear_hotplug_interrupts(dp);
+ break;
+ default:
+ dev_err(dp->dev, "Received irq - unknown type!\n");
+ break;
+ }
+ return IRQ_HANDLED;
+}
+
+static void exynos_dp_hotplug(struct work_struct *work)
+{
+ struct exynos_dp_device *dp;
+ int ret;
+
+ dp = container_of(work, struct exynos_dp_device, hotplug_work);
+
+ ret = exynos_dp_detect_hpd(dp);
+ if (ret) {
+ /* Cable has been disconnected, we're done */
+ return;
+ }
+
+ ret = exynos_dp_handle_edid(dp);
+ if (ret) {
+ dev_err(dp->dev, "unable to handle edid\n");
+ return;
+ }
+
+ ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
+ dp->video_info->link_rate);
+ if (ret) {
+ dev_err(dp->dev, "unable to do link train\n");
+ return;
+ }
+
+ exynos_dp_enable_scramble(dp, 1);
+ exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
+ exynos_dp_enable_enhanced_mode(dp, 1);
+
+ exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
+ exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
+
+ exynos_dp_init_video(dp);
+ ret = exynos_dp_config_video(dp);
+ if (ret)
+ dev_err(dp->dev, "unable to config video\n");
+}
+
+#ifdef CONFIG_OF
+static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
+{
+ struct device_node *dp_node = dev->of_node;
+ struct exynos_dp_platdata *pd;
+ struct video_info *dp_video_config;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ dev_err(dev, "memory allocation for pdata failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ dp_video_config = devm_kzalloc(dev,
+ sizeof(*dp_video_config), GFP_KERNEL);
+
+ if (!dp_video_config) {
+ dev_err(dev, "memory allocation for video config failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ pd->video_info = dp_video_config;
+
+ dp_video_config->h_sync_polarity =
+ of_property_read_bool(dp_node, "hsync-active-high");
+
+ dp_video_config->v_sync_polarity =
+ of_property_read_bool(dp_node, "vsync-active-high");
+
+ dp_video_config->interlaced =
+ of_property_read_bool(dp_node, "interlaced");
+
+ if (of_property_read_u32(dp_node, "samsung,color-space",
+ &dp_video_config->color_space)) {
+ dev_err(dev, "failed to get color-space\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(dp_node, "samsung,dynamic-range",
+ &dp_video_config->dynamic_range)) {
+ dev_err(dev, "failed to get dynamic-range\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
+ &dp_video_config->ycbcr_coeff)) {
+ dev_err(dev, "failed to get ycbcr-coeff\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(dp_node, "samsung,color-depth",
+ &dp_video_config->color_depth)) {
+ dev_err(dev, "failed to get color-depth\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(dp_node, "samsung,link-rate",
+ &dp_video_config->link_rate)) {
+ dev_err(dev, "failed to get link-rate\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(dp_node, "samsung,lane-count",
+ &dp_video_config->lane_count)) {
+ dev_err(dev, "failed to get lane-count\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return pd;
+}
+
+static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
+{
+ struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
+ u32 phy_base;
+ int ret = 0;
+
+ dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
+ if (!dp_phy_node) {
+ dev_err(dp->dev, "could not find dptx-phy node\n");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
+ dev_err(dp->dev, "failed to get reg for dptx-phy\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
+ &dp->enable_mask)) {
+ dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dp->phy_addr = ioremap(phy_base, SZ_4);
+ if (!dp->phy_addr) {
+ dev_err(dp->dev, "failed to ioremap dp-phy\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+err:
+ of_node_put(dp_phy_node);
+
+ return ret;
+}
+
+static void exynos_dp_phy_init(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = __raw_readl(dp->phy_addr);
+ reg |= dp->enable_mask;
+ __raw_writel(reg, dp->phy_addr);
+}
+
+static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = __raw_readl(dp->phy_addr);
+ reg &= ~(dp->enable_mask);
+ __raw_writel(reg, dp->phy_addr);
+}
+#else
+static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
+{
+ return NULL;
+}
+
+static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
+{
+ return -EINVAL;
+}
+
+static void exynos_dp_phy_init(struct exynos_dp_device *dp)
+{
+ return;
+}
+
+static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
+{
+ return;
+}
+#endif /* CONFIG_OF */
+
+static int exynos_dp_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct exynos_dp_device *dp;
+ struct exynos_dp_platdata *pdata;
+
+ int ret = 0;
+
+ dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
+ GFP_KERNEL);
+ if (!dp) {
+ dev_err(&pdev->dev, "no memory for device data\n");
+ return -ENOMEM;
+ }
+
+ dp->dev = &pdev->dev;
+
+ if (pdev->dev.of_node) {
+ pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+
+ ret = exynos_dp_dt_parse_phydata(dp);
+ if (ret)
+ return ret;
+ } else {
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+ }
+
+ dp->clock = devm_clk_get(&pdev->dev, "dp");
+ if (IS_ERR(dp->clock)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ return PTR_ERR(dp->clock);
+ }
+
+ clk_prepare_enable(dp->clock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dp->reg_base))
+ return PTR_ERR(dp->reg_base);
+
+ dp->irq = platform_get_irq(pdev, 0);
+ if (dp->irq == -ENXIO) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ return -ENODEV;
+ }
+
+ INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
+
+ dp->video_info = pdata->video_info;
+
+ if (pdev->dev.of_node) {
+ if (dp->phy_addr)
+ exynos_dp_phy_init(dp);
+ } else {
+ if (pdata->phy_init)
+ pdata->phy_init();
+ }
+
+ exynos_dp_init_dp(dp);
+
+ ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
+ "exynos-dp", dp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, dp);
+
+ return 0;
+}
+
+static int exynos_dp_remove(struct platform_device *pdev)
+{
+ struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
+ struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+
+ flush_work(&dp->hotplug_work);
+
+ if (pdev->dev.of_node) {
+ if (dp->phy_addr)
+ exynos_dp_phy_exit(dp);
+ } else {
+ if (pdata->phy_exit)
+ pdata->phy_exit();
+ }
+
+ clk_disable_unprepare(dp->clock);
+
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos_dp_suspend(struct device *dev)
+{
+ struct exynos_dp_platdata *pdata = dev->platform_data;
+ struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+ disable_irq(dp->irq);
+
+ flush_work(&dp->hotplug_work);
+
+ if (dev->of_node) {
+ if (dp->phy_addr)
+ exynos_dp_phy_exit(dp);
+ } else {
+ if (pdata->phy_exit)
+ pdata->phy_exit();
+ }
+
+ clk_disable_unprepare(dp->clock);
+
+ return 0;
+}
+
+static int exynos_dp_resume(struct device *dev)
+{
+ struct exynos_dp_platdata *pdata = dev->platform_data;
+ struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+ if (dev->of_node) {
+ if (dp->phy_addr)
+ exynos_dp_phy_init(dp);
+ } else {
+ if (pdata->phy_init)
+ pdata->phy_init();
+ }
+
+ clk_prepare_enable(dp->clock);
+
+ exynos_dp_init_dp(dp);
+
+ enable_irq(dp->irq);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_dp_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
+};
+
+static const struct of_device_id exynos_dp_match[] = {
+ { .compatible = "samsung,exynos5-dp" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_dp_match);
+
+static struct platform_driver exynos_dp_driver = {
+ .probe = exynos_dp_probe,
+ .remove = exynos_dp_remove,
+ .driver = {
+ .name = "exynos-dp",
+ .owner = THIS_MODULE,
+ .pm = &exynos_dp_pm_ops,
+ .of_match_table = of_match_ptr(exynos_dp_match),
+ },
+};
+
+module_platform_driver(exynos_dp_driver);
+
+MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC DP Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
new file mode 100644
index 0000000..6c567bbf
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -0,0 +1,210 @@
+/*
+ * Header file for Samsung DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@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_DP_CORE_H
+#define _EXYNOS_DP_CORE_H
+
+enum dp_irq_type {
+ DP_IRQ_TYPE_HP_CABLE_IN,
+ DP_IRQ_TYPE_HP_CABLE_OUT,
+ DP_IRQ_TYPE_HP_CHANGE,
+ DP_IRQ_TYPE_UNKNOWN,
+};
+
+struct link_train {
+ int eq_loop;
+ int cr_loop[4];
+
+ u8 link_rate;
+ u8 lane_count;
+ u8 training_lane[4];
+
+ enum link_training_state lt_state;
+};
+
+struct exynos_dp_device {
+ struct device *dev;
+ struct clk *clock;
+ unsigned int irq;
+ void __iomem *reg_base;
+ void __iomem *phy_addr;
+ unsigned int enable_mask;
+
+ struct video_info *video_info;
+ struct link_train link_train;
+ struct work_struct hotplug_work;
+};
+
+/* exynos_dp_reg.c */
+void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_stop_video(struct exynos_dp_device *dp);
+void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_init_analog_param(struct exynos_dp_device *dp);
+void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
+void exynos_dp_reset(struct exynos_dp_device *dp);
+void exynos_dp_swreset(struct exynos_dp_device *dp);
+void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
+enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
+void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
+ enum analog_power_block block,
+ bool enable);
+void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
+void exynos_dp_init_hpd(struct exynos_dp_device *dp);
+enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp);
+void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp);
+void exynos_dp_reset_aux(struct exynos_dp_device *dp);
+void exynos_dp_init_aux(struct exynos_dp_device *dp);
+int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
+void exynos_dp_enable_sw_function(struct exynos_dp_device *dp);
+int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp);
+int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char data);
+int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char *data);
+int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[]);
+int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[]);
+int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr);
+int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int *data);
+int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char edid[]);
+void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
+void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
+void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
+void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
+void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
+ enum pattern_set pattern);
+void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
+ u32 training_lane);
+void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
+ u32 training_lane);
+void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
+ u32 training_lane);
+void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
+ u32 training_lane);
+u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
+void exynos_dp_reset_macro(struct exynos_dp_device *dp);
+void exynos_dp_init_video(struct exynos_dp_device *dp);
+
+void exynos_dp_set_video_color_format(struct exynos_dp_device *dp);
+int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp);
+void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
+ enum clock_recovery_m_value_type type,
+ u32 m_value,
+ u32 n_value);
+void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type);
+void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_start_video(struct exynos_dp_device *dp);
+int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp);
+void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp);
+void exynos_dp_enable_scrambling(struct exynos_dp_device *dp);
+void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
+
+/* I2C EDID Chip ID, Slave Address */
+#define I2C_EDID_DEVICE_ADDR 0x50
+#define I2C_E_EDID_DEVICE_ADDR 0x30
+
+#define EDID_BLOCK_LENGTH 0x80
+#define EDID_HEADER_PATTERN 0x00
+#define EDID_EXTENSION_FLAG 0x7e
+#define EDID_CHECKSUM 0x7f
+
+/* Definition for DPCD Register */
+#define DPCD_ADDR_DPCD_REV 0x0000
+#define DPCD_ADDR_MAX_LINK_RATE 0x0001
+#define DPCD_ADDR_MAX_LANE_COUNT 0x0002
+#define DPCD_ADDR_LINK_BW_SET 0x0100
+#define DPCD_ADDR_LANE_COUNT_SET 0x0101
+#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102
+#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103
+#define DPCD_ADDR_LANE0_1_STATUS 0x0202
+#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204
+#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206
+#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207
+#define DPCD_ADDR_TEST_REQUEST 0x0218
+#define DPCD_ADDR_TEST_RESPONSE 0x0260
+#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261
+#define DPCD_ADDR_SINK_POWER_STATE 0x0600
+
+/* DPCD_ADDR_MAX_LANE_COUNT */
+#define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
+#define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
+
+/* DPCD_ADDR_LANE_COUNT_SET */
+#define DPCD_ENHANCED_FRAME_EN (0x1 << 7)
+#define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f)
+
+/* DPCD_ADDR_TRAINING_PATTERN_SET */
+#define DPCD_SCRAMBLING_DISABLED (0x1 << 5)
+#define DPCD_SCRAMBLING_ENABLED (0x0 << 5)
+#define DPCD_TRAINING_PATTERN_2 (0x2 << 0)
+#define DPCD_TRAINING_PATTERN_1 (0x1 << 0)
+#define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0)
+
+/* DPCD_ADDR_TRAINING_LANE0_SET */
+#define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5)
+#define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3)
+#define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3)
+#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3)
+#define DPCD_MAX_SWING_REACHED (0x1 << 2)
+#define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0)
+#define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3)
+#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0)
+
+/* DPCD_ADDR_LANE0_1_STATUS */
+#define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2)
+#define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1)
+#define DPCD_LANE_CR_DONE (0x1 << 0)
+#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \
+ DPCD_LANE_CHANNEL_EQ_DONE|\
+ DPCD_LANE_SYMBOL_LOCKED)
+
+/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
+#define DPCD_LINK_STATUS_UPDATED (0x1 << 7)
+#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6)
+#define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0)
+
+/* DPCD_ADDR_TEST_REQUEST */
+#define DPCD_TEST_EDID_READ (0x1 << 2)
+
+/* DPCD_ADDR_TEST_RESPONSE */
+#define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2)
+
+/* DPCD_ADDR_SINK_POWER_STATE */
+#define DPCD_SET_POWER_STATE_D0 (0x1 << 0)
+#define DPCD_SET_POWER_STATE_D4 (0x2 << 0)
+
+#endif /* _EXYNOS_DP_CORE_H */
diff --git a/drivers/gpu/drm/exynos/exynos_dp_reg.c b/drivers/gpu/drm/exynos/exynos_dp_reg.c
new file mode 100644
index 0000000..29d9d03
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_dp_reg.c
@@ -0,0 +1,1245 @@
+/*
+ * Samsung DP (Display port) register interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@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 <linux/device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <video/exynos_dp.h>
+
+#include "exynos_dp_core.h"
+#include "exynos_dp_reg.h"
+
+#define COMMON_INT_MASK_1 0
+#define COMMON_INT_MASK_2 0
+#define COMMON_INT_MASK_3 0
+#define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG)
+#define INT_STA_MASK INT_HPD
+
+void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+ reg |= HDCP_VIDEO_MUTE;
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+ reg &= ~HDCP_VIDEO_MUTE;
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+ }
+}
+
+void exynos_dp_stop_video(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+ reg &= ~VIDEO_EN;
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+}
+
+void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (enable)
+ reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
+ LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
+ else
+ reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
+ LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+
+ writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP);
+}
+
+void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = TX_TERMINAL_CTRL_50_OHM;
+ writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1);
+
+ reg = SEL_24M | TX_DVDD_BIT_1_0625V;
+ writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2);
+
+ reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
+ writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
+
+ reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
+ TX_CUR1_2X | TX_CUR_16_MA;
+ writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
+
+ reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
+ CH1_AMP_400_MV | CH0_AMP_400_MV;
+ writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL);
+}
+
+void exynos_dp_init_interrupt(struct exynos_dp_device *dp)
+{
+ /* Set interrupt pin assertion polarity as high */
+ writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL);
+
+ /* Clear pending regisers */
+ writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+ writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2);
+ writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3);
+ writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+ writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA);
+
+ /* 0:mask,1: unmask */
+ writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
+ writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
+ writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
+ writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
+ writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
+}
+
+void exynos_dp_reset(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ exynos_dp_stop_video(dp);
+ exynos_dp_enable_video_mute(dp, 0);
+
+ reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
+ AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
+ HDCP_FUNC_EN_N | SW_FUNC_EN_N;
+ writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+
+ reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
+ SERDES_FIFO_FUNC_EN_N |
+ LS_CLK_DOMAIN_FUNC_EN_N;
+ writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+
+ usleep_range(20, 30);
+
+ exynos_dp_lane_swap(dp, 0);
+
+ writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+ writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+ writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+ writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+
+ writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL);
+ writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL);
+
+ writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L);
+ writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H);
+
+ writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL);
+
+ writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST);
+
+ writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD);
+ writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN);
+
+ writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH);
+ writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH);
+
+ writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+}
+
+void exynos_dp_swreset(struct exynos_dp_device *dp)
+{
+ writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET);
+}
+
+void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ /* 0: mask, 1: unmask */
+ reg = COMMON_INT_MASK_1;
+ writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
+
+ reg = COMMON_INT_MASK_2;
+ writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
+
+ reg = COMMON_INT_MASK_3;
+ writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
+
+ reg = COMMON_INT_MASK_4;
+ writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
+
+ reg = INT_STA_MASK;
+ writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
+}
+
+enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+ if (reg & PLL_LOCK)
+ return PLL_LOCKED;
+ else
+ return PLL_UNLOCKED;
+}
+
+void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
+ reg |= DP_PLL_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
+ reg &= ~DP_PLL_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
+ }
+}
+
+void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
+ enum analog_power_block block,
+ bool enable)
+{
+ u32 reg;
+
+ switch (block) {
+ case AUX_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg |= AUX_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg &= ~AUX_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ }
+ break;
+ case CH0_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg |= CH0_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg &= ~CH0_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ }
+ break;
+ case CH1_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg |= CH1_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg &= ~CH1_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ }
+ break;
+ case CH2_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg |= CH2_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg &= ~CH2_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ }
+ break;
+ case CH3_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg |= CH3_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg &= ~CH3_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ }
+ break;
+ case ANALOG_TOTAL:
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg |= DP_PHY_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+ reg &= ~DP_PHY_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ }
+ break;
+ case POWER_ALL:
+ if (enable) {
+ reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
+ CH1_PD | CH0_PD;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+ } else {
+ writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
+{
+ u32 reg;
+ int timeout_loop = 0;
+
+ exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
+
+ reg = PLL_LOCK_CHG;
+ writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+
+ reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+ reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
+ writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+
+ /* Power up PLL */
+ if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+ exynos_dp_set_pll_power_down(dp, 0);
+
+ while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+ timeout_loop++;
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "failed to get pll lock status\n");
+ return;
+ }
+ usleep_range(10, 20);
+ }
+ }
+
+ /* Enable Serdes FIFO function and Link symbol clock domain module */
+ reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+ reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
+ | AUX_FUNC_EN_N);
+ writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = HOTPLUG_CHG | HPD_LOST | PLUG;
+ writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+
+ reg = INT_HPD;
+ writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
+}
+
+void exynos_dp_init_hpd(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ exynos_dp_clear_hotplug_interrupts(dp);
+
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+ reg &= ~(F_HPD | HPD_CTRL);
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+}
+
+enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ /* Parse hotplug interrupt status register */
+ reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+
+ if (reg & PLUG)
+ return DP_IRQ_TYPE_HP_CABLE_IN;
+
+ if (reg & HPD_LOST)
+ return DP_IRQ_TYPE_HP_CABLE_OUT;
+
+ if (reg & HOTPLUG_CHG)
+ return DP_IRQ_TYPE_HP_CHANGE;
+
+ return DP_IRQ_TYPE_UNKNOWN;
+}
+
+void exynos_dp_reset_aux(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ /* Disable AUX channel module */
+ reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+ reg |= AUX_FUNC_EN_N;
+ writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+void exynos_dp_init_aux(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ /* Clear inerrupts related to AUX channel */
+ reg = RPLY_RECEIV | AUX_ERR;
+ writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
+
+ exynos_dp_reset_aux(dp);
+
+ /* Disable AUX transaction H/W retry */
+ reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)|
+ AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ;
+
+ /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
+ reg = DEFER_CTRL_EN | DEFER_COUNT(1);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL);
+
+ /* Enable AUX channel module */
+ reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+ reg &= ~AUX_FUNC_EN_N;
+ writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+ if (reg & HPD_STATUS)
+ return 0;
+
+ return -EINVAL;
+}
+
+void exynos_dp_enable_sw_function(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+ reg &= ~SW_FUNC_EN_N;
+ writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+}
+
+int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
+{
+ int reg;
+ int retval = 0;
+ int timeout_loop = 0;
+
+ /* Enable AUX CH operation */
+ reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+ reg |= AUX_EN;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+
+ /* Is AUX CH command reply received? */
+ reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+ while (!(reg & RPLY_RECEIV)) {
+ timeout_loop++;
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "AUX CH command reply failed!\n");
+ return -ETIMEDOUT;
+ }
+ reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+ usleep_range(10, 11);
+ }
+
+ /* Clear interrupt source for AUX CH command reply */
+ writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA);
+
+ /* Clear interrupt source for AUX CH access error */
+ reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+ if (reg & AUX_ERR) {
+ writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA);
+ return -EREMOTEIO;
+ }
+
+ /* Check AUX CH error access status */
+ reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA);
+ if ((reg & AUX_STATUS_MASK) != 0) {
+ dev_err(dp->dev, "AUX CH error happens: %d\n\n",
+ reg & AUX_STATUS_MASK);
+ return -EREMOTEIO;
+ }
+
+ return retval;
+}
+
+int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char data)
+{
+ u32 reg;
+ int i;
+ int retval;
+
+ for (i = 0; i < 3; i++) {
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+ /* Select DPCD device address */
+ reg = AUX_ADDR_7_0(reg_addr);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+ reg = AUX_ADDR_15_8(reg_addr);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+ reg = AUX_ADDR_19_16(reg_addr);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+ /* Write data buffer */
+ reg = (unsigned int)data;
+ writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+ /*
+ * Set DisplayPort transaction and write 1 byte
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = exynos_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
+ }
+
+ return retval;
+}
+
+int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char *data)
+{
+ u32 reg;
+ int i;
+ int retval;
+
+ for (i = 0; i < 3; i++) {
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+ /* Select DPCD device address */
+ reg = AUX_ADDR_7_0(reg_addr);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+ reg = AUX_ADDR_15_8(reg_addr);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+ reg = AUX_ADDR_19_16(reg_addr);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+ /*
+ * Set DisplayPort transaction and read 1 byte
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = exynos_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
+ }
+
+ /* Read data buffer */
+ reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+ *data = (unsigned char)(reg & 0xff);
+
+ return retval;
+}
+
+int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[])
+{
+ u32 reg;
+ unsigned int start_offset;
+ unsigned int cur_data_count;
+ unsigned int cur_data_idx;
+ int i;
+ int retval = 0;
+
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+ start_offset = 0;
+ while (start_offset < count) {
+ /* Buffer size of AUX CH is 16 * 4bytes */
+ if ((count - start_offset) > 16)
+ cur_data_count = 16;
+ else
+ cur_data_count = count - start_offset;
+
+ for (i = 0; i < 3; i++) {
+ /* Select DPCD device address */
+ reg = AUX_ADDR_7_0(reg_addr + start_offset);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+ reg = AUX_ADDR_15_8(reg_addr + start_offset);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+ reg = AUX_ADDR_19_16(reg_addr + start_offset);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+ for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+ cur_data_idx++) {
+ reg = data[start_offset + cur_data_idx];
+ writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0
+ + 4 * cur_data_idx);
+ }
+
+ /*
+ * Set DisplayPort transaction and write
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_LENGTH(cur_data_count) |
+ AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = exynos_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
+ }
+
+ start_offset += cur_data_count;
+ }
+
+ return retval;
+}
+
+int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[])
+{
+ u32 reg;
+ unsigned int start_offset;
+ unsigned int cur_data_count;
+ unsigned int cur_data_idx;
+ int i;
+ int retval = 0;
+
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+ start_offset = 0;
+ while (start_offset < count) {
+ /* Buffer size of AUX CH is 16 * 4bytes */
+ if ((count - start_offset) > 16)
+ cur_data_count = 16;
+ else
+ cur_data_count = count - start_offset;
+
+ /* AUX CH Request Transaction process */
+ for (i = 0; i < 3; i++) {
+ /* Select DPCD device address */
+ reg = AUX_ADDR_7_0(reg_addr + start_offset);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+ reg = AUX_ADDR_15_8(reg_addr + start_offset);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+ reg = AUX_ADDR_19_16(reg_addr + start_offset);
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+ /*
+ * Set DisplayPort transaction and read
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_LENGTH(cur_data_count) |
+ AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = exynos_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
+ }
+
+ for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+ cur_data_idx++) {
+ reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
+ + 4 * cur_data_idx);
+ data[start_offset + cur_data_idx] =
+ (unsigned char)reg;
+ }
+
+ start_offset += cur_data_count;
+ }
+
+ return retval;
+}
+
+int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr)
+{
+ u32 reg;
+ int retval;
+
+ /* Set EDID device address */
+ reg = device_addr;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+ writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+ writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+ /* Set offset from base address of EDID device */
+ writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+ /*
+ * Set I2C transaction and write address
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
+ AUX_TX_COMM_WRITE;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = exynos_dp_start_aux_transaction(dp);
+ if (retval != 0)
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
+
+ return retval;
+}
+
+int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int *data)
+{
+ u32 reg;
+ int i;
+ int retval;
+
+ for (i = 0; i < 3; i++) {
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+ /* Select EDID device */
+ retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr);
+ if (retval != 0)
+ continue;
+
+ /*
+ * Set I2C transaction and read data
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_I2C_TRANSACTION |
+ AUX_TX_COMM_READ;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = exynos_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
+ }
+
+ /* Read data */
+ if (retval == 0)
+ *data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+ return retval;
+}
+
+int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char edid[])
+{
+ u32 reg;
+ unsigned int i, j;
+ unsigned int cur_data_idx;
+ unsigned int defer = 0;
+ int retval = 0;
+
+ for (i = 0; i < count; i += 16) {
+ for (j = 0; j < 3; j++) {
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+ /* Set normal AUX CH command */
+ reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+ reg &= ~ADDR_ONLY;
+ writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+
+ /*
+ * If Rx sends defer, Tx sends only reads
+ * request without sending address
+ */
+ if (!defer)
+ retval = exynos_dp_select_i2c_device(dp,
+ device_addr, reg_addr + i);
+ else
+ defer = 0;
+
+ if (retval == 0) {
+ /*
+ * Set I2C transaction and write data
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_LENGTH(16) |
+ AUX_TX_COMM_I2C_TRANSACTION |
+ AUX_TX_COMM_READ;
+ writel(reg, dp->reg_base +
+ EXYNOS_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = exynos_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev,
+ "%s: Aux Transaction fail!\n",
+ __func__);
+ }
+ /* Check if Rx sends defer */
+ reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM);
+ if (reg == AUX_RX_COMM_AUX_DEFER ||
+ reg == AUX_RX_COMM_I2C_DEFER) {
+ dev_err(dp->dev, "Defer: %d\n\n", reg);
+ defer = 1;
+ }
+ }
+
+ for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
+ reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
+ + 4 * cur_data_idx);
+ edid[i + cur_data_idx] = (unsigned char)reg;
+ }
+ }
+
+ return retval;
+}
+
+void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype)
+{
+ u32 reg;
+
+ reg = bwtype;
+ if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
+ writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET);
+}
+
+void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET);
+ *bwtype = reg;
+}
+
+void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count)
+{
+ u32 reg;
+
+ reg = count;
+ writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
+}
+
+void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
+ *count = reg;
+}
+
+void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+ reg |= ENHANCED;
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+ reg &= ~ENHANCED;
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+ }
+}
+
+void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
+ enum pattern_set pattern)
+{
+ u32 reg;
+
+ switch (pattern) {
+ case PRBS7:
+ reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
+ writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+ break;
+ case D10_2:
+ reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
+ writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+ break;
+ case TRAINING_PTN1:
+ reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
+ writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+ break;
+ case TRAINING_PTN2:
+ reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
+ writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+ break;
+ case DP_NONE:
+ reg = SCRAMBLING_ENABLE |
+ LINK_QUAL_PATTERN_SET_DISABLE |
+ SW_TRAINING_PATTERN_SET_NORMAL;
+ writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+ break;
+ default:
+ break;
+ }
+}
+
+void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+ reg &= ~PRE_EMPHASIS_SET_MASK;
+ reg |= level << PRE_EMPHASIS_SET_SHIFT;
+ writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+ reg &= ~PRE_EMPHASIS_SET_MASK;
+ reg |= level << PRE_EMPHASIS_SET_SHIFT;
+ writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+ reg &= ~PRE_EMPHASIS_SET_MASK;
+ reg |= level << PRE_EMPHASIS_SET_SHIFT;
+ writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+ reg &= ~PRE_EMPHASIS_SET_MASK;
+ reg |= level << PRE_EMPHASIS_SET_SHIFT;
+ writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
+ u32 training_lane)
+{
+ u32 reg;
+
+ reg = training_lane;
+ writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
+ u32 training_lane)
+{
+ u32 reg;
+
+ reg = training_lane;
+ writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
+ u32 training_lane)
+{
+ u32 reg;
+
+ reg = training_lane;
+ writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
+ u32 training_lane)
+{
+ u32 reg;
+
+ reg = training_lane;
+ writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+}
+
+u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+ return reg;
+}
+
+u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+ return reg;
+}
+
+u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+ return reg;
+}
+
+u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+ return reg;
+}
+
+void exynos_dp_reset_macro(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST);
+ reg |= MACRO_RST;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
+
+ /* 10 us is the minimum reset time. */
+ usleep_range(10, 20);
+
+ reg &= ~MACRO_RST;
+ writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
+}
+
+void exynos_dp_init_video(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
+ writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+
+ reg = 0x0;
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+ reg = CHA_CRI(4) | CHA_CTRL;
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+
+ reg = 0x0;
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+
+ reg = VID_HRES_TH(2) | VID_VRES_TH(0);
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
+}
+
+void exynos_dp_set_video_color_format(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ /* Configure the input color depth, color space, dynamic range */
+ reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) |
+ (dp->video_info->color_depth << IN_BPC_SHIFT) |
+ (dp->video_info->color_space << IN_COLOR_F_SHIFT);
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2);
+
+ /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
+ reg &= ~IN_YC_COEFFI_MASK;
+ if (dp->video_info->ycbcr_coeff)
+ reg |= IN_YC_COEFFI_ITU709;
+ else
+ reg |= IN_YC_COEFFI_ITU601;
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
+}
+
+int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+ if (!(reg & DET_STA)) {
+ dev_dbg(dp->dev, "Input stream clock not detected.\n");
+ return -EINVAL;
+ }
+
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+ dev_dbg(dp->dev, "wait SYS_CTL_2.\n");
+
+ if (reg & CHA_STA) {
+ dev_dbg(dp->dev, "Input stream clk is changing\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
+ enum clock_recovery_m_value_type type,
+ u32 m_value,
+ u32 n_value)
+{
+ u32 reg;
+
+ if (type == REGISTER_M) {
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+ reg |= FIX_M_VID;
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+ reg = m_value & 0xff;
+ writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0);
+ reg = (m_value >> 8) & 0xff;
+ writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1);
+ reg = (m_value >> 16) & 0xff;
+ writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2);
+
+ reg = n_value & 0xff;
+ writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0);
+ reg = (n_value >> 8) & 0xff;
+ writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1);
+ reg = (n_value >> 16) & 0xff;
+ writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+ reg &= ~FIX_M_VID;
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+
+ writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0);
+ writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1);
+ writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2);
+ }
+}
+
+void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type)
+{
+ u32 reg;
+
+ if (type == VIDEO_TIMING_FROM_CAPTURE) {
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+ reg &= ~FORMAT_SEL;
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+ reg |= FORMAT_SEL;
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+ }
+}
+
+void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (enable) {
+ reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+ reg &= ~VIDEO_MODE_MASK;
+ reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
+ writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+ } else {
+ reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+ reg &= ~VIDEO_MODE_MASK;
+ reg |= VIDEO_MODE_SLAVE_MODE;
+ writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+ }
+}
+
+void exynos_dp_start_video(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+ reg |= VIDEO_EN;
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+}
+
+int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+ writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+
+ reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+ if (!(reg & STRM_VALID)) {
+ dev_dbg(dp->dev, "Input video stream is not detected.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+ reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
+ reg |= MASTER_VID_FUNC_EN_N;
+ writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+ reg &= ~INTERACE_SCAN_CFG;
+ reg |= (dp->video_info->interlaced << 2);
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+ reg &= ~VSYNC_POLARITY_CFG;
+ reg |= (dp->video_info->v_sync_polarity << 1);
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+ reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+ reg &= ~HSYNC_POLARITY_CFG;
+ reg |= (dp->video_info->h_sync_polarity << 0);
+ writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+ reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
+ writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+}
+
+void exynos_dp_enable_scrambling(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+ reg &= ~SCRAMBLING_DISABLE;
+ writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+}
+
+void exynos_dp_disable_scrambling(struct exynos_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+ reg |= SCRAMBLING_DISABLE;
+ writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+}
diff --git a/drivers/gpu/drm/exynos/exynos_dp_reg.h b/drivers/gpu/drm/exynos/exynos_dp_reg.h
new file mode 100644
index 0000000..2e9bd0e
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_dp_reg.h
@@ -0,0 +1,366 @@
+/*
+ * Register definition file for Samsung DP driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef _EXYNOS_DP_REG_H
+#define _EXYNOS_DP_REG_H
+
+#define EXYNOS_DP_TX_SW_RESET 0x14
+#define EXYNOS_DP_FUNC_EN_1 0x18
+#define EXYNOS_DP_FUNC_EN_2 0x1C
+#define EXYNOS_DP_VIDEO_CTL_1 0x20
+#define EXYNOS_DP_VIDEO_CTL_2 0x24
+#define EXYNOS_DP_VIDEO_CTL_3 0x28
+
+#define EXYNOS_DP_VIDEO_CTL_8 0x3C
+#define EXYNOS_DP_VIDEO_CTL_10 0x44
+
+#define EXYNOS_DP_LANE_MAP 0x35C
+
+#define EXYNOS_DP_ANALOG_CTL_1 0x370
+#define EXYNOS_DP_ANALOG_CTL_2 0x374
+#define EXYNOS_DP_ANALOG_CTL_3 0x378
+#define EXYNOS_DP_PLL_FILTER_CTL_1 0x37C
+#define EXYNOS_DP_TX_AMP_TUNING_CTL 0x380
+
+#define EXYNOS_DP_AUX_HW_RETRY_CTL 0x390
+
+#define EXYNOS_DP_COMMON_INT_STA_1 0x3C4
+#define EXYNOS_DP_COMMON_INT_STA_2 0x3C8
+#define EXYNOS_DP_COMMON_INT_STA_3 0x3CC
+#define EXYNOS_DP_COMMON_INT_STA_4 0x3D0
+#define EXYNOS_DP_INT_STA 0x3DC
+#define EXYNOS_DP_COMMON_INT_MASK_1 0x3E0
+#define EXYNOS_DP_COMMON_INT_MASK_2 0x3E4
+#define EXYNOS_DP_COMMON_INT_MASK_3 0x3E8
+#define EXYNOS_DP_COMMON_INT_MASK_4 0x3EC
+#define EXYNOS_DP_INT_STA_MASK 0x3F8
+#define EXYNOS_DP_INT_CTL 0x3FC
+
+#define EXYNOS_DP_SYS_CTL_1 0x600
+#define EXYNOS_DP_SYS_CTL_2 0x604
+#define EXYNOS_DP_SYS_CTL_3 0x608
+#define EXYNOS_DP_SYS_CTL_4 0x60C
+
+#define EXYNOS_DP_PKT_SEND_CTL 0x640
+#define EXYNOS_DP_HDCP_CTL 0x648
+
+#define EXYNOS_DP_LINK_BW_SET 0x680
+#define EXYNOS_DP_LANE_COUNT_SET 0x684
+#define EXYNOS_DP_TRAINING_PTN_SET 0x688
+#define EXYNOS_DP_LN0_LINK_TRAINING_CTL 0x68C
+#define EXYNOS_DP_LN1_LINK_TRAINING_CTL 0x690
+#define EXYNOS_DP_LN2_LINK_TRAINING_CTL 0x694
+#define EXYNOS_DP_LN3_LINK_TRAINING_CTL 0x698
+
+#define EXYNOS_DP_DEBUG_CTL 0x6C0
+#define EXYNOS_DP_HPD_DEGLITCH_L 0x6C4
+#define EXYNOS_DP_HPD_DEGLITCH_H 0x6C8
+#define EXYNOS_DP_LINK_DEBUG_CTL 0x6E0
+
+#define EXYNOS_DP_M_VID_0 0x700
+#define EXYNOS_DP_M_VID_1 0x704
+#define EXYNOS_DP_M_VID_2 0x708
+#define EXYNOS_DP_N_VID_0 0x70C
+#define EXYNOS_DP_N_VID_1 0x710
+#define EXYNOS_DP_N_VID_2 0x714
+
+#define EXYNOS_DP_PLL_CTL 0x71C
+#define EXYNOS_DP_PHY_PD 0x720
+#define EXYNOS_DP_PHY_TEST 0x724
+
+#define EXYNOS_DP_VIDEO_FIFO_THRD 0x730
+#define EXYNOS_DP_AUDIO_MARGIN 0x73C
+
+#define EXYNOS_DP_M_VID_GEN_FILTER_TH 0x764
+#define EXYNOS_DP_M_AUD_GEN_FILTER_TH 0x778
+#define EXYNOS_DP_AUX_CH_STA 0x780
+#define EXYNOS_DP_AUX_CH_DEFER_CTL 0x788
+#define EXYNOS_DP_AUX_RX_COMM 0x78C
+#define EXYNOS_DP_BUFFER_DATA_CTL 0x790
+#define EXYNOS_DP_AUX_CH_CTL_1 0x794
+#define EXYNOS_DP_AUX_ADDR_7_0 0x798
+#define EXYNOS_DP_AUX_ADDR_15_8 0x79C
+#define EXYNOS_DP_AUX_ADDR_19_16 0x7A0
+#define EXYNOS_DP_AUX_CH_CTL_2 0x7A4
+
+#define EXYNOS_DP_BUF_DATA_0 0x7C0
+
+#define EXYNOS_DP_SOC_GENERAL_CTL 0x800
+
+/* EXYNOS_DP_TX_SW_RESET */
+#define RESET_DP_TX (0x1 << 0)
+
+/* EXYNOS_DP_FUNC_EN_1 */
+#define MASTER_VID_FUNC_EN_N (0x1 << 7)
+#define SLAVE_VID_FUNC_EN_N (0x1 << 5)
+#define AUD_FIFO_FUNC_EN_N (0x1 << 4)
+#define AUD_FUNC_EN_N (0x1 << 3)
+#define HDCP_FUNC_EN_N (0x1 << 2)
+#define CRC_FUNC_EN_N (0x1 << 1)
+#define SW_FUNC_EN_N (0x1 << 0)
+
+/* EXYNOS_DP_FUNC_EN_2 */
+#define SSC_FUNC_EN_N (0x1 << 7)
+#define AUX_FUNC_EN_N (0x1 << 2)
+#define SERDES_FIFO_FUNC_EN_N (0x1 << 1)
+#define LS_CLK_DOMAIN_FUNC_EN_N (0x1 << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_1 */
+#define VIDEO_EN (0x1 << 7)
+#define HDCP_VIDEO_MUTE (0x1 << 6)
+
+/* EXYNOS_DP_VIDEO_CTL_1 */
+#define IN_D_RANGE_MASK (0x1 << 7)
+#define IN_D_RANGE_SHIFT (7)
+#define IN_D_RANGE_CEA (0x1 << 7)
+#define IN_D_RANGE_VESA (0x0 << 7)
+#define IN_BPC_MASK (0x7 << 4)
+#define IN_BPC_SHIFT (4)
+#define IN_BPC_12_BITS (0x3 << 4)
+#define IN_BPC_10_BITS (0x2 << 4)
+#define IN_BPC_8_BITS (0x1 << 4)
+#define IN_BPC_6_BITS (0x0 << 4)
+#define IN_COLOR_F_MASK (0x3 << 0)
+#define IN_COLOR_F_SHIFT (0)
+#define IN_COLOR_F_YCBCR444 (0x2 << 0)
+#define IN_COLOR_F_YCBCR422 (0x1 << 0)
+#define IN_COLOR_F_RGB (0x0 << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_3 */
+#define IN_YC_COEFFI_MASK (0x1 << 7)
+#define IN_YC_COEFFI_SHIFT (7)
+#define IN_YC_COEFFI_ITU709 (0x1 << 7)
+#define IN_YC_COEFFI_ITU601 (0x0 << 7)
+#define VID_CHK_UPDATE_TYPE_MASK (0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_SHIFT (4)
+#define VID_CHK_UPDATE_TYPE_1 (0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_0 (0x0 << 4)
+
+/* EXYNOS_DP_VIDEO_CTL_8 */
+#define VID_HRES_TH(x) (((x) & 0xf) << 4)
+#define VID_VRES_TH(x) (((x) & 0xf) << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_10 */
+#define FORMAT_SEL (0x1 << 4)
+#define INTERACE_SCAN_CFG (0x1 << 2)
+#define VSYNC_POLARITY_CFG (0x1 << 1)
+#define HSYNC_POLARITY_CFG (0x1 << 0)
+
+/* EXYNOS_DP_LANE_MAP */
+#define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6)
+#define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6)
+#define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6)
+#define LANE3_MAP_LOGIC_LANE_3 (0x3 << 6)
+#define LANE2_MAP_LOGIC_LANE_0 (0x0 << 4)
+#define LANE2_MAP_LOGIC_LANE_1 (0x1 << 4)
+#define LANE2_MAP_LOGIC_LANE_2 (0x2 << 4)
+#define LANE2_MAP_LOGIC_LANE_3 (0x3 << 4)
+#define LANE1_MAP_LOGIC_LANE_0 (0x0 << 2)
+#define LANE1_MAP_LOGIC_LANE_1 (0x1 << 2)
+#define LANE1_MAP_LOGIC_LANE_2 (0x2 << 2)
+#define LANE1_MAP_LOGIC_LANE_3 (0x3 << 2)
+#define LANE0_MAP_LOGIC_LANE_0 (0x0 << 0)
+#define LANE0_MAP_LOGIC_LANE_1 (0x1 << 0)
+#define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0)
+#define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0)
+
+/* EXYNOS_DP_ANALOG_CTL_1 */
+#define TX_TERMINAL_CTRL_50_OHM (0x1 << 4)
+
+/* EXYNOS_DP_ANALOG_CTL_2 */
+#define SEL_24M (0x1 << 3)
+#define TX_DVDD_BIT_1_0625V (0x4 << 0)
+
+/* EXYNOS_DP_ANALOG_CTL_3 */
+#define DRIVE_DVDD_BIT_1_0625V (0x4 << 5)
+#define VCO_BIT_600_MICRO (0x5 << 0)
+
+/* EXYNOS_DP_PLL_FILTER_CTL_1 */
+#define PD_RING_OSC (0x1 << 6)
+#define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4)
+#define TX_CUR1_2X (0x1 << 2)
+#define TX_CUR_16_MA (0x3 << 0)
+
+/* EXYNOS_DP_TX_AMP_TUNING_CTL */
+#define CH3_AMP_400_MV (0x0 << 24)
+#define CH2_AMP_400_MV (0x0 << 16)
+#define CH1_AMP_400_MV (0x0 << 8)
+#define CH0_AMP_400_MV (0x0 << 0)
+
+/* EXYNOS_DP_AUX_HW_RETRY_CTL */
+#define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8)
+#define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3)
+#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3)
+#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3)
+#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS (0x2 << 3)
+#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3)
+#define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_1 */
+#define VSYNC_DET (0x1 << 7)
+#define PLL_LOCK_CHG (0x1 << 6)
+#define SPDIF_ERR (0x1 << 5)
+#define SPDIF_UNSTBL (0x1 << 4)
+#define VID_FORMAT_CHG (0x1 << 3)
+#define AUD_CLK_CHG (0x1 << 2)
+#define VID_CLK_CHG (0x1 << 1)
+#define SW_INT (0x1 << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_2 */
+#define ENC_EN_CHG (0x1 << 6)
+#define HW_BKSV_RDY (0x1 << 3)
+#define HW_SHA_DONE (0x1 << 2)
+#define HW_AUTH_STATE_CHG (0x1 << 1)
+#define HW_AUTH_DONE (0x1 << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_3 */
+#define AFIFO_UNDER (0x1 << 7)
+#define AFIFO_OVER (0x1 << 6)
+#define R0_CHK_FLAG (0x1 << 5)
+
+/* EXYNOS_DP_COMMON_INT_STA_4 */
+#define PSR_ACTIVE (0x1 << 7)
+#define PSR_INACTIVE (0x1 << 6)
+#define SPDIF_BI_PHASE_ERR (0x1 << 5)
+#define HOTPLUG_CHG (0x1 << 2)
+#define HPD_LOST (0x1 << 1)
+#define PLUG (0x1 << 0)
+
+/* EXYNOS_DP_INT_STA */
+#define INT_HPD (0x1 << 6)
+#define HW_TRAINING_FINISH (0x1 << 5)
+#define RPLY_RECEIV (0x1 << 1)
+#define AUX_ERR (0x1 << 0)
+
+/* EXYNOS_DP_INT_CTL */
+#define SOFT_INT_CTRL (0x1 << 2)
+#define INT_POL1 (0x1 << 1)
+#define INT_POL0 (0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_1 */
+#define DET_STA (0x1 << 2)
+#define FORCE_DET (0x1 << 1)
+#define DET_CTRL (0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_2 */
+#define CHA_CRI(x) (((x) & 0xf) << 4)
+#define CHA_STA (0x1 << 2)
+#define FORCE_CHA (0x1 << 1)
+#define CHA_CTRL (0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_3 */
+#define HPD_STATUS (0x1 << 6)
+#define F_HPD (0x1 << 5)
+#define HPD_CTRL (0x1 << 4)
+#define HDCP_RDY (0x1 << 3)
+#define STRM_VALID (0x1 << 2)
+#define F_VALID (0x1 << 1)
+#define VALID_CTRL (0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_4 */
+#define FIX_M_AUD (0x1 << 4)
+#define ENHANCED (0x1 << 3)
+#define FIX_M_VID (0x1 << 2)
+#define M_VID_UPDATE_CTRL (0x3 << 0)
+
+/* EXYNOS_DP_TRAINING_PTN_SET */
+#define SCRAMBLER_TYPE (0x1 << 9)
+#define HW_LINK_TRAINING_PATTERN (0x1 << 8)
+#define SCRAMBLING_DISABLE (0x1 << 5)
+#define SCRAMBLING_ENABLE (0x0 << 5)
+#define LINK_QUAL_PATTERN_SET_MASK (0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_PRBS7 (0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_D10_2 (0x1 << 2)
+#define LINK_QUAL_PATTERN_SET_DISABLE (0x0 << 2)
+#define SW_TRAINING_PATTERN_SET_MASK (0x3 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN2 (0x2 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0)
+#define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0)
+
+/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
+#define PRE_EMPHASIS_SET_MASK (0x3 << 3)
+#define PRE_EMPHASIS_SET_SHIFT (3)
+
+/* EXYNOS_DP_DEBUG_CTL */
+#define PLL_LOCK (0x1 << 4)
+#define F_PLL_LOCK (0x1 << 3)
+#define PLL_LOCK_CTRL (0x1 << 2)
+#define PN_INV (0x1 << 0)
+
+/* EXYNOS_DP_PLL_CTL */
+#define DP_PLL_PD (0x1 << 7)
+#define DP_PLL_RESET (0x1 << 6)
+#define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4)
+#define DP_PLL_REF_BIT_1_1250V (0x5 << 0)
+#define DP_PLL_REF_BIT_1_2500V (0x7 << 0)
+
+/* EXYNOS_DP_PHY_PD */
+#define DP_PHY_PD (0x1 << 5)
+#define AUX_PD (0x1 << 4)
+#define CH3_PD (0x1 << 3)
+#define CH2_PD (0x1 << 2)
+#define CH1_PD (0x1 << 1)
+#define CH0_PD (0x1 << 0)
+
+/* EXYNOS_DP_PHY_TEST */
+#define MACRO_RST (0x1 << 5)
+#define CH1_TEST (0x1 << 1)
+#define CH0_TEST (0x1 << 0)
+
+/* EXYNOS_DP_AUX_CH_STA */
+#define AUX_BUSY (0x1 << 4)
+#define AUX_STATUS_MASK (0xf << 0)
+
+/* EXYNOS_DP_AUX_CH_DEFER_CTL */
+#define DEFER_CTRL_EN (0x1 << 7)
+#define DEFER_COUNT(x) (((x) & 0x7f) << 0)
+
+/* EXYNOS_DP_AUX_RX_COMM */
+#define AUX_RX_COMM_I2C_DEFER (0x2 << 2)
+#define AUX_RX_COMM_AUX_DEFER (0x2 << 0)
+
+/* EXYNOS_DP_BUFFER_DATA_CTL */
+#define BUF_CLR (0x1 << 7)
+#define BUF_DATA_COUNT(x) (((x) & 0x1f) << 0)
+
+/* EXYNOS_DP_AUX_CH_CTL_1 */
+#define AUX_LENGTH(x) (((x - 1) & 0xf) << 4)
+#define AUX_TX_COMM_MASK (0xf << 0)
+#define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3)
+#define AUX_TX_COMM_I2C_TRANSACTION (0x0 << 3)
+#define AUX_TX_COMM_MOT (0x1 << 2)
+#define AUX_TX_COMM_WRITE (0x0 << 0)
+#define AUX_TX_COMM_READ (0x1 << 0)
+
+/* EXYNOS_DP_AUX_ADDR_7_0 */
+#define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff)
+
+/* EXYNOS_DP_AUX_ADDR_15_8 */
+#define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff)
+
+/* EXYNOS_DP_AUX_ADDR_19_16 */
+#define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f)
+
+/* EXYNOS_DP_AUX_CH_CTL_2 */
+#define ADDR_ONLY (0x1 << 1)
+#define AUX_EN (0x1 << 0)
+
+/* EXYNOS_DP_SOC_GENERAL_CTL */
+#define AUDIO_MODE_SPDIF_MODE (0x1 << 8)
+#define AUDIO_MODE_MASTER_MODE (0x0 << 8)
+#define MASTER_VIDEO_INTERLACE_EN (0x1 << 4)
+#define VIDEO_MASTER_CLK_SEL (0x1 << 2)
+#define VIDEO_MASTER_MODE_EN (0x1 << 1)
+#define VIDEO_MODE_MASK (0x1 << 0)
+#define VIDEO_MODE_SLAVE_MODE (0x1 << 0)
+#define VIDEO_MODE_MASTER_MODE (0x0 << 0)
+
+#endif /* _EXYNOS_DP_REG_H */
diff --git a/drivers/video/exynos/Kconfig b/drivers/video/exynos/Kconfig
index 1b035b2..7032ad9 100644
--- a/drivers/video/exynos/Kconfig
+++ b/drivers/video/exynos/Kconfig
@@ -27,11 +27,4 @@ config EXYNOS_LCD_S6E8AX0
If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its
LCD control driver.
-config EXYNOS_DP
- bool "EXYNOS DP driver support"
- depends on ARCH_EXYNOS
- default n
- help
- This enables support for DP device.
-
endif # EXYNOS_VIDEO
diff --git a/drivers/video/exynos/Makefile b/drivers/video/exynos/Makefile
index ec7772e..b5b1bd2 100644
--- a/drivers/video/exynos/Makefile
+++ b/drivers/video/exynos/Makefile
@@ -5,4 +5,3 @@
obj-$(CONFIG_EXYNOS_MIPI_DSI) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
exynos_mipi_dsi_lowlevel.o
obj-$(CONFIG_EXYNOS_LCD_S6E8AX0) += s6e8ax0.o
-obj-$(CONFIG_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
deleted file mode 100644
index 089ae22..0000000
--- a/drivers/video/exynos/exynos_dp_core.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-/*
- * Samsung SoC DP (Display Port) interface driver.
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@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 <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-
-#include <video/exynos_dp.h>
-
-#include "exynos_dp_core.h"
-
-static int exynos_dp_init_dp(struct exynos_dp_device *dp)
-{
- exynos_dp_reset(dp);
-
- exynos_dp_swreset(dp);
-
- exynos_dp_init_analog_param(dp);
- exynos_dp_init_interrupt(dp);
-
- /* SW defined function Normal operation */
- exynos_dp_enable_sw_function(dp);
-
- exynos_dp_config_interrupt(dp);
- exynos_dp_init_analog_func(dp);
-
- exynos_dp_init_hpd(dp);
- exynos_dp_init_aux(dp);
-
- return 0;
-}
-
-static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
-{
- int timeout_loop = 0;
-
- while (exynos_dp_get_plug_in_status(dp) != 0) {
- timeout_loop++;
- if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
- dev_err(dp->dev, "failed to get hpd plug status\n");
- return -ETIMEDOUT;
- }
- usleep_range(10, 11);
- }
-
- return 0;
-}
-
-static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
-{
- int i;
- unsigned char sum = 0;
-
- for (i = 0; i < EDID_BLOCK_LENGTH; i++)
- sum = sum + edid_data[i];
-
- return sum;
-}
-
-static int exynos_dp_read_edid(struct exynos_dp_device *dp)
-{
- unsigned char edid[EDID_BLOCK_LENGTH * 2];
- unsigned int extend_block = 0;
- unsigned char sum;
- unsigned char test_vector;
- int retval;
-
- /*
- * EDID device address is 0x50.
- * However, if necessary, you must have set upper address
- * into E-EDID in I2C device, 0x30.
- */
-
- /* Read Extension Flag, Number of 128-byte EDID extension blocks */
- retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
- EDID_EXTENSION_FLAG,
- &extend_block);
- if (retval)
- return retval;
-
- if (extend_block > 0) {
- dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
- /* Read EDID data */
- retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
- EDID_HEADER_PATTERN,
- EDID_BLOCK_LENGTH,
- &edid[EDID_HEADER_PATTERN]);
- if (retval != 0) {
- dev_err(dp->dev, "EDID Read failed!\n");
- return -EIO;
- }
- sum = exynos_dp_calc_edid_check_sum(edid);
- if (sum != 0) {
- dev_err(dp->dev, "EDID bad checksum!\n");
- return -EIO;
- }
-
- /* Read additional EDID data */
- retval = exynos_dp_read_bytes_from_i2c(dp,
- I2C_EDID_DEVICE_ADDR,
- EDID_BLOCK_LENGTH,
- EDID_BLOCK_LENGTH,
- &edid[EDID_BLOCK_LENGTH]);
- if (retval != 0) {
- dev_err(dp->dev, "EDID Read failed!\n");
- return -EIO;
- }
- sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
- if (sum != 0) {
- dev_err(dp->dev, "EDID bad checksum!\n");
- return -EIO;
- }
-
- exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
- &test_vector);
- if (test_vector & DPCD_TEST_EDID_READ) {
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TEST_EDID_CHECKSUM,
- edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TEST_RESPONSE,
- DPCD_TEST_EDID_CHECKSUM_WRITE);
- }
- } else {
- dev_info(dp->dev, "EDID data does not include any extensions.\n");
-
- /* Read EDID data */
- retval = exynos_dp_read_bytes_from_i2c(dp,
- I2C_EDID_DEVICE_ADDR,
- EDID_HEADER_PATTERN,
- EDID_BLOCK_LENGTH,
- &edid[EDID_HEADER_PATTERN]);
- if (retval != 0) {
- dev_err(dp->dev, "EDID Read failed!\n");
- return -EIO;
- }
- sum = exynos_dp_calc_edid_check_sum(edid);
- if (sum != 0) {
- dev_err(dp->dev, "EDID bad checksum!\n");
- return -EIO;
- }
-
- exynos_dp_read_byte_from_dpcd(dp,
- DPCD_ADDR_TEST_REQUEST,
- &test_vector);
- if (test_vector & DPCD_TEST_EDID_READ) {
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TEST_EDID_CHECKSUM,
- edid[EDID_CHECKSUM]);
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TEST_RESPONSE,
- DPCD_TEST_EDID_CHECKSUM_WRITE);
- }
- }
-
- dev_err(dp->dev, "EDID Read success!\n");
- return 0;
-}
-
-static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
-{
- u8 buf[12];
- int i;
- int retval;
-
- /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
- retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV,
- 12, buf);
- if (retval)
- return retval;
-
- /* Read EDID */
- for (i = 0; i < 3; i++) {
- retval = exynos_dp_read_edid(dp);
- if (!retval)
- break;
- }
-
- return retval;
-}
-
-static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
- bool enable)
-{
- u8 data;
-
- exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
-
- if (enable)
- exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
- DPCD_ENHANCED_FRAME_EN |
- DPCD_LANE_COUNT_SET(data));
- else
- exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
- DPCD_LANE_COUNT_SET(data));
-}
-
-static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
-{
- u8 data;
- int retval;
-
- exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
- retval = DPCD_ENHANCED_FRAME_CAP(data);
-
- return retval;
-}
-
-static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
-{
- u8 data;
-
- data = exynos_dp_is_enhanced_mode_available(dp);
- exynos_dp_enable_rx_to_enhanced_mode(dp, data);
- exynos_dp_enable_enhanced_mode(dp, data);
-}
-
-static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
-{
- exynos_dp_set_training_pattern(dp, DP_NONE);
-
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_PATTERN_SET,
- DPCD_TRAINING_PATTERN_DISABLED);
-}
-
-static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
- int pre_emphasis, int lane)
-{
- switch (lane) {
- case 0:
- exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
- break;
- case 1:
- exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
- break;
-
- case 2:
- exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
- break;
-
- case 3:
- exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
- break;
- }
-}
-
-static int exynos_dp_link_start(struct exynos_dp_device *dp)
-{
- u8 buf[4];
- int lane, lane_count, pll_tries, retval;
-
- lane_count = dp->link_train.lane_count;
-
- dp->link_train.lt_state = CLOCK_RECOVERY;
- dp->link_train.eq_loop = 0;
-
- for (lane = 0; lane < lane_count; lane++)
- dp->link_train.cr_loop[lane] = 0;
-
- /* Set link rate and count as you want to establish*/
- exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
- exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
-
- /* Setup RX configuration */
- buf[0] = dp->link_train.link_rate;
- buf[1] = dp->link_train.lane_count;
- retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
- 2, buf);
- if (retval)
- return retval;
-
- /* Set TX pre-emphasis to minimum */
- for (lane = 0; lane < lane_count; lane++)
- exynos_dp_set_lane_lane_pre_emphasis(dp,
- PRE_EMPHASIS_LEVEL_0, lane);
-
- /* Wait for PLL lock */
- pll_tries = 0;
- while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
- if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
- dev_err(dp->dev, "Wait for PLL lock timed out\n");
- return -ETIMEDOUT;
- }
-
- pll_tries++;
- usleep_range(90, 120);
- }
-
- /* Set training pattern 1 */
- exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
-
- /* Set RX training pattern */
- retval = exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_PATTERN_SET,
- DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
- if (retval)
- return retval;
-
- for (lane = 0; lane < lane_count; lane++)
- buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
- DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
-
- retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
- lane_count, buf);
-
- return retval;
-}
-
-static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
-{
- int shift = (lane & 1) * 4;
- u8 link_value = link_status[lane>>1];
-
- return (link_value >> shift) & 0xf;
-}
-
-static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
-{
- int lane;
- u8 lane_status;
-
- for (lane = 0; lane < lane_count; lane++) {
- lane_status = exynos_dp_get_lane_status(link_status, lane);
- if ((lane_status & DPCD_LANE_CR_DONE) == 0)
- return -EINVAL;
- }
- return 0;
-}
-
-static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
- int lane_count)
-{
- int lane;
- u8 lane_status;
-
- if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
- return -EINVAL;
-
- for (lane = 0; lane < lane_count; lane++) {
- lane_status = exynos_dp_get_lane_status(link_status, lane);
- lane_status &= DPCD_CHANNEL_EQ_BITS;
- if (lane_status != DPCD_CHANNEL_EQ_BITS)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
- int lane)
-{
- int shift = (lane & 1) * 4;
- u8 link_value = adjust_request[lane>>1];
-
- return (link_value >> shift) & 0x3;
-}
-
-static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
- u8 adjust_request[2],
- int lane)
-{
- int shift = (lane & 1) * 4;
- u8 link_value = adjust_request[lane>>1];
-
- return ((link_value >> shift) & 0xc) >> 2;
-}
-
-static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
- u8 training_lane_set, int lane)
-{
- switch (lane) {
- case 0:
- exynos_dp_set_lane0_link_training(dp, training_lane_set);
- break;
- case 1:
- exynos_dp_set_lane1_link_training(dp, training_lane_set);
- break;
-
- case 2:
- exynos_dp_set_lane2_link_training(dp, training_lane_set);
- break;
-
- case 3:
- exynos_dp_set_lane3_link_training(dp, training_lane_set);
- break;
- }
-}
-
-static unsigned int exynos_dp_get_lane_link_training(
- struct exynos_dp_device *dp,
- int lane)
-{
- u32 reg;
-
- switch (lane) {
- case 0:
- reg = exynos_dp_get_lane0_link_training(dp);
- break;
- case 1:
- reg = exynos_dp_get_lane1_link_training(dp);
- break;
- case 2:
- reg = exynos_dp_get_lane2_link_training(dp);
- break;
- case 3:
- reg = exynos_dp_get_lane3_link_training(dp);
- break;
- default:
- WARN_ON(1);
- return 0;
- }
-
- return reg;
-}
-
-static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
-{
- exynos_dp_training_pattern_dis(dp);
- exynos_dp_set_enhanced_mode(dp);
-
- dp->link_train.lt_state = FAILED;
-}
-
-static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
- u8 adjust_request[2])
-{
- int lane, lane_count;
- u8 voltage_swing, pre_emphasis, training_lane;
-
- lane_count = dp->link_train.lane_count;
- for (lane = 0; lane < lane_count; lane++) {
- voltage_swing = exynos_dp_get_adjust_request_voltage(
- adjust_request, lane);
- pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
- adjust_request, lane);
- training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
- DPCD_PRE_EMPHASIS_SET(pre_emphasis);
-
- if (voltage_swing == VOLTAGE_LEVEL_3)
- training_lane |= DPCD_MAX_SWING_REACHED;
- if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
- training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
-
- dp->link_train.training_lane[lane] = training_lane;
- }
-}
-
-static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
-{
- int lane, lane_count, retval;
- u8 voltage_swing, pre_emphasis, training_lane;
- u8 link_status[2], adjust_request[2];
-
- usleep_range(100, 101);
-
- lane_count = dp->link_train.lane_count;
-
- retval = exynos_dp_read_bytes_from_dpcd(dp,
- DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
- if (retval)
- return retval;
-
- retval = exynos_dp_read_bytes_from_dpcd(dp,
- DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
- if (retval)
- return retval;
-
- if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
- /* set training pattern 2 for EQ */
- exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
-
- retval = exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_PATTERN_SET,
- DPCD_SCRAMBLING_DISABLED |
- DPCD_TRAINING_PATTERN_2);
- if (retval)
- return retval;
-
- dev_info(dp->dev, "Link Training Clock Recovery success\n");
- dp->link_train.lt_state = EQUALIZER_TRAINING;
- } else {
- for (lane = 0; lane < lane_count; lane++) {
- training_lane = exynos_dp_get_lane_link_training(
- dp, lane);
- voltage_swing = exynos_dp_get_adjust_request_voltage(
- adjust_request, lane);
- pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
- adjust_request, lane);
-
- if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
- voltage_swing &&
- DPCD_PRE_EMPHASIS_GET(training_lane) ==
- pre_emphasis)
- dp->link_train.cr_loop[lane]++;
-
- if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
- voltage_swing == VOLTAGE_LEVEL_3 ||
- pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
- dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
- dp->link_train.cr_loop[lane],
- voltage_swing, pre_emphasis);
- exynos_dp_reduce_link_rate(dp);
- return -EIO;
- }
- }
- }
-
- exynos_dp_get_adjust_training_lane(dp, adjust_request);
-
- for (lane = 0; lane < lane_count; lane++)
- exynos_dp_set_lane_link_training(dp,
- dp->link_train.training_lane[lane], lane);
-
- retval = exynos_dp_write_bytes_to_dpcd(dp,
- DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
- dp->link_train.training_lane);
- if (retval)
- return retval;
-
- return retval;
-}
-
-static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
-{
- int lane, lane_count, retval;
- u32 reg;
- u8 link_align, link_status[2], adjust_request[2];
-
- usleep_range(400, 401);
-
- lane_count = dp->link_train.lane_count;
-
- retval = exynos_dp_read_bytes_from_dpcd(dp,
- DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
- if (retval)
- return retval;
-
- if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
- exynos_dp_reduce_link_rate(dp);
- return -EIO;
- }
-
- retval = exynos_dp_read_bytes_from_dpcd(dp,
- DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
- if (retval)
- return retval;
-
- retval = exynos_dp_read_byte_from_dpcd(dp,
- DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
- if (retval)
- return retval;
-
- exynos_dp_get_adjust_training_lane(dp, adjust_request);
-
- if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
- /* traing pattern Set to Normal */
- exynos_dp_training_pattern_dis(dp);
-
- dev_info(dp->dev, "Link Training success!\n");
-
- exynos_dp_get_link_bandwidth(dp, ®);
- dp->link_train.link_rate = reg;
- dev_dbg(dp->dev, "final bandwidth = %.2x\n",
- dp->link_train.link_rate);
-
- exynos_dp_get_lane_count(dp, ®);
- dp->link_train.lane_count = reg;
- dev_dbg(dp->dev, "final lane count = %.2x\n",
- dp->link_train.lane_count);
-
- /* set enhanced mode if available */
- exynos_dp_set_enhanced_mode(dp);
- dp->link_train.lt_state = FINISHED;
-
- return 0;
- }
-
- /* not all locked */
- dp->link_train.eq_loop++;
-
- if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
- dev_err(dp->dev, "EQ Max loop\n");
- exynos_dp_reduce_link_rate(dp);
- return -EIO;
- }
-
- for (lane = 0; lane < lane_count; lane++)
- exynos_dp_set_lane_link_training(dp,
- dp->link_train.training_lane[lane], lane);
-
- retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
- lane_count, dp->link_train.training_lane);
-
- return retval;
-}
-
-static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
- u8 *bandwidth)
-{
- u8 data;
-
- /*
- * For DP rev.1.1, Maximum link rate of Main Link lanes
- * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
- */
- exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
- *bandwidth = data;
-}
-
-static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
- u8 *lane_count)
-{
- u8 data;
-
- /*
- * For DP rev.1.1, Maximum number of Main Link lanes
- * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
- */
- exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
- *lane_count = DPCD_MAX_LANE_COUNT(data);
-}
-
-static void exynos_dp_init_training(struct exynos_dp_device *dp,
- enum link_lane_count_type max_lane,
- enum link_rate_type max_rate)
-{
- /*
- * MACRO_RST must be applied after the PLL_LOCK to avoid
- * the DP inter pair skew issue for at least 10 us
- */
- exynos_dp_reset_macro(dp);
-
- /* Initialize by reading RX's DPCD */
- exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
- exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
-
- if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
- (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
- dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
- dp->link_train.link_rate);
- dp->link_train.link_rate = LINK_RATE_1_62GBPS;
- }
-
- if (dp->link_train.lane_count == 0) {
- dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
- dp->link_train.lane_count);
- dp->link_train.lane_count = (u8)LANE_COUNT1;
- }
-
- /* Setup TX lane count & rate */
- if (dp->link_train.lane_count > max_lane)
- dp->link_train.lane_count = max_lane;
- if (dp->link_train.link_rate > max_rate)
- dp->link_train.link_rate = max_rate;
-
- /* All DP analog module power up */
- exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
-}
-
-static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
-{
- int retval = 0, training_finished = 0;
-
- dp->link_train.lt_state = START;
-
- /* Process here */
- while (!retval && !training_finished) {
- switch (dp->link_train.lt_state) {
- case START:
- retval = exynos_dp_link_start(dp);
- if (retval)
- dev_err(dp->dev, "LT link start failed!\n");
- break;
- case CLOCK_RECOVERY:
- retval = exynos_dp_process_clock_recovery(dp);
- if (retval)
- dev_err(dp->dev, "LT CR failed!\n");
- break;
- case EQUALIZER_TRAINING:
- retval = exynos_dp_process_equalizer_training(dp);
- if (retval)
- dev_err(dp->dev, "LT EQ failed!\n");
- break;
- case FINISHED:
- training_finished = 1;
- break;
- case FAILED:
- return -EREMOTEIO;
- }
- }
- if (retval)
- dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
-
- return retval;
-}
-
-static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
- u32 count,
- u32 bwtype)
-{
- int i;
- int retval;
-
- for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
- exynos_dp_init_training(dp, count, bwtype);
- retval = exynos_dp_sw_link_training(dp);
- if (retval == 0)
- break;
-
- usleep_range(100, 110);
- }
-
- return retval;
-}
-
-static int exynos_dp_config_video(struct exynos_dp_device *dp)
-{
- int retval = 0;
- int timeout_loop = 0;
- int done_count = 0;
-
- exynos_dp_config_video_slave_mode(dp);
-
- exynos_dp_set_video_color_format(dp);
-
- if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
- dev_err(dp->dev, "PLL is not locked yet.\n");
- return -EINVAL;
- }
-
- for (;;) {
- timeout_loop++;
- if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
- break;
- if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
- dev_err(dp->dev, "Timeout of video streamclk ok\n");
- return -ETIMEDOUT;
- }
-
- usleep_range(1, 2);
- }
-
- /* Set to use the register calculated M/N video */
- exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
-
- /* For video bist, Video timing must be generated by register */
- exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
-
- /* Disable video mute */
- exynos_dp_enable_video_mute(dp, 0);
-
- /* Configure video slave mode */
- exynos_dp_enable_video_master(dp, 0);
-
- /* Enable video */
- exynos_dp_start_video(dp);
-
- timeout_loop = 0;
-
- for (;;) {
- timeout_loop++;
- if (exynos_dp_is_video_stream_on(dp) == 0) {
- done_count++;
- if (done_count > 10)
- break;
- } else if (done_count) {
- done_count = 0;
- }
- if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
- dev_err(dp->dev, "Timeout of video streamclk ok\n");
- return -ETIMEDOUT;
- }
-
- usleep_range(1000, 1001);
- }
-
- if (retval != 0)
- dev_err(dp->dev, "Video stream is not detected!\n");
-
- return retval;
-}
-
-static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
-{
- u8 data;
-
- if (enable) {
- exynos_dp_enable_scrambling(dp);
-
- exynos_dp_read_byte_from_dpcd(dp,
- DPCD_ADDR_TRAINING_PATTERN_SET,
- &data);
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_PATTERN_SET,
- (u8)(data & ~DPCD_SCRAMBLING_DISABLED));
- } else {
- exynos_dp_disable_scrambling(dp);
-
- exynos_dp_read_byte_from_dpcd(dp,
- DPCD_ADDR_TRAINING_PATTERN_SET,
- &data);
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_PATTERN_SET,
- (u8)(data | DPCD_SCRAMBLING_DISABLED));
- }
-}
-
-static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
-{
- struct exynos_dp_device *dp = arg;
-
- enum dp_irq_type irq_type;
-
- irq_type = exynos_dp_get_irq_type(dp);
- switch (irq_type) {
- case DP_IRQ_TYPE_HP_CABLE_IN:
- dev_dbg(dp->dev, "Received irq - cable in\n");
- schedule_work(&dp->hotplug_work);
- exynos_dp_clear_hotplug_interrupts(dp);
- break;
- case DP_IRQ_TYPE_HP_CABLE_OUT:
- dev_dbg(dp->dev, "Received irq - cable out\n");
- exynos_dp_clear_hotplug_interrupts(dp);
- break;
- case DP_IRQ_TYPE_HP_CHANGE:
- /*
- * We get these change notifications once in a while, but there
- * is nothing we can do with them. Just ignore it for now and
- * only handle cable changes.
- */
- dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
- exynos_dp_clear_hotplug_interrupts(dp);
- break;
- default:
- dev_err(dp->dev, "Received irq - unknown type!\n");
- break;
- }
- return IRQ_HANDLED;
-}
-
-static void exynos_dp_hotplug(struct work_struct *work)
-{
- struct exynos_dp_device *dp;
- int ret;
-
- dp = container_of(work, struct exynos_dp_device, hotplug_work);
-
- ret = exynos_dp_detect_hpd(dp);
- if (ret) {
- /* Cable has been disconnected, we're done */
- return;
- }
-
- ret = exynos_dp_handle_edid(dp);
- if (ret) {
- dev_err(dp->dev, "unable to handle edid\n");
- return;
- }
-
- ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
- dp->video_info->link_rate);
- if (ret) {
- dev_err(dp->dev, "unable to do link train\n");
- return;
- }
-
- exynos_dp_enable_scramble(dp, 1);
- exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
- exynos_dp_enable_enhanced_mode(dp, 1);
-
- exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
- exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
-
- exynos_dp_init_video(dp);
- ret = exynos_dp_config_video(dp);
- if (ret)
- dev_err(dp->dev, "unable to config video\n");
-}
-
-#ifdef CONFIG_OF
-static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
-{
- struct device_node *dp_node = dev->of_node;
- struct exynos_dp_platdata *pd;
- struct video_info *dp_video_config;
-
- pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
- if (!pd) {
- dev_err(dev, "memory allocation for pdata failed\n");
- return ERR_PTR(-ENOMEM);
- }
- dp_video_config = devm_kzalloc(dev,
- sizeof(*dp_video_config), GFP_KERNEL);
-
- if (!dp_video_config) {
- dev_err(dev, "memory allocation for video config failed\n");
- return ERR_PTR(-ENOMEM);
- }
- pd->video_info = dp_video_config;
-
- dp_video_config->h_sync_polarity =
- of_property_read_bool(dp_node, "hsync-active-high");
-
- dp_video_config->v_sync_polarity =
- of_property_read_bool(dp_node, "vsync-active-high");
-
- dp_video_config->interlaced =
- of_property_read_bool(dp_node, "interlaced");
-
- if (of_property_read_u32(dp_node, "samsung,color-space",
- &dp_video_config->color_space)) {
- dev_err(dev, "failed to get color-space\n");
- return ERR_PTR(-EINVAL);
- }
-
- if (of_property_read_u32(dp_node, "samsung,dynamic-range",
- &dp_video_config->dynamic_range)) {
- dev_err(dev, "failed to get dynamic-range\n");
- return ERR_PTR(-EINVAL);
- }
-
- if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
- &dp_video_config->ycbcr_coeff)) {
- dev_err(dev, "failed to get ycbcr-coeff\n");
- return ERR_PTR(-EINVAL);
- }
-
- if (of_property_read_u32(dp_node, "samsung,color-depth",
- &dp_video_config->color_depth)) {
- dev_err(dev, "failed to get color-depth\n");
- return ERR_PTR(-EINVAL);
- }
-
- if (of_property_read_u32(dp_node, "samsung,link-rate",
- &dp_video_config->link_rate)) {
- dev_err(dev, "failed to get link-rate\n");
- return ERR_PTR(-EINVAL);
- }
-
- if (of_property_read_u32(dp_node, "samsung,lane-count",
- &dp_video_config->lane_count)) {
- dev_err(dev, "failed to get lane-count\n");
- return ERR_PTR(-EINVAL);
- }
-
- return pd;
-}
-
-static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
-{
- struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
- u32 phy_base;
- int ret = 0;
-
- dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
- if (!dp_phy_node) {
- dev_err(dp->dev, "could not find dptx-phy node\n");
- return -ENODEV;
- }
-
- if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
- dev_err(dp->dev, "failed to get reg for dptx-phy\n");
- ret = -EINVAL;
- goto err;
- }
-
- if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
- &dp->enable_mask)) {
- dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
- ret = -EINVAL;
- goto err;
- }
-
- dp->phy_addr = ioremap(phy_base, SZ_4);
- if (!dp->phy_addr) {
- dev_err(dp->dev, "failed to ioremap dp-phy\n");
- ret = -ENOMEM;
- goto err;
- }
-
-err:
- of_node_put(dp_phy_node);
-
- return ret;
-}
-
-static void exynos_dp_phy_init(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = __raw_readl(dp->phy_addr);
- reg |= dp->enable_mask;
- __raw_writel(reg, dp->phy_addr);
-}
-
-static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = __raw_readl(dp->phy_addr);
- reg &= ~(dp->enable_mask);
- __raw_writel(reg, dp->phy_addr);
-}
-#else
-static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
-{
- return NULL;
-}
-
-static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
-{
- return -EINVAL;
-}
-
-static void exynos_dp_phy_init(struct exynos_dp_device *dp)
-{
- return;
-}
-
-static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
-{
- return;
-}
-#endif /* CONFIG_OF */
-
-static int exynos_dp_probe(struct platform_device *pdev)
-{
- struct resource *res;
- struct exynos_dp_device *dp;
- struct exynos_dp_platdata *pdata;
-
- int ret = 0;
-
- dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
- GFP_KERNEL);
- if (!dp) {
- dev_err(&pdev->dev, "no memory for device data\n");
- return -ENOMEM;
- }
-
- dp->dev = &pdev->dev;
-
- if (pdev->dev.of_node) {
- pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
-
- ret = exynos_dp_dt_parse_phydata(dp);
- if (ret)
- return ret;
- } else {
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data\n");
- return -EINVAL;
- }
- }
-
- dp->clock = devm_clk_get(&pdev->dev, "dp");
- if (IS_ERR(dp->clock)) {
- dev_err(&pdev->dev, "failed to get clock\n");
- return PTR_ERR(dp->clock);
- }
-
- clk_prepare_enable(dp->clock);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(dp->reg_base))
- return PTR_ERR(dp->reg_base);
-
- dp->irq = platform_get_irq(pdev, 0);
- if (dp->irq == -ENXIO) {
- dev_err(&pdev->dev, "failed to get irq\n");
- return -ENODEV;
- }
-
- INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
-
- dp->video_info = pdata->video_info;
-
- if (pdev->dev.of_node) {
- if (dp->phy_addr)
- exynos_dp_phy_init(dp);
- } else {
- if (pdata->phy_init)
- pdata->phy_init();
- }
-
- exynos_dp_init_dp(dp);
-
- ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
- "exynos-dp", dp);
- if (ret) {
- dev_err(&pdev->dev, "failed to request irq\n");
- return ret;
- }
-
- platform_set_drvdata(pdev, dp);
-
- return 0;
-}
-
-static int exynos_dp_remove(struct platform_device *pdev)
-{
- struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
- struct exynos_dp_device *dp = platform_get_drvdata(pdev);
-
- flush_work(&dp->hotplug_work);
-
- if (pdev->dev.of_node) {
- if (dp->phy_addr)
- exynos_dp_phy_exit(dp);
- } else {
- if (pdata->phy_exit)
- pdata->phy_exit();
- }
-
- clk_disable_unprepare(dp->clock);
-
-
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int exynos_dp_suspend(struct device *dev)
-{
- struct exynos_dp_platdata *pdata = dev->platform_data;
- struct exynos_dp_device *dp = dev_get_drvdata(dev);
-
- disable_irq(dp->irq);
-
- flush_work(&dp->hotplug_work);
-
- if (dev->of_node) {
- if (dp->phy_addr)
- exynos_dp_phy_exit(dp);
- } else {
- if (pdata->phy_exit)
- pdata->phy_exit();
- }
-
- clk_disable_unprepare(dp->clock);
-
- return 0;
-}
-
-static int exynos_dp_resume(struct device *dev)
-{
- struct exynos_dp_platdata *pdata = dev->platform_data;
- struct exynos_dp_device *dp = dev_get_drvdata(dev);
-
- if (dev->of_node) {
- if (dp->phy_addr)
- exynos_dp_phy_init(dp);
- } else {
- if (pdata->phy_init)
- pdata->phy_init();
- }
-
- clk_prepare_enable(dp->clock);
-
- exynos_dp_init_dp(dp);
-
- enable_irq(dp->irq);
-
- return 0;
-}
-#endif
-
-static const struct dev_pm_ops exynos_dp_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
-};
-
-static const struct of_device_id exynos_dp_match[] = {
- { .compatible = "samsung,exynos5-dp" },
- {},
-};
-MODULE_DEVICE_TABLE(of, exynos_dp_match);
-
-static struct platform_driver exynos_dp_driver = {
- .probe = exynos_dp_probe,
- .remove = exynos_dp_remove,
- .driver = {
- .name = "exynos-dp",
- .owner = THIS_MODULE,
- .pm = &exynos_dp_pm_ops,
- .of_match_table = of_match_ptr(exynos_dp_match),
- },
-};
-
-module_platform_driver(exynos_dp_driver);
-
-MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DP Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h
deleted file mode 100644
index 6c567bbf..0000000
--- a/drivers/video/exynos/exynos_dp_core.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Header file for Samsung DP (Display Port) interface driver.
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@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_DP_CORE_H
-#define _EXYNOS_DP_CORE_H
-
-enum dp_irq_type {
- DP_IRQ_TYPE_HP_CABLE_IN,
- DP_IRQ_TYPE_HP_CABLE_OUT,
- DP_IRQ_TYPE_HP_CHANGE,
- DP_IRQ_TYPE_UNKNOWN,
-};
-
-struct link_train {
- int eq_loop;
- int cr_loop[4];
-
- u8 link_rate;
- u8 lane_count;
- u8 training_lane[4];
-
- enum link_training_state lt_state;
-};
-
-struct exynos_dp_device {
- struct device *dev;
- struct clk *clock;
- unsigned int irq;
- void __iomem *reg_base;
- void __iomem *phy_addr;
- unsigned int enable_mask;
-
- struct video_info *video_info;
- struct link_train link_train;
- struct work_struct hotplug_work;
-};
-
-/* exynos_dp_reg.c */
-void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_stop_video(struct exynos_dp_device *dp);
-void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_init_analog_param(struct exynos_dp_device *dp);
-void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
-void exynos_dp_reset(struct exynos_dp_device *dp);
-void exynos_dp_swreset(struct exynos_dp_device *dp);
-void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
-enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
-void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
- enum analog_power_block block,
- bool enable);
-void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
-void exynos_dp_init_hpd(struct exynos_dp_device *dp);
-enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp);
-void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp);
-void exynos_dp_reset_aux(struct exynos_dp_device *dp);
-void exynos_dp_init_aux(struct exynos_dp_device *dp);
-int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
-void exynos_dp_enable_sw_function(struct exynos_dp_device *dp);
-int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp);
-int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
- unsigned int reg_addr,
- unsigned char data);
-int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
- unsigned int reg_addr,
- unsigned char *data);
-int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
- unsigned int reg_addr,
- unsigned int count,
- unsigned char data[]);
-int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
- unsigned int reg_addr,
- unsigned int count,
- unsigned char data[]);
-int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
- unsigned int device_addr,
- unsigned int reg_addr);
-int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
- unsigned int device_addr,
- unsigned int reg_addr,
- unsigned int *data);
-int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
- unsigned int device_addr,
- unsigned int reg_addr,
- unsigned int count,
- unsigned char edid[]);
-void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
-void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
-void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
-void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
-void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
- enum pattern_set pattern);
-void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
- u32 training_lane);
-void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
- u32 training_lane);
-void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
- u32 training_lane);
-void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
- u32 training_lane);
-u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp);
-u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
-u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
-u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
-void exynos_dp_reset_macro(struct exynos_dp_device *dp);
-void exynos_dp_init_video(struct exynos_dp_device *dp);
-
-void exynos_dp_set_video_color_format(struct exynos_dp_device *dp);
-int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp);
-void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
- enum clock_recovery_m_value_type type,
- u32 m_value,
- u32 n_value);
-void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type);
-void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_start_video(struct exynos_dp_device *dp);
-int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp);
-void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp);
-void exynos_dp_enable_scrambling(struct exynos_dp_device *dp);
-void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
-
-/* I2C EDID Chip ID, Slave Address */
-#define I2C_EDID_DEVICE_ADDR 0x50
-#define I2C_E_EDID_DEVICE_ADDR 0x30
-
-#define EDID_BLOCK_LENGTH 0x80
-#define EDID_HEADER_PATTERN 0x00
-#define EDID_EXTENSION_FLAG 0x7e
-#define EDID_CHECKSUM 0x7f
-
-/* Definition for DPCD Register */
-#define DPCD_ADDR_DPCD_REV 0x0000
-#define DPCD_ADDR_MAX_LINK_RATE 0x0001
-#define DPCD_ADDR_MAX_LANE_COUNT 0x0002
-#define DPCD_ADDR_LINK_BW_SET 0x0100
-#define DPCD_ADDR_LANE_COUNT_SET 0x0101
-#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102
-#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103
-#define DPCD_ADDR_LANE0_1_STATUS 0x0202
-#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204
-#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206
-#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207
-#define DPCD_ADDR_TEST_REQUEST 0x0218
-#define DPCD_ADDR_TEST_RESPONSE 0x0260
-#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261
-#define DPCD_ADDR_SINK_POWER_STATE 0x0600
-
-/* DPCD_ADDR_MAX_LANE_COUNT */
-#define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
-#define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
-
-/* DPCD_ADDR_LANE_COUNT_SET */
-#define DPCD_ENHANCED_FRAME_EN (0x1 << 7)
-#define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f)
-
-/* DPCD_ADDR_TRAINING_PATTERN_SET */
-#define DPCD_SCRAMBLING_DISABLED (0x1 << 5)
-#define DPCD_SCRAMBLING_ENABLED (0x0 << 5)
-#define DPCD_TRAINING_PATTERN_2 (0x2 << 0)
-#define DPCD_TRAINING_PATTERN_1 (0x1 << 0)
-#define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0)
-
-/* DPCD_ADDR_TRAINING_LANE0_SET */
-#define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5)
-#define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3)
-#define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3)
-#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3)
-#define DPCD_MAX_SWING_REACHED (0x1 << 2)
-#define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0)
-#define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3)
-#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0)
-
-/* DPCD_ADDR_LANE0_1_STATUS */
-#define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2)
-#define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1)
-#define DPCD_LANE_CR_DONE (0x1 << 0)
-#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \
- DPCD_LANE_CHANNEL_EQ_DONE|\
- DPCD_LANE_SYMBOL_LOCKED)
-
-/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
-#define DPCD_LINK_STATUS_UPDATED (0x1 << 7)
-#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6)
-#define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0)
-
-/* DPCD_ADDR_TEST_REQUEST */
-#define DPCD_TEST_EDID_READ (0x1 << 2)
-
-/* DPCD_ADDR_TEST_RESPONSE */
-#define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2)
-
-/* DPCD_ADDR_SINK_POWER_STATE */
-#define DPCD_SET_POWER_STATE_D0 (0x1 << 0)
-#define DPCD_SET_POWER_STATE_D4 (0x2 << 0)
-
-#endif /* _EXYNOS_DP_CORE_H */
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c
deleted file mode 100644
index 29d9d03..0000000
--- a/drivers/video/exynos/exynos_dp_reg.c
+++ /dev/null
@@ -1,1245 +0,0 @@
-/*
- * Samsung DP (Display port) register interface driver.
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@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 <linux/device.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-
-#include <video/exynos_dp.h>
-
-#include "exynos_dp_core.h"
-#include "exynos_dp_reg.h"
-
-#define COMMON_INT_MASK_1 0
-#define COMMON_INT_MASK_2 0
-#define COMMON_INT_MASK_3 0
-#define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG)
-#define INT_STA_MASK INT_HPD
-
-void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable)
-{
- u32 reg;
-
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
- reg |= HDCP_VIDEO_MUTE;
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
- reg &= ~HDCP_VIDEO_MUTE;
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
- }
-}
-
-void exynos_dp_stop_video(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
- reg &= ~VIDEO_EN;
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-}
-
-void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable)
-{
- u32 reg;
-
- if (enable)
- reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
- LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
- else
- reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
- LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
-
- writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP);
-}
-
-void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = TX_TERMINAL_CTRL_50_OHM;
- writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1);
-
- reg = SEL_24M | TX_DVDD_BIT_1_0625V;
- writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2);
-
- reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
- writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
-
- reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
- TX_CUR1_2X | TX_CUR_16_MA;
- writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
-
- reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
- CH1_AMP_400_MV | CH0_AMP_400_MV;
- writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL);
-}
-
-void exynos_dp_init_interrupt(struct exynos_dp_device *dp)
-{
- /* Set interrupt pin assertion polarity as high */
- writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL);
-
- /* Clear pending regisers */
- writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
- writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2);
- writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3);
- writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
- writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA);
-
- /* 0:mask,1: unmask */
- writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
- writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
- writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
- writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
- writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
-}
-
-void exynos_dp_reset(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- exynos_dp_stop_video(dp);
- exynos_dp_enable_video_mute(dp, 0);
-
- reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
- AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
- HDCP_FUNC_EN_N | SW_FUNC_EN_N;
- writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-
- reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
- SERDES_FIFO_FUNC_EN_N |
- LS_CLK_DOMAIN_FUNC_EN_N;
- writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-
- usleep_range(20, 30);
-
- exynos_dp_lane_swap(dp, 0);
-
- writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
- writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
- writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
- writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-
- writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL);
- writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL);
-
- writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L);
- writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H);
-
- writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL);
-
- writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST);
-
- writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD);
- writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN);
-
- writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH);
- writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH);
-
- writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-}
-
-void exynos_dp_swreset(struct exynos_dp_device *dp)
-{
- writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET);
-}
-
-void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- /* 0: mask, 1: unmask */
- reg = COMMON_INT_MASK_1;
- writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
-
- reg = COMMON_INT_MASK_2;
- writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
-
- reg = COMMON_INT_MASK_3;
- writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
-
- reg = COMMON_INT_MASK_4;
- writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
-
- reg = INT_STA_MASK;
- writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
-}
-
-enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
- if (reg & PLL_LOCK)
- return PLL_LOCKED;
- else
- return PLL_UNLOCKED;
-}
-
-void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable)
-{
- u32 reg;
-
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
- reg |= DP_PLL_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
- reg &= ~DP_PLL_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
- }
-}
-
-void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
- enum analog_power_block block,
- bool enable)
-{
- u32 reg;
-
- switch (block) {
- case AUX_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg |= AUX_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg &= ~AUX_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- }
- break;
- case CH0_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg |= CH0_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg &= ~CH0_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- }
- break;
- case CH1_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg |= CH1_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg &= ~CH1_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- }
- break;
- case CH2_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg |= CH2_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg &= ~CH2_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- }
- break;
- case CH3_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg |= CH3_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg &= ~CH3_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- }
- break;
- case ANALOG_TOTAL:
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg |= DP_PHY_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
- reg &= ~DP_PHY_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- }
- break;
- case POWER_ALL:
- if (enable) {
- reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
- CH1_PD | CH0_PD;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
- } else {
- writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD);
- }
- break;
- default:
- break;
- }
-}
-
-void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
-{
- u32 reg;
- int timeout_loop = 0;
-
- exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
-
- reg = PLL_LOCK_CHG;
- writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
-
- reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
- reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
- writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL);
-
- /* Power up PLL */
- if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
- exynos_dp_set_pll_power_down(dp, 0);
-
- while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
- timeout_loop++;
- if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
- dev_err(dp->dev, "failed to get pll lock status\n");
- return;
- }
- usleep_range(10, 20);
- }
- }
-
- /* Enable Serdes FIFO function and Link symbol clock domain module */
- reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
- reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
- | AUX_FUNC_EN_N);
- writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-}
-
-void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = HOTPLUG_CHG | HPD_LOST | PLUG;
- writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
-
- reg = INT_HPD;
- writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
-}
-
-void exynos_dp_init_hpd(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- exynos_dp_clear_hotplug_interrupts(dp);
-
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
- reg &= ~(F_HPD | HPD_CTRL);
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-}
-
-enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- /* Parse hotplug interrupt status register */
- reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
-
- if (reg & PLUG)
- return DP_IRQ_TYPE_HP_CABLE_IN;
-
- if (reg & HPD_LOST)
- return DP_IRQ_TYPE_HP_CABLE_OUT;
-
- if (reg & HOTPLUG_CHG)
- return DP_IRQ_TYPE_HP_CHANGE;
-
- return DP_IRQ_TYPE_UNKNOWN;
-}
-
-void exynos_dp_reset_aux(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- /* Disable AUX channel module */
- reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
- reg |= AUX_FUNC_EN_N;
- writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-}
-
-void exynos_dp_init_aux(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- /* Clear inerrupts related to AUX channel */
- reg = RPLY_RECEIV | AUX_ERR;
- writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
-
- exynos_dp_reset_aux(dp);
-
- /* Disable AUX transaction H/W retry */
- reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)|
- AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ;
-
- /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
- reg = DEFER_CTRL_EN | DEFER_COUNT(1);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL);
-
- /* Enable AUX channel module */
- reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
- reg &= ~AUX_FUNC_EN_N;
- writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-}
-
-int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
- if (reg & HPD_STATUS)
- return 0;
-
- return -EINVAL;
-}
-
-void exynos_dp_enable_sw_function(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
- reg &= ~SW_FUNC_EN_N;
- writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-}
-
-int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
-{
- int reg;
- int retval = 0;
- int timeout_loop = 0;
-
- /* Enable AUX CH operation */
- reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
- reg |= AUX_EN;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-
- /* Is AUX CH command reply received? */
- reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
- while (!(reg & RPLY_RECEIV)) {
- timeout_loop++;
- if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
- dev_err(dp->dev, "AUX CH command reply failed!\n");
- return -ETIMEDOUT;
- }
- reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
- usleep_range(10, 11);
- }
-
- /* Clear interrupt source for AUX CH command reply */
- writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA);
-
- /* Clear interrupt source for AUX CH access error */
- reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
- if (reg & AUX_ERR) {
- writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA);
- return -EREMOTEIO;
- }
-
- /* Check AUX CH error access status */
- reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA);
- if ((reg & AUX_STATUS_MASK) != 0) {
- dev_err(dp->dev, "AUX CH error happens: %d\n\n",
- reg & AUX_STATUS_MASK);
- return -EREMOTEIO;
- }
-
- return retval;
-}
-
-int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
- unsigned int reg_addr,
- unsigned char data)
-{
- u32 reg;
- int i;
- int retval;
-
- for (i = 0; i < 3; i++) {
- /* Clear AUX CH data buffer */
- reg = BUF_CLR;
- writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
- /* Select DPCD device address */
- reg = AUX_ADDR_7_0(reg_addr);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
- reg = AUX_ADDR_15_8(reg_addr);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
- reg = AUX_ADDR_19_16(reg_addr);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
- /* Write data buffer */
- reg = (unsigned int)data;
- writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-
- /*
- * Set DisplayPort transaction and write 1 byte
- * If bit 3 is 1, DisplayPort transaction.
- * If Bit 3 is 0, I2C transaction.
- */
- reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
- /* Start AUX transaction */
- retval = exynos_dp_start_aux_transaction(dp);
- if (retval == 0)
- break;
- else
- dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
- __func__);
- }
-
- return retval;
-}
-
-int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
- unsigned int reg_addr,
- unsigned char *data)
-{
- u32 reg;
- int i;
- int retval;
-
- for (i = 0; i < 3; i++) {
- /* Clear AUX CH data buffer */
- reg = BUF_CLR;
- writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
- /* Select DPCD device address */
- reg = AUX_ADDR_7_0(reg_addr);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
- reg = AUX_ADDR_15_8(reg_addr);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
- reg = AUX_ADDR_19_16(reg_addr);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
- /*
- * Set DisplayPort transaction and read 1 byte
- * If bit 3 is 1, DisplayPort transaction.
- * If Bit 3 is 0, I2C transaction.
- */
- reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
- /* Start AUX transaction */
- retval = exynos_dp_start_aux_transaction(dp);
- if (retval == 0)
- break;
- else
- dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
- __func__);
- }
-
- /* Read data buffer */
- reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
- *data = (unsigned char)(reg & 0xff);
-
- return retval;
-}
-
-int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
- unsigned int reg_addr,
- unsigned int count,
- unsigned char data[])
-{
- u32 reg;
- unsigned int start_offset;
- unsigned int cur_data_count;
- unsigned int cur_data_idx;
- int i;
- int retval = 0;
-
- /* Clear AUX CH data buffer */
- reg = BUF_CLR;
- writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
- start_offset = 0;
- while (start_offset < count) {
- /* Buffer size of AUX CH is 16 * 4bytes */
- if ((count - start_offset) > 16)
- cur_data_count = 16;
- else
- cur_data_count = count - start_offset;
-
- for (i = 0; i < 3; i++) {
- /* Select DPCD device address */
- reg = AUX_ADDR_7_0(reg_addr + start_offset);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
- reg = AUX_ADDR_15_8(reg_addr + start_offset);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
- reg = AUX_ADDR_19_16(reg_addr + start_offset);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
- for (cur_data_idx = 0; cur_data_idx < cur_data_count;
- cur_data_idx++) {
- reg = data[start_offset + cur_data_idx];
- writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0
- + 4 * cur_data_idx);
- }
-
- /*
- * Set DisplayPort transaction and write
- * If bit 3 is 1, DisplayPort transaction.
- * If Bit 3 is 0, I2C transaction.
- */
- reg = AUX_LENGTH(cur_data_count) |
- AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
- /* Start AUX transaction */
- retval = exynos_dp_start_aux_transaction(dp);
- if (retval == 0)
- break;
- else
- dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
- __func__);
- }
-
- start_offset += cur_data_count;
- }
-
- return retval;
-}
-
-int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
- unsigned int reg_addr,
- unsigned int count,
- unsigned char data[])
-{
- u32 reg;
- unsigned int start_offset;
- unsigned int cur_data_count;
- unsigned int cur_data_idx;
- int i;
- int retval = 0;
-
- /* Clear AUX CH data buffer */
- reg = BUF_CLR;
- writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
- start_offset = 0;
- while (start_offset < count) {
- /* Buffer size of AUX CH is 16 * 4bytes */
- if ((count - start_offset) > 16)
- cur_data_count = 16;
- else
- cur_data_count = count - start_offset;
-
- /* AUX CH Request Transaction process */
- for (i = 0; i < 3; i++) {
- /* Select DPCD device address */
- reg = AUX_ADDR_7_0(reg_addr + start_offset);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
- reg = AUX_ADDR_15_8(reg_addr + start_offset);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
- reg = AUX_ADDR_19_16(reg_addr + start_offset);
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
- /*
- * Set DisplayPort transaction and read
- * If bit 3 is 1, DisplayPort transaction.
- * If Bit 3 is 0, I2C transaction.
- */
- reg = AUX_LENGTH(cur_data_count) |
- AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
- /* Start AUX transaction */
- retval = exynos_dp_start_aux_transaction(dp);
- if (retval == 0)
- break;
- else
- dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
- __func__);
- }
-
- for (cur_data_idx = 0; cur_data_idx < cur_data_count;
- cur_data_idx++) {
- reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
- + 4 * cur_data_idx);
- data[start_offset + cur_data_idx] =
- (unsigned char)reg;
- }
-
- start_offset += cur_data_count;
- }
-
- return retval;
-}
-
-int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
- unsigned int device_addr,
- unsigned int reg_addr)
-{
- u32 reg;
- int retval;
-
- /* Set EDID device address */
- reg = device_addr;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
- writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
- writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
- /* Set offset from base address of EDID device */
- writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-
- /*
- * Set I2C transaction and write address
- * If bit 3 is 1, DisplayPort transaction.
- * If Bit 3 is 0, I2C transaction.
- */
- reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
- AUX_TX_COMM_WRITE;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
- /* Start AUX transaction */
- retval = exynos_dp_start_aux_transaction(dp);
- if (retval != 0)
- dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
-
- return retval;
-}
-
-int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
- unsigned int device_addr,
- unsigned int reg_addr,
- unsigned int *data)
-{
- u32 reg;
- int i;
- int retval;
-
- for (i = 0; i < 3; i++) {
- /* Clear AUX CH data buffer */
- reg = BUF_CLR;
- writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
- /* Select EDID device */
- retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr);
- if (retval != 0)
- continue;
-
- /*
- * Set I2C transaction and read data
- * If bit 3 is 1, DisplayPort transaction.
- * If Bit 3 is 0, I2C transaction.
- */
- reg = AUX_TX_COMM_I2C_TRANSACTION |
- AUX_TX_COMM_READ;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
- /* Start AUX transaction */
- retval = exynos_dp_start_aux_transaction(dp);
- if (retval == 0)
- break;
- else
- dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
- __func__);
- }
-
- /* Read data */
- if (retval == 0)
- *data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-
- return retval;
-}
-
-int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
- unsigned int device_addr,
- unsigned int reg_addr,
- unsigned int count,
- unsigned char edid[])
-{
- u32 reg;
- unsigned int i, j;
- unsigned int cur_data_idx;
- unsigned int defer = 0;
- int retval = 0;
-
- for (i = 0; i < count; i += 16) {
- for (j = 0; j < 3; j++) {
- /* Clear AUX CH data buffer */
- reg = BUF_CLR;
- writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
- /* Set normal AUX CH command */
- reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
- reg &= ~ADDR_ONLY;
- writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-
- /*
- * If Rx sends defer, Tx sends only reads
- * request without sending address
- */
- if (!defer)
- retval = exynos_dp_select_i2c_device(dp,
- device_addr, reg_addr + i);
- else
- defer = 0;
-
- if (retval == 0) {
- /*
- * Set I2C transaction and write data
- * If bit 3 is 1, DisplayPort transaction.
- * If Bit 3 is 0, I2C transaction.
- */
- reg = AUX_LENGTH(16) |
- AUX_TX_COMM_I2C_TRANSACTION |
- AUX_TX_COMM_READ;
- writel(reg, dp->reg_base +
- EXYNOS_DP_AUX_CH_CTL_1);
-
- /* Start AUX transaction */
- retval = exynos_dp_start_aux_transaction(dp);
- if (retval == 0)
- break;
- else
- dev_dbg(dp->dev,
- "%s: Aux Transaction fail!\n",
- __func__);
- }
- /* Check if Rx sends defer */
- reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM);
- if (reg == AUX_RX_COMM_AUX_DEFER ||
- reg == AUX_RX_COMM_I2C_DEFER) {
- dev_err(dp->dev, "Defer: %d\n\n", reg);
- defer = 1;
- }
- }
-
- for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
- reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
- + 4 * cur_data_idx);
- edid[i + cur_data_idx] = (unsigned char)reg;
- }
- }
-
- return retval;
-}
-
-void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype)
-{
- u32 reg;
-
- reg = bwtype;
- if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
- writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET);
-}
-
-void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET);
- *bwtype = reg;
-}
-
-void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count)
-{
- u32 reg;
-
- reg = count;
- writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
-}
-
-void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
- *count = reg;
-}
-
-void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable)
-{
- u32 reg;
-
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
- reg |= ENHANCED;
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
- reg &= ~ENHANCED;
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
- }
-}
-
-void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
- enum pattern_set pattern)
-{
- u32 reg;
-
- switch (pattern) {
- case PRBS7:
- reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
- writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
- break;
- case D10_2:
- reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
- writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
- break;
- case TRAINING_PTN1:
- reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
- writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
- break;
- case TRAINING_PTN2:
- reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
- writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
- break;
- case DP_NONE:
- reg = SCRAMBLING_ENABLE |
- LINK_QUAL_PATTERN_SET_DISABLE |
- SW_TRAINING_PATTERN_SET_NORMAL;
- writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
- break;
- default:
- break;
- }
-}
-
-void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
- reg &= ~PRE_EMPHASIS_SET_MASK;
- reg |= level << PRE_EMPHASIS_SET_SHIFT;
- writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
- reg &= ~PRE_EMPHASIS_SET_MASK;
- reg |= level << PRE_EMPHASIS_SET_SHIFT;
- writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
- reg &= ~PRE_EMPHASIS_SET_MASK;
- reg |= level << PRE_EMPHASIS_SET_SHIFT;
- writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
- reg &= ~PRE_EMPHASIS_SET_MASK;
- reg |= level << PRE_EMPHASIS_SET_SHIFT;
- writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
- u32 training_lane)
-{
- u32 reg;
-
- reg = training_lane;
- writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
- u32 training_lane)
-{
- u32 reg;
-
- reg = training_lane;
- writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
- u32 training_lane)
-{
- u32 reg;
-
- reg = training_lane;
- writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
- u32 training_lane)
-{
- u32 reg;
-
- reg = training_lane;
- writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-}
-
-u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
- return reg;
-}
-
-u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
- return reg;
-}
-
-u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
- return reg;
-}
-
-u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
- return reg;
-}
-
-void exynos_dp_reset_macro(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST);
- reg |= MACRO_RST;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
-
- /* 10 us is the minimum reset time. */
- usleep_range(10, 20);
-
- reg &= ~MACRO_RST;
- writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
-}
-
-void exynos_dp_init_video(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
- writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
-
- reg = 0x0;
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-
- reg = CHA_CRI(4) | CHA_CTRL;
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-
- reg = 0x0;
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-
- reg = VID_HRES_TH(2) | VID_VRES_TH(0);
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
-}
-
-void exynos_dp_set_video_color_format(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- /* Configure the input color depth, color space, dynamic range */
- reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) |
- (dp->video_info->color_depth << IN_BPC_SHIFT) |
- (dp->video_info->color_space << IN_COLOR_F_SHIFT);
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2);
-
- /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
- reg &= ~IN_YC_COEFFI_MASK;
- if (dp->video_info->ycbcr_coeff)
- reg |= IN_YC_COEFFI_ITU709;
- else
- reg |= IN_YC_COEFFI_ITU601;
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
-}
-
-int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-
- if (!(reg & DET_STA)) {
- dev_dbg(dp->dev, "Input stream clock not detected.\n");
- return -EINVAL;
- }
-
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
- dev_dbg(dp->dev, "wait SYS_CTL_2.\n");
-
- if (reg & CHA_STA) {
- dev_dbg(dp->dev, "Input stream clk is changing\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
- enum clock_recovery_m_value_type type,
- u32 m_value,
- u32 n_value)
-{
- u32 reg;
-
- if (type == REGISTER_M) {
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
- reg |= FIX_M_VID;
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
- reg = m_value & 0xff;
- writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0);
- reg = (m_value >> 8) & 0xff;
- writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1);
- reg = (m_value >> 16) & 0xff;
- writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2);
-
- reg = n_value & 0xff;
- writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0);
- reg = (n_value >> 8) & 0xff;
- writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1);
- reg = (n_value >> 16) & 0xff;
- writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
- reg &= ~FIX_M_VID;
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-
- writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0);
- writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1);
- writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2);
- }
-}
-
-void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type)
-{
- u32 reg;
-
- if (type == VIDEO_TIMING_FROM_CAPTURE) {
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
- reg &= ~FORMAT_SEL;
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
- reg |= FORMAT_SEL;
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
- }
-}
-
-void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable)
-{
- u32 reg;
-
- if (enable) {
- reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
- reg &= ~VIDEO_MODE_MASK;
- reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
- writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
- } else {
- reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
- reg &= ~VIDEO_MODE_MASK;
- reg |= VIDEO_MODE_SLAVE_MODE;
- writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
- }
-}
-
-void exynos_dp_start_video(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
- reg |= VIDEO_EN;
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-}
-
-int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
- writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-
- reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
- if (!(reg & STRM_VALID)) {
- dev_dbg(dp->dev, "Input video stream is not detected.\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
- reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
- reg |= MASTER_VID_FUNC_EN_N;
- writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
- reg &= ~INTERACE_SCAN_CFG;
- reg |= (dp->video_info->interlaced << 2);
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
- reg &= ~VSYNC_POLARITY_CFG;
- reg |= (dp->video_info->v_sync_polarity << 1);
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-
- reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
- reg &= ~HSYNC_POLARITY_CFG;
- reg |= (dp->video_info->h_sync_polarity << 0);
- writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-
- reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
- writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-}
-
-void exynos_dp_enable_scrambling(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
- reg &= ~SCRAMBLING_DISABLE;
- writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-}
-
-void exynos_dp_disable_scrambling(struct exynos_dp_device *dp)
-{
- u32 reg;
-
- reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
- reg |= SCRAMBLING_DISABLE;
- writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-}
diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h
deleted file mode 100644
index 2e9bd0e..0000000
--- a/drivers/video/exynos/exynos_dp_reg.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Register definition file for Samsung DP driver
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@samsung.com>
- *
- * 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.
- */
-
-#ifndef _EXYNOS_DP_REG_H
-#define _EXYNOS_DP_REG_H
-
-#define EXYNOS_DP_TX_SW_RESET 0x14
-#define EXYNOS_DP_FUNC_EN_1 0x18
-#define EXYNOS_DP_FUNC_EN_2 0x1C
-#define EXYNOS_DP_VIDEO_CTL_1 0x20
-#define EXYNOS_DP_VIDEO_CTL_2 0x24
-#define EXYNOS_DP_VIDEO_CTL_3 0x28
-
-#define EXYNOS_DP_VIDEO_CTL_8 0x3C
-#define EXYNOS_DP_VIDEO_CTL_10 0x44
-
-#define EXYNOS_DP_LANE_MAP 0x35C
-
-#define EXYNOS_DP_ANALOG_CTL_1 0x370
-#define EXYNOS_DP_ANALOG_CTL_2 0x374
-#define EXYNOS_DP_ANALOG_CTL_3 0x378
-#define EXYNOS_DP_PLL_FILTER_CTL_1 0x37C
-#define EXYNOS_DP_TX_AMP_TUNING_CTL 0x380
-
-#define EXYNOS_DP_AUX_HW_RETRY_CTL 0x390
-
-#define EXYNOS_DP_COMMON_INT_STA_1 0x3C4
-#define EXYNOS_DP_COMMON_INT_STA_2 0x3C8
-#define EXYNOS_DP_COMMON_INT_STA_3 0x3CC
-#define EXYNOS_DP_COMMON_INT_STA_4 0x3D0
-#define EXYNOS_DP_INT_STA 0x3DC
-#define EXYNOS_DP_COMMON_INT_MASK_1 0x3E0
-#define EXYNOS_DP_COMMON_INT_MASK_2 0x3E4
-#define EXYNOS_DP_COMMON_INT_MASK_3 0x3E8
-#define EXYNOS_DP_COMMON_INT_MASK_4 0x3EC
-#define EXYNOS_DP_INT_STA_MASK 0x3F8
-#define EXYNOS_DP_INT_CTL 0x3FC
-
-#define EXYNOS_DP_SYS_CTL_1 0x600
-#define EXYNOS_DP_SYS_CTL_2 0x604
-#define EXYNOS_DP_SYS_CTL_3 0x608
-#define EXYNOS_DP_SYS_CTL_4 0x60C
-
-#define EXYNOS_DP_PKT_SEND_CTL 0x640
-#define EXYNOS_DP_HDCP_CTL 0x648
-
-#define EXYNOS_DP_LINK_BW_SET 0x680
-#define EXYNOS_DP_LANE_COUNT_SET 0x684
-#define EXYNOS_DP_TRAINING_PTN_SET 0x688
-#define EXYNOS_DP_LN0_LINK_TRAINING_CTL 0x68C
-#define EXYNOS_DP_LN1_LINK_TRAINING_CTL 0x690
-#define EXYNOS_DP_LN2_LINK_TRAINING_CTL 0x694
-#define EXYNOS_DP_LN3_LINK_TRAINING_CTL 0x698
-
-#define EXYNOS_DP_DEBUG_CTL 0x6C0
-#define EXYNOS_DP_HPD_DEGLITCH_L 0x6C4
-#define EXYNOS_DP_HPD_DEGLITCH_H 0x6C8
-#define EXYNOS_DP_LINK_DEBUG_CTL 0x6E0
-
-#define EXYNOS_DP_M_VID_0 0x700
-#define EXYNOS_DP_M_VID_1 0x704
-#define EXYNOS_DP_M_VID_2 0x708
-#define EXYNOS_DP_N_VID_0 0x70C
-#define EXYNOS_DP_N_VID_1 0x710
-#define EXYNOS_DP_N_VID_2 0x714
-
-#define EXYNOS_DP_PLL_CTL 0x71C
-#define EXYNOS_DP_PHY_PD 0x720
-#define EXYNOS_DP_PHY_TEST 0x724
-
-#define EXYNOS_DP_VIDEO_FIFO_THRD 0x730
-#define EXYNOS_DP_AUDIO_MARGIN 0x73C
-
-#define EXYNOS_DP_M_VID_GEN_FILTER_TH 0x764
-#define EXYNOS_DP_M_AUD_GEN_FILTER_TH 0x778
-#define EXYNOS_DP_AUX_CH_STA 0x780
-#define EXYNOS_DP_AUX_CH_DEFER_CTL 0x788
-#define EXYNOS_DP_AUX_RX_COMM 0x78C
-#define EXYNOS_DP_BUFFER_DATA_CTL 0x790
-#define EXYNOS_DP_AUX_CH_CTL_1 0x794
-#define EXYNOS_DP_AUX_ADDR_7_0 0x798
-#define EXYNOS_DP_AUX_ADDR_15_8 0x79C
-#define EXYNOS_DP_AUX_ADDR_19_16 0x7A0
-#define EXYNOS_DP_AUX_CH_CTL_2 0x7A4
-
-#define EXYNOS_DP_BUF_DATA_0 0x7C0
-
-#define EXYNOS_DP_SOC_GENERAL_CTL 0x800
-
-/* EXYNOS_DP_TX_SW_RESET */
-#define RESET_DP_TX (0x1 << 0)
-
-/* EXYNOS_DP_FUNC_EN_1 */
-#define MASTER_VID_FUNC_EN_N (0x1 << 7)
-#define SLAVE_VID_FUNC_EN_N (0x1 << 5)
-#define AUD_FIFO_FUNC_EN_N (0x1 << 4)
-#define AUD_FUNC_EN_N (0x1 << 3)
-#define HDCP_FUNC_EN_N (0x1 << 2)
-#define CRC_FUNC_EN_N (0x1 << 1)
-#define SW_FUNC_EN_N (0x1 << 0)
-
-/* EXYNOS_DP_FUNC_EN_2 */
-#define SSC_FUNC_EN_N (0x1 << 7)
-#define AUX_FUNC_EN_N (0x1 << 2)
-#define SERDES_FIFO_FUNC_EN_N (0x1 << 1)
-#define LS_CLK_DOMAIN_FUNC_EN_N (0x1 << 0)
-
-/* EXYNOS_DP_VIDEO_CTL_1 */
-#define VIDEO_EN (0x1 << 7)
-#define HDCP_VIDEO_MUTE (0x1 << 6)
-
-/* EXYNOS_DP_VIDEO_CTL_1 */
-#define IN_D_RANGE_MASK (0x1 << 7)
-#define IN_D_RANGE_SHIFT (7)
-#define IN_D_RANGE_CEA (0x1 << 7)
-#define IN_D_RANGE_VESA (0x0 << 7)
-#define IN_BPC_MASK (0x7 << 4)
-#define IN_BPC_SHIFT (4)
-#define IN_BPC_12_BITS (0x3 << 4)
-#define IN_BPC_10_BITS (0x2 << 4)
-#define IN_BPC_8_BITS (0x1 << 4)
-#define IN_BPC_6_BITS (0x0 << 4)
-#define IN_COLOR_F_MASK (0x3 << 0)
-#define IN_COLOR_F_SHIFT (0)
-#define IN_COLOR_F_YCBCR444 (0x2 << 0)
-#define IN_COLOR_F_YCBCR422 (0x1 << 0)
-#define IN_COLOR_F_RGB (0x0 << 0)
-
-/* EXYNOS_DP_VIDEO_CTL_3 */
-#define IN_YC_COEFFI_MASK (0x1 << 7)
-#define IN_YC_COEFFI_SHIFT (7)
-#define IN_YC_COEFFI_ITU709 (0x1 << 7)
-#define IN_YC_COEFFI_ITU601 (0x0 << 7)
-#define VID_CHK_UPDATE_TYPE_MASK (0x1 << 4)
-#define VID_CHK_UPDATE_TYPE_SHIFT (4)
-#define VID_CHK_UPDATE_TYPE_1 (0x1 << 4)
-#define VID_CHK_UPDATE_TYPE_0 (0x0 << 4)
-
-/* EXYNOS_DP_VIDEO_CTL_8 */
-#define VID_HRES_TH(x) (((x) & 0xf) << 4)
-#define VID_VRES_TH(x) (((x) & 0xf) << 0)
-
-/* EXYNOS_DP_VIDEO_CTL_10 */
-#define FORMAT_SEL (0x1 << 4)
-#define INTERACE_SCAN_CFG (0x1 << 2)
-#define VSYNC_POLARITY_CFG (0x1 << 1)
-#define HSYNC_POLARITY_CFG (0x1 << 0)
-
-/* EXYNOS_DP_LANE_MAP */
-#define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6)
-#define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6)
-#define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6)
-#define LANE3_MAP_LOGIC_LANE_3 (0x3 << 6)
-#define LANE2_MAP_LOGIC_LANE_0 (0x0 << 4)
-#define LANE2_MAP_LOGIC_LANE_1 (0x1 << 4)
-#define LANE2_MAP_LOGIC_LANE_2 (0x2 << 4)
-#define LANE2_MAP_LOGIC_LANE_3 (0x3 << 4)
-#define LANE1_MAP_LOGIC_LANE_0 (0x0 << 2)
-#define LANE1_MAP_LOGIC_LANE_1 (0x1 << 2)
-#define LANE1_MAP_LOGIC_LANE_2 (0x2 << 2)
-#define LANE1_MAP_LOGIC_LANE_3 (0x3 << 2)
-#define LANE0_MAP_LOGIC_LANE_0 (0x0 << 0)
-#define LANE0_MAP_LOGIC_LANE_1 (0x1 << 0)
-#define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0)
-#define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0)
-
-/* EXYNOS_DP_ANALOG_CTL_1 */
-#define TX_TERMINAL_CTRL_50_OHM (0x1 << 4)
-
-/* EXYNOS_DP_ANALOG_CTL_2 */
-#define SEL_24M (0x1 << 3)
-#define TX_DVDD_BIT_1_0625V (0x4 << 0)
-
-/* EXYNOS_DP_ANALOG_CTL_3 */
-#define DRIVE_DVDD_BIT_1_0625V (0x4 << 5)
-#define VCO_BIT_600_MICRO (0x5 << 0)
-
-/* EXYNOS_DP_PLL_FILTER_CTL_1 */
-#define PD_RING_OSC (0x1 << 6)
-#define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4)
-#define TX_CUR1_2X (0x1 << 2)
-#define TX_CUR_16_MA (0x3 << 0)
-
-/* EXYNOS_DP_TX_AMP_TUNING_CTL */
-#define CH3_AMP_400_MV (0x0 << 24)
-#define CH2_AMP_400_MV (0x0 << 16)
-#define CH1_AMP_400_MV (0x0 << 8)
-#define CH0_AMP_400_MV (0x0 << 0)
-
-/* EXYNOS_DP_AUX_HW_RETRY_CTL */
-#define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8)
-#define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3)
-#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3)
-#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3)
-#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS (0x2 << 3)
-#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3)
-#define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0)
-
-/* EXYNOS_DP_COMMON_INT_STA_1 */
-#define VSYNC_DET (0x1 << 7)
-#define PLL_LOCK_CHG (0x1 << 6)
-#define SPDIF_ERR (0x1 << 5)
-#define SPDIF_UNSTBL (0x1 << 4)
-#define VID_FORMAT_CHG (0x1 << 3)
-#define AUD_CLK_CHG (0x1 << 2)
-#define VID_CLK_CHG (0x1 << 1)
-#define SW_INT (0x1 << 0)
-
-/* EXYNOS_DP_COMMON_INT_STA_2 */
-#define ENC_EN_CHG (0x1 << 6)
-#define HW_BKSV_RDY (0x1 << 3)
-#define HW_SHA_DONE (0x1 << 2)
-#define HW_AUTH_STATE_CHG (0x1 << 1)
-#define HW_AUTH_DONE (0x1 << 0)
-
-/* EXYNOS_DP_COMMON_INT_STA_3 */
-#define AFIFO_UNDER (0x1 << 7)
-#define AFIFO_OVER (0x1 << 6)
-#define R0_CHK_FLAG (0x1 << 5)
-
-/* EXYNOS_DP_COMMON_INT_STA_4 */
-#define PSR_ACTIVE (0x1 << 7)
-#define PSR_INACTIVE (0x1 << 6)
-#define SPDIF_BI_PHASE_ERR (0x1 << 5)
-#define HOTPLUG_CHG (0x1 << 2)
-#define HPD_LOST (0x1 << 1)
-#define PLUG (0x1 << 0)
-
-/* EXYNOS_DP_INT_STA */
-#define INT_HPD (0x1 << 6)
-#define HW_TRAINING_FINISH (0x1 << 5)
-#define RPLY_RECEIV (0x1 << 1)
-#define AUX_ERR (0x1 << 0)
-
-/* EXYNOS_DP_INT_CTL */
-#define SOFT_INT_CTRL (0x1 << 2)
-#define INT_POL1 (0x1 << 1)
-#define INT_POL0 (0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_1 */
-#define DET_STA (0x1 << 2)
-#define FORCE_DET (0x1 << 1)
-#define DET_CTRL (0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_2 */
-#define CHA_CRI(x) (((x) & 0xf) << 4)
-#define CHA_STA (0x1 << 2)
-#define FORCE_CHA (0x1 << 1)
-#define CHA_CTRL (0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_3 */
-#define HPD_STATUS (0x1 << 6)
-#define F_HPD (0x1 << 5)
-#define HPD_CTRL (0x1 << 4)
-#define HDCP_RDY (0x1 << 3)
-#define STRM_VALID (0x1 << 2)
-#define F_VALID (0x1 << 1)
-#define VALID_CTRL (0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_4 */
-#define FIX_M_AUD (0x1 << 4)
-#define ENHANCED (0x1 << 3)
-#define FIX_M_VID (0x1 << 2)
-#define M_VID_UPDATE_CTRL (0x3 << 0)
-
-/* EXYNOS_DP_TRAINING_PTN_SET */
-#define SCRAMBLER_TYPE (0x1 << 9)
-#define HW_LINK_TRAINING_PATTERN (0x1 << 8)
-#define SCRAMBLING_DISABLE (0x1 << 5)
-#define SCRAMBLING_ENABLE (0x0 << 5)
-#define LINK_QUAL_PATTERN_SET_MASK (0x3 << 2)
-#define LINK_QUAL_PATTERN_SET_PRBS7 (0x3 << 2)
-#define LINK_QUAL_PATTERN_SET_D10_2 (0x1 << 2)
-#define LINK_QUAL_PATTERN_SET_DISABLE (0x0 << 2)
-#define SW_TRAINING_PATTERN_SET_MASK (0x3 << 0)
-#define SW_TRAINING_PATTERN_SET_PTN2 (0x2 << 0)
-#define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0)
-#define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0)
-
-/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
-#define PRE_EMPHASIS_SET_MASK (0x3 << 3)
-#define PRE_EMPHASIS_SET_SHIFT (3)
-
-/* EXYNOS_DP_DEBUG_CTL */
-#define PLL_LOCK (0x1 << 4)
-#define F_PLL_LOCK (0x1 << 3)
-#define PLL_LOCK_CTRL (0x1 << 2)
-#define PN_INV (0x1 << 0)
-
-/* EXYNOS_DP_PLL_CTL */
-#define DP_PLL_PD (0x1 << 7)
-#define DP_PLL_RESET (0x1 << 6)
-#define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4)
-#define DP_PLL_REF_BIT_1_1250V (0x5 << 0)
-#define DP_PLL_REF_BIT_1_2500V (0x7 << 0)
-
-/* EXYNOS_DP_PHY_PD */
-#define DP_PHY_PD (0x1 << 5)
-#define AUX_PD (0x1 << 4)
-#define CH3_PD (0x1 << 3)
-#define CH2_PD (0x1 << 2)
-#define CH1_PD (0x1 << 1)
-#define CH0_PD (0x1 << 0)
-
-/* EXYNOS_DP_PHY_TEST */
-#define MACRO_RST (0x1 << 5)
-#define CH1_TEST (0x1 << 1)
-#define CH0_TEST (0x1 << 0)
-
-/* EXYNOS_DP_AUX_CH_STA */
-#define AUX_BUSY (0x1 << 4)
-#define AUX_STATUS_MASK (0xf << 0)
-
-/* EXYNOS_DP_AUX_CH_DEFER_CTL */
-#define DEFER_CTRL_EN (0x1 << 7)
-#define DEFER_COUNT(x) (((x) & 0x7f) << 0)
-
-/* EXYNOS_DP_AUX_RX_COMM */
-#define AUX_RX_COMM_I2C_DEFER (0x2 << 2)
-#define AUX_RX_COMM_AUX_DEFER (0x2 << 0)
-
-/* EXYNOS_DP_BUFFER_DATA_CTL */
-#define BUF_CLR (0x1 << 7)
-#define BUF_DATA_COUNT(x) (((x) & 0x1f) << 0)
-
-/* EXYNOS_DP_AUX_CH_CTL_1 */
-#define AUX_LENGTH(x) (((x - 1) & 0xf) << 4)
-#define AUX_TX_COMM_MASK (0xf << 0)
-#define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3)
-#define AUX_TX_COMM_I2C_TRANSACTION (0x0 << 3)
-#define AUX_TX_COMM_MOT (0x1 << 2)
-#define AUX_TX_COMM_WRITE (0x0 << 0)
-#define AUX_TX_COMM_READ (0x1 << 0)
-
-/* EXYNOS_DP_AUX_ADDR_7_0 */
-#define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff)
-
-/* EXYNOS_DP_AUX_ADDR_15_8 */
-#define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff)
-
-/* EXYNOS_DP_AUX_ADDR_19_16 */
-#define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f)
-
-/* EXYNOS_DP_AUX_CH_CTL_2 */
-#define ADDR_ONLY (0x1 << 1)
-#define AUX_EN (0x1 << 0)
-
-/* EXYNOS_DP_SOC_GENERAL_CTL */
-#define AUDIO_MODE_SPDIF_MODE (0x1 << 8)
-#define AUDIO_MODE_MASTER_MODE (0x0 << 8)
-#define MASTER_VIDEO_INTERLACE_EN (0x1 << 4)
-#define VIDEO_MASTER_CLK_SEL (0x1 << 2)
-#define VIDEO_MASTER_MODE_EN (0x1 << 1)
-#define VIDEO_MODE_MASK (0x1 << 0)
-#define VIDEO_MODE_SLAVE_MODE (0x1 << 0)
-#define VIDEO_MODE_MASTER_MODE (0x0 << 0)
-
-#endif /* _EXYNOS_DP_REG_H */
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 22/23] drm/exynos: Move display implementation into dp
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (20 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 21/23] drm/exynos: Move dp driver from video/ to drm/ Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-11 0:30 ` [PATCH 23/23] ARM: dts: Move display-timings node from fimd to dp Sean Paul
2013-10-12 2:26 ` [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Tomasz Figa
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch moves the exynos_drm_display implementation from fimd into
the dp driver. This will allow for tighter integration of the dp driver
into the exynos drm driver.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
.../devicetree/bindings/video/exynos_dp.txt | 17 +++
.../devicetree/bindings/video/samsung-fimd.txt | 2 +
drivers/gpu/drm/exynos/exynos_dp_core.c | 136 +++++++++++++++------
drivers/gpu/drm/exynos/exynos_dp_core.h | 5 +
drivers/gpu/drm/exynos/exynos_drm_drv.c | 14 +++
drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 +
drivers/gpu/drm/exynos/exynos_drm_fimd.c | 77 +++---------
7 files changed, 155 insertions(+), 97 deletions(-)
diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt
index 84f10c1..a073e15 100644
--- a/Documentation/devicetree/bindings/video/exynos_dp.txt
+++ b/Documentation/devicetree/bindings/video/exynos_dp.txt
@@ -45,6 +45,8 @@ Required properties for dp-controller:
-samsung,lane-count:
number of lanes supported by the panel.
LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4
+ - display-timings: timings for the connected panel as described by
+ Documentation/devicetree/bindings/video/display-timing.txt
Optional properties for dp-controller:
-interlaced:
@@ -83,4 +85,19 @@ Board Specific portion:
samsung,color-depth = <1>;
samsung,link-rate = <0x0a>;
samsung,lane-count = <4>;
+
+ display-timings {
+ native-mode = <&lcd_timing>;
+ lcd_timing: 1366x768 {
+ clock-frequency = <70589280>;
+ hactive = <1366>;
+ vactive = <768>;
+ hfront-porch = <40>;
+ hback-porch = <40>;
+ hsync-len = <32>;
+ vback-porch = <10>;
+ vfront-porch = <12>;
+ vsync-len = <6>;
+ };
+ };
};
diff --git a/Documentation/devicetree/bindings/video/samsung-fimd.txt b/Documentation/devicetree/bindings/video/samsung-fimd.txt
index 778838a..fa465c3 100644
--- a/Documentation/devicetree/bindings/video/samsung-fimd.txt
+++ b/Documentation/devicetree/bindings/video/samsung-fimd.txt
@@ -39,6 +39,8 @@ Required properties:
Optional Properties:
- samsung,power-domain: a phandle to FIMD power domain node.
+- samsung,invert-vden: video enable signal is inverted
+- samsung,invert_vclk: video clock signal is inverted
Example:
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 089ae22..361cc8c 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -18,9 +18,12 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/of.h>
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
-#include <video/exynos_dp.h>
+#include <drm/drmP.h>
+#include "exynos_drm_drv.h"
#include "exynos_dp_core.h"
static int exynos_dp_init_dp(struct exynos_dp_device *dp)
@@ -893,6 +896,34 @@ static void exynos_dp_hotplug(struct work_struct *work)
dev_err(dp->dev, "unable to config video\n");
}
+static bool exynos_dp_display_is_connected(void *in_ctx)
+{
+ return true;
+}
+
+static void *exynos_dp_get_panel(void *in_ctx)
+{
+ struct exynos_dp_device *dp = in_ctx;
+
+ return &dp->panel;
+}
+
+static int exynos_dp_check_mode(void *in_ctx, struct drm_display_mode *mode)
+{
+ return 0;
+}
+
+static struct exynos_drm_display_ops exynos_dp_display_ops = {
+ .is_connected = exynos_dp_display_is_connected,
+ .get_panel = exynos_dp_get_panel,
+ .check_mode = exynos_dp_check_mode,
+};
+
+static struct exynos_drm_display exynos_dp_display = {
+ .type = EXYNOS_DISPLAY_TYPE_LCD,
+ .ops = &exynos_dp_display_ops,
+};
+
#ifdef CONFIG_OF
static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
{
@@ -1000,6 +1031,19 @@ err:
return ret;
}
+static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
+{
+ int ret;
+
+ ret = of_get_videomode(dp->dev->of_node, &dp->panel.vm,
+ OF_USE_NATIVE_MODE);
+ if (ret) {
+ DRM_ERROR("failed: of_get_videomode() : %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
static void exynos_dp_phy_init(struct exynos_dp_device *dp)
{
u32 reg;
@@ -1028,6 +1072,11 @@ static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
return -EINVAL;
}
+static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
+{
+ return -EINVAL;
+}
+
static void exynos_dp_phy_init(struct exynos_dp_device *dp)
{
return;
@@ -1039,6 +1088,46 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
}
#endif /* CONFIG_OF */
+void exynos_dp_poweron(struct exynos_dp_device *dp)
+{
+ struct device *dev = dp->dev;
+ struct exynos_dp_platdata *pdata = dev->platform_data;
+
+ if (dev->of_node) {
+ if (dp->phy_addr)
+ exynos_dp_phy_init(dp);
+ } else {
+ if (pdata->phy_init)
+ pdata->phy_init();
+ }
+
+ clk_prepare_enable(dp->clock);
+
+ exynos_dp_init_dp(dp);
+
+ enable_irq(dp->irq);
+}
+
+void exynos_dp_poweroff(struct exynos_dp_device *dp)
+{
+ struct device *dev = dp->dev;
+ struct exynos_dp_platdata *pdata = dev->platform_data;
+
+ disable_irq(dp->irq);
+
+ flush_work(&dp->hotplug_work);
+
+ if (dev->of_node) {
+ if (dp->phy_addr)
+ exynos_dp_phy_exit(dp);
+ } else {
+ if (pdata->phy_exit)
+ pdata->phy_exit();
+ }
+
+ clk_disable_unprepare(dp->clock);
+}
+
static int exynos_dp_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -1064,6 +1153,10 @@ static int exynos_dp_probe(struct platform_device *pdev)
ret = exynos_dp_dt_parse_phydata(dp);
if (ret)
return ret;
+
+ ret = exynos_dp_dt_parse_panel(dp);
+ if (ret)
+ return ret;
} else {
pdata = pdev->dev.platform_data;
if (!pdata) {
@@ -1115,6 +1208,9 @@ static int exynos_dp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dp);
+ exynos_dp_display.ctx = dp;
+ exynos_drm_display_register(&exynos_dp_display);
+
return 0;
}
@@ -1123,6 +1219,8 @@ static int exynos_dp_remove(struct platform_device *pdev)
struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+ exynos_drm_display_unregister(&exynos_dp_display);
+
flush_work(&dp->hotplug_work);
if (pdev->dev.of_node) {
@@ -1142,45 +1240,17 @@ static int exynos_dp_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int exynos_dp_suspend(struct device *dev)
{
- struct exynos_dp_platdata *pdata = dev->platform_data;
struct exynos_dp_device *dp = dev_get_drvdata(dev);
- disable_irq(dp->irq);
-
- flush_work(&dp->hotplug_work);
-
- if (dev->of_node) {
- if (dp->phy_addr)
- exynos_dp_phy_exit(dp);
- } else {
- if (pdata->phy_exit)
- pdata->phy_exit();
- }
-
- clk_disable_unprepare(dp->clock);
-
+ exynos_dp_poweroff(dp);
return 0;
}
static int exynos_dp_resume(struct device *dev)
{
- struct exynos_dp_platdata *pdata = dev->platform_data;
struct exynos_dp_device *dp = dev_get_drvdata(dev);
- if (dev->of_node) {
- if (dp->phy_addr)
- exynos_dp_phy_init(dp);
- } else {
- if (pdata->phy_init)
- pdata->phy_init();
- }
-
- clk_prepare_enable(dp->clock);
-
- exynos_dp_init_dp(dp);
-
- enable_irq(dp->irq);
-
+ exynos_dp_poweron(dp);
return 0;
}
#endif
@@ -1195,7 +1265,7 @@ static const struct of_device_id exynos_dp_match[] = {
};
MODULE_DEVICE_TABLE(of, exynos_dp_match);
-static struct platform_driver exynos_dp_driver = {
+struct platform_driver dp_driver = {
.probe = exynos_dp_probe,
.remove = exynos_dp_remove,
.driver = {
@@ -1206,8 +1276,6 @@ static struct platform_driver exynos_dp_driver = {
},
};
-module_platform_driver(exynos_dp_driver);
-
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
MODULE_DESCRIPTION("Samsung SoC DP Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
index 6c567bbf..a5e9145 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.h
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -13,6 +13,9 @@
#ifndef _EXYNOS_DP_CORE_H
#define _EXYNOS_DP_CORE_H
+#include <drm/exynos_drm.h>
+#include <video/exynos_dp.h>
+
enum dp_irq_type {
DP_IRQ_TYPE_HP_CABLE_IN,
DP_IRQ_TYPE_HP_CABLE_OUT,
@@ -42,6 +45,8 @@ struct exynos_dp_device {
struct video_info *video_info;
struct link_train link_train;
struct work_struct hotplug_work;
+
+ struct exynos_drm_panel_info panel;
};
/* exynos_dp_reg.c */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 4b265bf..03caa3a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -316,6 +316,12 @@ static int __init exynos_drm_init(void)
{
int ret;
+#ifdef CONFIG_DRM_EXYNOS_DP
+ ret = platform_driver_register(&dp_driver);
+ if (ret < 0)
+ goto out_dp;
+#endif
+
#ifdef CONFIG_DRM_EXYNOS_FIMD
ret = platform_driver_register(&fimd_driver);
if (ret < 0)
@@ -431,6 +437,10 @@ out_hdmi:
platform_driver_unregister(&fimd_driver);
out_fimd:
#endif
+#ifdef CONFIG_DRM_EXYNOS_DP
+ platform_driver_unregister(&dp_driver);
+out_dp:
+#endif
return ret;
}
@@ -473,6 +483,10 @@ static void __exit exynos_drm_exit(void)
#ifdef CONFIG_DRM_EXYNOS_FIMD
platform_driver_unregister(&fimd_driver);
#endif
+
+#ifdef CONFIG_DRM_EXYNOS_DP
+ platform_driver_unregister(&dp_driver);
+#endif
}
module_init(exynos_drm_init);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 0a956d0..ce7a497 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -359,6 +359,7 @@ int exynos_platform_device_ipp_register(void);
*/
void exynos_platform_device_ipp_unregister(void);
+extern struct platform_driver dp_driver;
extern struct platform_driver fimd_driver;
extern struct platform_driver hdmi_driver;
extern struct platform_driver mixer_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index f2d7058..0f8c19f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -158,38 +158,6 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
return (struct fimd_driver_data *)of_id->data;
}
-static bool fimd_display_is_connected(void *in_ctx)
-{
- /* TODO. */
-
- return true;
-}
-
-static void *fimd_get_panel(void *in_ctx)
-{
- struct fimd_context *ctx = in_ctx;
-
- return &ctx->panel;
-}
-
-static int fimd_check_mode(void *in_ctx, struct drm_display_mode *mode)
-{
- /* TODO. */
-
- return 0;
-}
-
-static struct exynos_drm_display_ops fimd_display_ops = {
- .is_connected = fimd_display_is_connected,
- .get_panel = fimd_get_panel,
- .check_mode = fimd_check_mode,
-};
-
-static struct exynos_drm_display fimd_display = {
- .type = EXYNOS_DISPLAY_TYPE_LCD,
- .ops = &fimd_display_ops,
-};
-
static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
{
struct fimd_context *ctx = in_ctx;
@@ -607,6 +575,16 @@ static void fimd_mode_set(void *in_ctx, const struct drm_display_mode *in_mode)
mode->hfpd = hblank - mode->hsync_len - mode->hbpd;
mode->clkdiv = fimd_calc_clkdiv(ctx, in_mode);
+
+ if (in_mode->flags & DRM_MODE_FLAG_NVSYNC)
+ ctx->vidcon1 |= VIDCON1_INV_VSYNC;
+ else
+ ctx->vidcon1 &= ~VIDCON1_INV_VSYNC;
+
+ if (in_mode->flags & DRM_MODE_FLAG_NHSYNC)
+ ctx->vidcon1 |= VIDCON1_INV_HSYNC;
+ else
+ ctx->vidcon1 &= ~VIDCON1_INV_HSYNC;
}
static void fimd_commit(void *in_ctx)
@@ -879,30 +857,6 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
return 0;
}
-static int fimd_get_platform_data(struct fimd_context *ctx, struct device *dev)
-{
- struct videomode *vm;
- int ret;
-
- vm = &ctx->panel.vm;
- ret = of_get_videomode(dev->of_node, vm, OF_USE_NATIVE_MODE);
- if (ret) {
- DRM_ERROR("failed: of_get_videomode() : %d\n", ret);
- return ret;
- }
-
- if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
- ctx->vidcon1 |= VIDCON1_INV_VSYNC;
- if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
- ctx->vidcon1 |= VIDCON1_INV_HSYNC;
- if (vm->flags & DISPLAY_FLAGS_DE_LOW)
- ctx->vidcon1 |= VIDCON1_INV_VDEN;
- if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
- ctx->vidcon1 |= VIDCON1_INV_VCLK;
-
- return 0;
-}
-
static int fimd_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -918,9 +872,10 @@ static int fimd_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- ret = fimd_get_platform_data(ctx, dev);
- if (ret)
- return ret;
+ if (of_property_read_bool(dev->of_node, "samsung,invert-vden"))
+ ctx->vidcon1 |= VIDCON1_INV_VDEN;
+ if (of_property_read_bool(dev->of_node, "samsung,invert-vclk"))
+ ctx->vidcon1 |= VIDCON1_INV_VCLK;
ctx->bus_clk = devm_clk_get(dev, "fimd");
if (IS_ERR(ctx->bus_clk)) {
@@ -968,9 +923,6 @@ static int fimd_probe(struct platform_device *pdev)
fimd_manager.ctx = ctx;
exynos_drm_manager_register(&fimd_manager);
- fimd_display.ctx = ctx;
- exynos_drm_display_register(&fimd_display);
-
return 0;
}
@@ -979,7 +931,6 @@ static int fimd_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct fimd_context *ctx = platform_get_drvdata(pdev);
- exynos_drm_display_unregister(&fimd_display);
exynos_drm_manager_unregister(&fimd_manager);
if (ctx->suspended)
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 23/23] ARM: dts: Move display-timings node from fimd to dp
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (21 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 22/23] drm/exynos: Move display implementation into dp Sean Paul
@ 2013-10-11 0:30 ` Sean Paul
2013-10-12 2:26 ` [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Tomasz Figa
23 siblings, 0 replies; 38+ messages in thread
From: Sean Paul @ 2013-10-11 0:30 UTC (permalink / raw)
To: dri-devel, inki.dae; +Cc: marcheu
This patch moves the display-timings node from fimd to dp to reflect the
device tree bindings change.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
arch/arm/boot/dts/exynos5250-arndale.dts | 7 ++++---
arch/arm/boot/dts/exynos5250-smdk5250.dts | 7 ++++---
arch/arm/boot/dts/exynos5250-snow.dts | 7 ++++---
arch/arm/boot/dts/exynos5420-smdk5420.dts | 7 ++++---
4 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index cee55fa..4583de4 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -517,10 +517,7 @@
samsung,link-rate = <0x0a>;
samsung,lane-count = <4>;
status = "okay";
- };
- fimd: fimd@14400000 {
- status = "okay";
display-timings {
native-mode = <&timing0>;
timing0: timing@0 {
@@ -538,6 +535,10 @@
};
};
+ fimd: fimd@14400000 {
+ status = "okay";
+ };
+
usb_hub_bus {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index 2538b32..df1001d 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -261,10 +261,7 @@
pinctrl-names = "default";
pinctrl-0 = <&dp_hpd>;
status = "okay";
- };
- fimd@14400000 {
- status = "okay";
display-timings {
native-mode = <&timing0>;
timing0: timing@0 {
@@ -282,6 +279,10 @@
};
};
+ fimd@14400000 {
+ status = "okay";
+ };
+
fixed-rate-clocks {
xxti {
compatible = "samsung,clock-xxti";
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index 8c92df8..b2783d8 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -216,10 +216,7 @@
pinctrl-names = "default";
pinctrl-0 = <&dp_hpd>;
status = "okay";
- };
- fimd: fimd@14400000 {
- status = "okay";
display-timings {
native-mode = <&lcd_timing>;
lcd_timing: 1366x768 {
@@ -236,6 +233,10 @@
};
};
+ fimd: fimd@14400000 {
+ status = "okay";
+ };
+
fixed-rate-clocks {
xxti {
compatible = "samsung,clock-xxti";
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts
index bafba25..763797c 100644
--- a/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -41,10 +41,7 @@
samsung,link-rate = <0x0a>;
samsung,lane-count = <4>;
status = "okay";
- };
- fimd@14400000 {
- status = "okay";
display-timings {
native-mode = <&timing0>;
timing0: timing@0 {
@@ -61,4 +58,8 @@
};
};
+ fimd@14400000 {
+ status = "okay";
+ };
+
};
--
1.8.4
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-11 0:30 ` [PATCH 12/23] drm/exynos: Split manager/display/subdrv Sean Paul
@ 2013-10-12 0:42 ` Inki Dae
2013-10-12 2:06 ` Sean Paul
2013-10-14 15:24 ` Inki Dae
1 sibling, 1 reply; 38+ messages in thread
From: Inki Dae @ 2013-10-12 0:42 UTC (permalink / raw)
To: Sean Paul; +Cc: Stéphane Marchesin, DRI mailing list
> static int exynos_drm_create_enc_conn(struct drm_device *dev,
> - struct exynos_drm_subdrv *subdrv)
> + struct exynos_drm_display *display)
> {
> struct drm_encoder *encoder;
> struct drm_connector *connector;
> + struct exynos_drm_manager *manager;
> int ret;
> + unsigned long possible_crtcs = 0;
>
> - subdrv->manager->dev = subdrv->dev;
> + /* Find possible crtcs for this display */
> + list_for_each_entry(manager, &exynos_drm_manager_list, list)
> + if (manager->type == display->type)
> + possible_crtcs |= 1 << manager->pipe;
>
> /* create and initialize a encoder for this sub driver. */
> - encoder = exynos_drm_encoder_create(dev, subdrv->manager,
> - (1 << MAX_CRTC) - 1);
> + encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
> if (!encoder) {
> DRM_ERROR("failed to create encoder\n");
> return -EFAULT;
> }
> - subdrv->encoder = encoder;
> + display->encoder = encoder;
>
> - if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) {
> + if (display->type == EXYNOS_DISPLAY_TYPE_LCD) {
> ret = exynos_drm_attach_lcd_bridge(dev, encoder)
Plz, _do_not_base_ on top of your lvds bridge patch set. As I
mentioned before, the tricky codes are not good. For this, let's find
a better way after your refactoring patch set are reviewed enough, and
if merged.
> if (ret)
> return 0;
> @@ -91,7 +98,7 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev,
> goto err_destroy_encoder;
> }
>
> - subdrv->connector = connector;
> + display->connector = connector;
>
> return 0;
>
> @@ -100,21 +107,6 @@ err_destroy_encoder:
> return ret;
> }
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-12 0:42 ` Inki Dae
@ 2013-10-12 2:06 ` Sean Paul
2013-10-12 3:49 ` Inki Dae
0 siblings, 1 reply; 38+ messages in thread
From: Sean Paul @ 2013-10-12 2:06 UTC (permalink / raw)
To: Inki Dae; +Cc: Stéphane Marchesin, DRI mailing list
On Fri, Oct 11, 2013 at 8:42 PM, Inki Dae <inki.dae@samsung.com> wrote:
>> static int exynos_drm_create_enc_conn(struct drm_device *dev,
>> - struct exynos_drm_subdrv *subdrv)
>> + struct exynos_drm_display *display)
>> {
>> struct drm_encoder *encoder;
>> struct drm_connector *connector;
>> + struct exynos_drm_manager *manager;
>> int ret;
>> + unsigned long possible_crtcs = 0;
>>
>> - subdrv->manager->dev = subdrv->dev;
>> + /* Find possible crtcs for this display */
>> + list_for_each_entry(manager, &exynos_drm_manager_list, list)
>> + if (manager->type == display->type)
>> + possible_crtcs |= 1 << manager->pipe;
>>
>> /* create and initialize a encoder for this sub driver. */
>> - encoder = exynos_drm_encoder_create(dev, subdrv->manager,
>> - (1 << MAX_CRTC) - 1);
>> + encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
>> if (!encoder) {
>> DRM_ERROR("failed to create encoder\n");
>> return -EFAULT;
>> }
>> - subdrv->encoder = encoder;
>> + display->encoder = encoder;
>>
>> - if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) {
>> + if (display->type == EXYNOS_DISPLAY_TYPE_LCD) {
>> ret = exynos_drm_attach_lcd_bridge(dev, encoder)
>
> Plz, _do_not_base_ on top of your lvds bridge patch set. As I
> mentioned before, the tricky codes are not good. For this, let's find
> a better way after your refactoring patch set are reviewed enough, and
> if merged.
>
[+adding back the people you removed from CC]
I'm happy to change how that works, but I've yet to find a better
solution. Instead of just dismissing something as "tricky codes", can
you suggest a concrete solution that is better than what I've got?
I'm also a bit confused as to why you think it's so tricky, it's a
synchronous initialization call to a driver; that's about as simple as
it gets.
Sean
>> if (ret)
>> return 0;
>> @@ -91,7 +98,7 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev,
>> goto err_destroy_encoder;
>> }
>>
>> - subdrv->connector = connector;
>> + display->connector = connector;
>>
>> return 0;
>>
>> @@ -100,21 +107,6 @@ err_destroy_encoder:
>> return ret;
>> }
>>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
` (22 preceding siblings ...)
2013-10-11 0:30 ` [PATCH 23/23] ARM: dts: Move display-timings node from fimd to dp Sean Paul
@ 2013-10-12 2:26 ` Tomasz Figa
23 siblings, 0 replies; 38+ messages in thread
From: Tomasz Figa @ 2013-10-12 2:26 UTC (permalink / raw)
To: dri-devel; +Cc: marcheu
Hi Sean,
On Thursday 10 of October 2013 20:30:13 Sean Paul wrote:
> This patchset refactors parts of the exynos driver to move it closer to a proper
> drm driver (rather than just implementing a drm layer on top of the hardware
> drivers). The hope is to get to a point where the dp/hdmi drivers can implement
> drm_connector/drm_encoder directly, and fimd/mixer can directly implement
> drm_crtc.
This looks like a really great series. I did not have time yet to do
a thorough review, but at first glance it looks fine. Let me try to
take a deeper look into this next week.
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 38+ messages in thread
* RE: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-12 2:06 ` Sean Paul
@ 2013-10-12 3:49 ` Inki Dae
2013-10-12 4:19 ` Sean Paul
0 siblings, 1 reply; 38+ messages in thread
From: Inki Dae @ 2013-10-12 3:49 UTC (permalink / raw)
To: 'Sean Paul'
Cc: 'Stéphane Marchesin', 'DRI mailing list'
> -----Original Message-----
> From: Sean Paul [mailto:seanpaul@chromium.org]
> Sent: Saturday, October 12, 2013 11:07 AM
> To: Inki Dae
> Cc: DRI mailing list; Stéphane Marchesin; Dave Airlie; Tomasz Figa
> Subject: Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
>
> On Fri, Oct 11, 2013 at 8:42 PM, Inki Dae <inki.dae@samsung.com> wrote:
> >> static int exynos_drm_create_enc_conn(struct drm_device *dev,
> >> - struct exynos_drm_subdrv
*subdrv)
> >> + struct exynos_drm_display
*display)
> >> {
> >> struct drm_encoder *encoder;
> >> struct drm_connector *connector;
> >> + struct exynos_drm_manager *manager;
> >> int ret;
> >> + unsigned long possible_crtcs = 0;
> >>
> >> - subdrv->manager->dev = subdrv->dev;
> >> + /* Find possible crtcs for this display */
> >> + list_for_each_entry(manager, &exynos_drm_manager_list, list)
> >> + if (manager->type == display->type)
> >> + possible_crtcs |= 1 << manager->pipe;
> >>
> >> /* create and initialize a encoder for this sub driver. */
> >> - encoder = exynos_drm_encoder_create(dev, subdrv->manager,
> >> - (1 << MAX_CRTC) - 1);
> >> + encoder = exynos_drm_encoder_create(dev, display,
> possible_crtcs);
> >> if (!encoder) {
> >> DRM_ERROR("failed to create encoder\n");
> >> return -EFAULT;
> >> }
> >> - subdrv->encoder = encoder;
> >> + display->encoder = encoder;
> >>
> >> - if (subdrv->manager->display_ops->type ==
> EXYNOS_DISPLAY_TYPE_LCD) {
> >> + if (display->type == EXYNOS_DISPLAY_TYPE_LCD) {
> >> ret = exynos_drm_attach_lcd_bridge(dev, encoder)
> >
> > Plz, _do_not_base_ on top of your lvds bridge patch set. As I
> > mentioned before, the tricky codes are not good. For this, let's find
> > a better way after your refactoring patch set are reviewed enough, and
> > if merged.
> >
>
> [+adding back the people you removed from CC]
>
Hm.. I didn't really remove the people from CC. See the your original
email. :)
> I'm happy to change how that works, but I've yet to find a better
> solution. Instead of just dismissing something as "tricky codes", can
> you suggest a concrete solution that is better than what I've got?
>
I think I mentioned already at previous email. First of all, let's have a
thorough review to your refactoring patch set, and then let's find a better
way.
I believe that we can find a better way with your refactoring patch set: now
we can implement encoder and connector directly.
> I'm also a bit confused as to why you think it's so tricky, it's a
First, That was your comment, "Right, so this is kind of tricky". And also
it seems like tricky codes to me.
> synchronous initialization call to a driver; that's about as simple as
> it gets.
As you mentioned before, ptn3460 driver is not depended on SoC, and can be
used for other SoC. Let you try to think about lcd class and backlight
class. I think we need a interfacing layer between common driver and
specific something for connecting SoC specific DRM framework.
>
> Sean
>
>
>
> >> if (ret)
> >> return 0;
> >> @@ -91,7 +98,7 @@ static int exynos_drm_create_enc_conn(struct
> drm_device *dev,
> >> goto err_destroy_encoder;
> >> }
> >>
> >> - subdrv->connector = connector;
> >> + display->connector = connector;
> >>
> >> return 0;
> >>
> >> @@ -100,21 +107,6 @@ err_destroy_encoder:
> >> return ret;
> >> }
> >>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-12 3:49 ` Inki Dae
@ 2013-10-12 4:19 ` Sean Paul
2013-10-12 4:30 ` Inki Dae
0 siblings, 1 reply; 38+ messages in thread
From: Sean Paul @ 2013-10-12 4:19 UTC (permalink / raw)
To: Inki Dae; +Cc: Stéphane Marchesin, DRI mailing list
On Fri, Oct 11, 2013 at 11:49 PM, Inki Dae <inki.dae@samsung.com> wrote:
>
>
>> -----Original Message-----
>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> Sent: Saturday, October 12, 2013 11:07 AM
>> To: Inki Dae
>> Cc: DRI mailing list; Stéphane Marchesin; Dave Airlie; Tomasz Figa
>> Subject: Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
>>
>> On Fri, Oct 11, 2013 at 8:42 PM, Inki Dae <inki.dae@samsung.com> wrote:
>> >> static int exynos_drm_create_enc_conn(struct drm_device *dev,
>> >> - struct exynos_drm_subdrv
> *subdrv)
>> >> + struct exynos_drm_display
> *display)
>> >> {
>> >> struct drm_encoder *encoder;
>> >> struct drm_connector *connector;
>> >> + struct exynos_drm_manager *manager;
>> >> int ret;
>> >> + unsigned long possible_crtcs = 0;
>> >>
>> >> - subdrv->manager->dev = subdrv->dev;
>> >> + /* Find possible crtcs for this display */
>> >> + list_for_each_entry(manager, &exynos_drm_manager_list, list)
>> >> + if (manager->type == display->type)
>> >> + possible_crtcs |= 1 << manager->pipe;
>> >>
>> >> /* create and initialize a encoder for this sub driver. */
>> >> - encoder = exynos_drm_encoder_create(dev, subdrv->manager,
>> >> - (1 << MAX_CRTC) - 1);
>> >> + encoder = exynos_drm_encoder_create(dev, display,
>> possible_crtcs);
>> >> if (!encoder) {
>> >> DRM_ERROR("failed to create encoder\n");
>> >> return -EFAULT;
>> >> }
>> >> - subdrv->encoder = encoder;
>> >> + display->encoder = encoder;
>> >>
>> >> - if (subdrv->manager->display_ops->type ==
>> EXYNOS_DISPLAY_TYPE_LCD) {
>> >> + if (display->type == EXYNOS_DISPLAY_TYPE_LCD) {
>> >> ret = exynos_drm_attach_lcd_bridge(dev, encoder)
>> >
>> > Plz, _do_not_base_ on top of your lvds bridge patch set. As I
>> > mentioned before, the tricky codes are not good. For this, let's find
>> > a better way after your refactoring patch set are reviewed enough, and
>> > if merged.
>> >
>>
>> [+adding back the people you removed from CC]
>>
>
> Hm.. I didn't really remove the people from CC. See the your original
> email. :)
>
>
>> I'm happy to change how that works, but I've yet to find a better
>> solution. Instead of just dismissing something as "tricky codes", can
>> you suggest a concrete solution that is better than what I've got?
>>
>
> I think I mentioned already at previous email. First of all, let's have a
> thorough review to your refactoring patch set, and then let's find a better
> way.
>
> I believe that we can find a better way with your refactoring patch set: now
> we can implement encoder and connector directly.
>
The code will look the exact same, it'll just be in the dp driver
instead of drm_core (since drm_core will not create
encoders/connectors). Adding the ptn driver in the interim allows me
to boot exynos5250-snow with linux-next, so I can test my changes.
>
>> I'm also a bit confused as to why you think it's so tricky, it's a
>
> First, That was your comment, "Right, so this is kind of tricky". And also
> it seems like tricky codes to me.
>
Right, it was a tricky problem (for reasons I've stated multiple
times), but the solution is dead easy to understand.
>> synchronous initialization call to a driver; that's about as simple as
>> it gets.
>
> As you mentioned before, ptn3460 driver is not depended on SoC, and can be
> used for other SoC. Let you try to think about lcd class and backlight
> class. I think we need a interfacing layer between common driver and
> specific something for connecting SoC specific DRM framework.
>
Laurent mentioned that he wanted to come up with a way to model
graphics hardware in dt. He could then build a notifier when the
various pieces were successfully probed, and drm would only load once
all of the pieces were ready.
I think that would be a nice long-term solution, however let's not let
the perfect be the enemy of the good. If you can simplify how this
works, I'm all for it. However, I don't see any other way at the
moment and I don't think it's productive to just wait around for
something better to come along.
Sean
>>
>> Sean
>>
>>
>>
>> >> if (ret)
>> >> return 0;
>> >> @@ -91,7 +98,7 @@ static int exynos_drm_create_enc_conn(struct
>> drm_device *dev,
>> >> goto err_destroy_encoder;
>> >> }
>> >>
>> >> - subdrv->connector = connector;
>> >> + display->connector = connector;
>> >>
>> >> return 0;
>> >>
>> >> @@ -100,21 +107,6 @@ err_destroy_encoder:
>> >> return ret;
>> >> }
>> >>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* RE: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-12 4:19 ` Sean Paul
@ 2013-10-12 4:30 ` Inki Dae
0 siblings, 0 replies; 38+ messages in thread
From: Inki Dae @ 2013-10-12 4:30 UTC (permalink / raw)
To: 'Sean Paul'
Cc: 'Stéphane Marchesin', 'DRI mailing list'
> -----Original Message-----
> From: Sean Paul [mailto:seanpaul@chromium.org]
> Sent: Saturday, October 12, 2013 1:20 PM
> To: Inki Dae
> Cc: DRI mailing list; Stéphane Marchesin; Dave Airlie; Tomasz Figa
> Subject: Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
>
> On Fri, Oct 11, 2013 at 11:49 PM, Inki Dae <inki.dae@samsung.com> wrote:
> >
> >
> >> -----Original Message-----
> >> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> Sent: Saturday, October 12, 2013 11:07 AM
> >> To: Inki Dae
> >> Cc: DRI mailing list; Stéphane Marchesin; Dave Airlie; Tomasz Figa
> >> Subject: Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
> >>
> >> On Fri, Oct 11, 2013 at 8:42 PM, Inki Dae <inki.dae@samsung.com> wrote:
> >> >> static int exynos_drm_create_enc_conn(struct drm_device *dev,
> >> >> - struct exynos_drm_subdrv
> > *subdrv)
> >> >> + struct exynos_drm_display
> > *display)
> >> >> {
> >> >> struct drm_encoder *encoder;
> >> >> struct drm_connector *connector;
> >> >> + struct exynos_drm_manager *manager;
> >> >> int ret;
> >> >> + unsigned long possible_crtcs = 0;
> >> >>
> >> >> - subdrv->manager->dev = subdrv->dev;
> >> >> + /* Find possible crtcs for this display */
> >> >> + list_for_each_entry(manager, &exynos_drm_manager_list, list)
> >> >> + if (manager->type == display->type)
> >> >> + possible_crtcs |= 1 << manager->pipe;
> >> >>
> >> >> /* create and initialize a encoder for this sub driver. */
> >> >> - encoder = exynos_drm_encoder_create(dev, subdrv->manager,
> >> >> - (1 << MAX_CRTC) - 1);
> >> >> + encoder = exynos_drm_encoder_create(dev, display,
> >> possible_crtcs);
> >> >> if (!encoder) {
> >> >> DRM_ERROR("failed to create encoder\n");
> >> >> return -EFAULT;
> >> >> }
> >> >> - subdrv->encoder = encoder;
> >> >> + display->encoder = encoder;
> >> >>
> >> >> - if (subdrv->manager->display_ops->type ==
> >> EXYNOS_DISPLAY_TYPE_LCD) {
> >> >> + if (display->type == EXYNOS_DISPLAY_TYPE_LCD) {
> >> >> ret = exynos_drm_attach_lcd_bridge(dev, encoder)
> >> >
> >> > Plz, _do_not_base_ on top of your lvds bridge patch set. As I
> >> > mentioned before, the tricky codes are not good. For this, let's find
> >> > a better way after your refactoring patch set are reviewed enough,
> and
> >> > if merged.
> >> >
> >>
> >> [+adding back the people you removed from CC]
> >>
> >
> > Hm.. I didn't really remove the people from CC. See the your original
> > email. :)
> >
> >
> >> I'm happy to change how that works, but I've yet to find a better
> >> solution. Instead of just dismissing something as "tricky codes", can
> >> you suggest a concrete solution that is better than what I've got?
> >>
> >
> > I think I mentioned already at previous email. First of all, let's have
> a
> > thorough review to your refactoring patch set, and then let's find a
> better
> > way.
> >
> > I believe that we can find a better way with your refactoring patch set:
> now
> > we can implement encoder and connector directly.
> >
>
> The code will look the exact same, it'll just be in the dp driver
> instead of drm_core (since drm_core will not create
> encoders/connectors). Adding the ptn driver in the interim allows me
> to boot exynos5250-snow with linux-next, so I can test my changes.
>
>
> >
> >> I'm also a bit confused as to why you think it's so tricky, it's a
> >
> > First, That was your comment, "Right, so this is kind of tricky". And
> also
> > it seems like tricky codes to me.
> >
>
> Right, it was a tricky problem (for reasons I've stated multiple
> times), but the solution is dead easy to understand.
>
>
> >> synchronous initialization call to a driver; that's about as simple as
> >> it gets.
> >
> > As you mentioned before, ptn3460 driver is not depended on SoC, and can
> be
> > used for other SoC. Let you try to think about lcd class and backlight
> > class. I think we need a interfacing layer between common driver and
> > specific something for connecting SoC specific DRM framework.
> >
>
> Laurent mentioned that he wanted to come up with a way to model
> graphics hardware in dt. He could then build a notifier when the
> various pieces were successfully probed, and drm would only load once
> all of the pieces were ready.
>
> I think that would be a nice long-term solution, however let's not let
> the perfect be the enemy of the good. If you can simplify how this
> works, I'm all for it. However, I don't see any other way at the
> moment and I don't think it's productive to just wait around for
> something better to come along.
>
Sean, let's have reviews to your refactoring patch set first. And then I
will merge your lvds bridge patch if we cannot find a better way. That would
not take much time.
> Sean
>
>
> >>
> >> Sean
> >>
> >>
> >>
> >> >> if (ret)
> >> >> return 0;
> >> >> @@ -91,7 +98,7 @@ static int exynos_drm_create_enc_conn(struct
> >> drm_device *dev,
> >> >> goto err_destroy_encoder;
> >> >> }
> >> >>
> >> >> - subdrv->connector = connector;
> >> >> + display->connector = connector;
> >> >>
> >> >> return 0;
> >> >>
> >> >> @@ -100,21 +107,6 @@ err_destroy_encoder:
> >> >> return ret;
> >> >> }
> >> >>
> >
^ permalink raw reply [flat|nested] 38+ messages in thread
* RE: [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev
2013-10-11 0:30 ` [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev Sean Paul
@ 2013-10-12 6:44 ` Inki Dae
2013-10-14 12:42 ` Inki Dae
1 sibling, 0 replies; 38+ messages in thread
From: Inki Dae @ 2013-10-12 6:44 UTC (permalink / raw)
To: 'Sean Paul', dri-devel; +Cc: marcheu
> void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void
> *data)
> @@ -495,7 +495,7 @@ void exynos_drm_encoder_plane_enable(struct
> drm_encoder *encoder, void *data)
> zpos = *(int *)data;
>
> if (manager_ops && manager_ops->win_enable)
> - manager_ops->win_enable(manager->dev, zpos);
> + manager_ops->win_enable(manager->ctx, zpos);
> }
>
> void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void
> *data)
> @@ -509,5 +509,5 @@ void exynos_drm_encoder_plane_disable(struct
> drm_encoder *encoder, void *data)
> zpos = *(int *)data;
>
> if (manager_ops && manager_ops->win_disable)
> - manager_ops->win_disable(manager->dev, zpos);
> + manager_ops->win_disable(manager->ctx, zpos);
> }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index 90fcd6f..9c2720a 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -106,6 +106,7 @@ struct fimd_win_data {
>
> struct fimd_context {
> struct exynos_drm_subdrv subdrv;
> + struct device *dev;
Where device object is set to ctx->dev? And we already have device object in
subdrv. And why did you add dev?
And you are making driver callbacks to be called with its own context. Why
framework should know the context of each driver? The framework knows the
device object of each device driver since the sub driver of each device
driver is registered to the framework. And the device driver can get its own
context from the device object driver-internally. The framework should call
some callbacks of each device driver _with_device_object_, and this way is
more generic.
The context is a_thing_only_for_the_device_driver.
> struct drm_device *drm_dev;
> int irq;
> struct drm_crtc *crtc;
> @@ -182,16 +183,15 @@ static struct exynos_drm_display_ops
> fimd_display_ops = {
> .power_on = fimd_display_power_on,
> };
>
> -static void fimd_win_mode_set(struct device *dev,
> - struct exynos_drm_overlay *overlay)
> +static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay
> *overlay)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> struct fimd_win_data *win_data;
> int win;
> unsigned long offset;
>
> if (!overlay) {
> - dev_err(dev, "overlay is NULL\n");
> + DRM_ERROR("overlay is NULL\n");
> return;
> }
>
> @@ -231,9 +231,8 @@ static void fimd_win_mode_set(struct device *dev,
> overlay->fb_width, overlay->crtc_width);
> }
>
> -static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
> +static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int
> win)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> struct fimd_win_data *win_data = &ctx->win_data[win];
> unsigned long val;
>
> @@ -289,9 +288,8 @@ static void fimd_win_set_pixfmt(struct device *dev,
> unsigned int win)
> writel(val, ctx->regs + WINCON(win));
> }
>
> -static void fimd_win_set_colkey(struct device *dev, unsigned int win)
> +static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int
> win)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> unsigned int keycon0 = 0, keycon1 = 0;
>
> keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
> @@ -330,9 +328,9 @@ static void fimd_shadow_protect_win(struct
> fimd_context *ctx,
> writel(val, ctx->regs + reg);
> }
>
> -static void fimd_win_commit(struct device *dev, int zpos)
> +static void fimd_win_commit(void *in_ctx, int zpos)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> struct fimd_win_data *win_data;
> int win = zpos;
> unsigned long val, alpha, size;
> @@ -427,11 +425,11 @@ static void fimd_win_commit(struct device *dev, int
> zpos)
> DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
> }
>
> - fimd_win_set_pixfmt(dev, win);
> + fimd_win_set_pixfmt(ctx, win);
>
> /* hardware window 0 doesn't support color key. */
> if (win != 0)
> - fimd_win_set_colkey(dev, win);
> + fimd_win_set_colkey(ctx, win);
>
> /* wincon */
> val = readl(ctx->regs + WINCON(win));
> @@ -450,9 +448,9 @@ static void fimd_win_commit(struct device *dev, int
> zpos)
> win_data->enabled = true;
> }
>
> -static void fimd_win_disable(struct device *dev, int zpos)
> +static void fimd_win_disable(void *in_ctx, int zpos)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> struct fimd_win_data *win_data;
> int win = zpos;
> u32 val;
> @@ -491,19 +489,18 @@ static void fimd_win_disable(struct device *dev, int
> zpos)
> win_data->enabled = false;
> }
>
> -static int fimd_mgr_initialize(struct device *subdrv_dev,
> - struct drm_device *drm_dev)
> +static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
> {
> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
> + struct fimd_context *ctx = in_ctx;
>
> ctx->drm_dev = drm_dev;
>
> return 0;
> }
>
> -static void fimd_dpms(struct device *subdrv_dev, int mode)
> +static void fimd_dpms(void *in_ctx, int mode)
> {
> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
> + struct fimd_context *ctx = in_ctx;
>
> DRM_DEBUG_KMS("%d\n", mode);
>
> @@ -518,13 +515,13 @@ static void fimd_dpms(struct device *subdrv_dev, int
> mode)
> * clk_enable could be called double time.
> */
> if (ctx->suspended)
> - pm_runtime_get_sync(subdrv_dev);
> + pm_runtime_get_sync(ctx->dev);
Maybe invalid memory access to ctx->dev. So Shoulnd't it ctx->subdrv.dev?
> break;
> case DRM_MODE_DPMS_STANDBY:
> case DRM_MODE_DPMS_SUSPEND:
> case DRM_MODE_DPMS_OFF:
> if (!ctx->suspended)
> - pm_runtime_put_sync(subdrv_dev);
> + pm_runtime_put_sync(ctx->dev);
Ditto
> break;
> default:
> DRM_DEBUG_KMS("unspecified mode %d\n", mode);
> @@ -534,9 +531,9 @@ static void fimd_dpms(struct device *subdrv_dev, int
> mode)
> mutex_unlock(&ctx->lock);
> }
>
> -static void fimd_apply(struct device *subdrv_dev)
> +static void fimd_apply(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
> + struct fimd_context *ctx = in_ctx;
> struct exynos_drm_manager *mgr = ctx->subdrv.manager;
> struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
> struct fimd_win_data *win_data;
> @@ -545,16 +542,16 @@ static void fimd_apply(struct device *subdrv_dev)
> for (i = 0; i < WINDOWS_NR; i++) {
> win_data = &ctx->win_data[i];
> if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
> - mgr_ops->win_commit(subdrv_dev, i);
> + mgr_ops->win_commit(ctx, i);
> }
>
> if (mgr_ops && mgr_ops->commit)
> - mgr_ops->commit(subdrv_dev);
> + mgr_ops->commit(ctx);
> }
>
> -static void fimd_commit(struct device *dev)
> +static void fimd_commit(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> struct exynos_drm_panel_info *panel = &ctx->panel;
> struct videomode *vm = &panel->vm;
> struct fimd_driver_data *driver_data;
> @@ -608,9 +605,9 @@ static void fimd_commit(struct device *dev)
> writel(val, ctx->regs + VIDCON0);
> }
>
> -static int fimd_enable_vblank(struct device *dev)
> +static int fimd_enable_vblank(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> u32 val;
>
> if (ctx->suspended)
> @@ -633,9 +630,9 @@ static int fimd_enable_vblank(struct device *dev)
> return 0;
> }
>
> -static void fimd_disable_vblank(struct device *dev)
> +static void fimd_disable_vblank(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> u32 val;
>
> if (ctx->suspended)
> @@ -651,9 +648,9 @@ static void fimd_disable_vblank(struct device *dev)
> }
> }
>
> -static void fimd_wait_for_vblank(struct device *dev)
> +static void fimd_wait_for_vblank(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
>
> if (ctx->suspended)
> return;
> @@ -845,9 +842,9 @@ static void fimd_window_suspend(struct device *dev)
> for (i = 0; i < WINDOWS_NR; i++) {
> win_data = &ctx->win_data[i];
> win_data->resume = win_data->enabled;
> - fimd_win_disable(dev, i);
> + fimd_win_disable(ctx, i);
> }
> - fimd_wait_for_vblank(dev);
> + fimd_wait_for_vblank(ctx);
> }
>
> static void fimd_window_resume(struct device *dev)
> @@ -963,6 +960,8 @@ static int fimd_probe(struct platform_device *pdev)
> DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
> atomic_set(&ctx->wait_vsync_event, 0);
>
> + fimd_manager.ctx = ctx;
> +
> subdrv = &ctx->subdrv;
>
> subdrv->dev = dev;
> @@ -1042,7 +1041,7 @@ static int fimd_resume(struct device *dev)
> * registers but in case of sleep wakeup, it's not.
> * so fimd_apply function should be called at here.
> */
> - fimd_apply(dev);
> + fimd_apply(ctx);
> }
>
> return 0;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> index aebcc0e..cddb0c8 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> @@ -129,11 +129,9 @@ static struct edid *drm_hdmi_get_edid(struct device
> *dev,
>
> return NULL;
> }
> -
> -static int drm_hdmi_check_mode(struct device *dev,
> +static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
> struct drm_display_mode *mode)
> {
> - struct drm_hdmi_context *ctx = to_context(dev);
> int ret = 0;
>
> /*
> @@ -153,6 +151,14 @@ static int drm_hdmi_check_mode(struct device *dev,
> return 0;
> }
>
> +static int drm_hdmi_check_mode(struct device *dev,
> + struct drm_display_mode *mode)
> +{
> + struct drm_hdmi_context *ctx = to_context(dev);
> +
> + return drm_hdmi_check_mode_ctx(ctx, mode);
> +}
> +
> static int drm_hdmi_power_on(struct device *dev, int mode)
> {
> struct drm_hdmi_context *ctx = to_context(dev);
> @@ -172,9 +178,9 @@ static struct exynos_drm_display_ops
> drm_hdmi_display_ops = {
> .power_on = drm_hdmi_power_on,
> };
>
> -static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
> +static int drm_hdmi_enable_vblank(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
> struct exynos_drm_manager *manager = subdrv->manager;
>
> @@ -185,33 +191,33 @@ static int drm_hdmi_enable_vblank(struct device
> *subdrv_dev)
> return 0;
> }
>
> -static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
> +static void drm_hdmi_disable_vblank(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_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 device *subdrv_dev)
> +static void drm_hdmi_wait_for_vblank(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + 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_mode_fixup(struct device *subdrv_dev,
> - struct drm_connector *connector,
> +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(subdrv_dev, adjusted_mode);
> + mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode);
>
> /* just return if user desired mode exists. */
> if (mode_ok == 0)
> @@ -222,7 +228,7 @@ static void drm_hdmi_mode_fixup(struct device
> *subdrv_dev,
> * to adjusted_mode.
> */
> list_for_each_entry(m, &connector->modes, head) {
> - mode_ok = drm_hdmi_check_mode(subdrv_dev, m);
> + mode_ok = drm_hdmi_check_mode_ctx(ctx, m);
>
> if (mode_ok == 0) {
> struct drm_mode_object base;
> @@ -245,35 +251,34 @@ static void drm_hdmi_mode_fixup(struct device
> *subdrv_dev,
> }
> }
>
> -static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
> +static void drm_hdmi_mode_set(void *in_ctx, void *mode)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_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 device *subdrv_dev,
> - unsigned int *width, unsigned int *height)
> +static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
> + unsigned int *height)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
>
> if (hdmi_ops && hdmi_ops->get_max_resol)
> hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
> }
>
> -static void drm_hdmi_commit(struct device *subdrv_dev)
> +static void drm_hdmi_commit(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + 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(struct device *subdrv_dev,
> - struct drm_device *drm_dev)
> +static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device
> *drm_dev)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> int ret = 0;
>
> if (mixer_ops && mixer_ops->initialize)
> @@ -285,9 +290,9 @@ static int drm_hdmi_mgr_initialize(struct device
> *subdrv_dev,
> return ret;
> }
>
> -static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
> +static void drm_hdmi_dpms(void *in_ctx, int mode)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
>
> if (mixer_ops && mixer_ops->dpms)
> mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
> @@ -296,9 +301,9 @@ static void drm_hdmi_dpms(struct device *subdrv_dev,
> int mode)
> hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
> }
>
> -static void drm_hdmi_apply(struct device *subdrv_dev)
> +static void drm_hdmi_apply(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> int i;
>
> for (i = 0; i < MIXER_WIN_NR; i++) {
> @@ -312,18 +317,18 @@ static void drm_hdmi_apply(struct device
*subdrv_dev)
> hdmi_ops->commit(ctx->hdmi_ctx->ctx);
> }
>
> -static void drm_mixer_win_mode_set(struct device *subdrv_dev,
> - struct exynos_drm_overlay *overlay)
> +static void drm_mixer_win_mode_set(void *in_ctx,
> + struct exynos_drm_overlay *overlay)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + 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(struct device *subdrv_dev, int zpos)
> +static void drm_mixer_win_commit(void *in_ctx, int zpos)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
>
> if (win < 0 || win >= MIXER_WIN_NR) {
> @@ -337,9 +342,9 @@ static void drm_mixer_win_commit(struct device
> *subdrv_dev, int zpos)
> ctx->enabled[win] = true;
> }
>
> -static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
> +static void drm_mixer_win_disable(void *in_ctx, int zpos)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
>
> if (win < 0 || win >= MIXER_WIN_NR) {
> @@ -425,6 +430,8 @@ static int exynos_drm_hdmi_probe(struct
> platform_device *pdev)
> if (!ctx)
> return -ENOMEM;
>
> + hdmi_manager.ctx = ctx;
> +
> subdrv = &ctx->subdrv;
>
> subdrv->dev = dev;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> index 15a97ce..a583a74 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> @@ -152,9 +152,9 @@ static struct exynos_drm_display_ops vidi_display_ops
> = {
> .power_on = vidi_display_power_on,
> };
>
> -static void vidi_dpms(struct device *subdrv_dev, int mode)
> +static void vidi_dpms(void *in_ctx, int mode)
> {
> - struct vidi_context *ctx = get_vidi_context(subdrv_dev);
> + struct vidi_context *ctx = in_ctx;
>
> DRM_DEBUG_KMS("%d\n", mode);
>
> @@ -177,9 +177,9 @@ static void vidi_dpms(struct device *subdrv_dev, int
> mode)
> mutex_unlock(&ctx->lock);
> }
>
> -static void vidi_apply(struct device *subdrv_dev)
> +static void vidi_apply(void *in_ctx)
> {
> - struct vidi_context *ctx = get_vidi_context(subdrv_dev);
> + struct vidi_context *ctx = in_ctx;
> struct exynos_drm_manager *mgr = ctx->subdrv.manager;
> struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
> struct vidi_win_data *win_data;
> @@ -188,24 +188,24 @@ static void vidi_apply(struct device *subdrv_dev)
> for (i = 0; i < WINDOWS_NR; i++) {
> win_data = &ctx->win_data[i];
> if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
> - mgr_ops->win_commit(subdrv_dev, i);
> + mgr_ops->win_commit(ctx, i);
> }
>
> if (mgr_ops && mgr_ops->commit)
> - mgr_ops->commit(subdrv_dev);
> + mgr_ops->commit(ctx);
> }
>
> -static void vidi_commit(struct device *dev)
> +static void vidi_commit(void *in_ctx)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
>
> if (ctx->suspended)
> return;
> }
>
> -static int vidi_enable_vblank(struct device *dev)
> +static int vidi_enable_vblank(void *in_ctx)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
>
> if (ctx->suspended)
> return -EPERM;
> @@ -225,9 +225,9 @@ static int vidi_enable_vblank(struct device *dev)
> return 0;
> }
>
> -static void vidi_disable_vblank(struct device *dev)
> +static void vidi_disable_vblank(void *in_ctx)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
>
> if (ctx->suspended)
> return;
> @@ -236,16 +236,15 @@ static void vidi_disable_vblank(struct device *dev)
> ctx->vblank_on = false;
> }
>
> -static void vidi_win_mode_set(struct device *dev,
> - struct exynos_drm_overlay *overlay)
> +static void vidi_win_mode_set(void *in_ctx, struct exynos_drm_overlay
> *overlay)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
> struct vidi_win_data *win_data;
> int win;
> unsigned long offset;
>
> if (!overlay) {
> - dev_err(dev, "overlay is NULL\n");
> + DRM_ERROR("overlay is NULL\n");
> return;
> }
>
> @@ -289,9 +288,9 @@ static void vidi_win_mode_set(struct device *dev,
> overlay->fb_width, overlay->crtc_width);
> }
>
> -static void vidi_win_commit(struct device *dev, int zpos)
> +static void vidi_win_commit(void *in_ctx, int zpos)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
> struct vidi_win_data *win_data;
> int win = zpos;
>
> @@ -314,9 +313,9 @@ static void vidi_win_commit(struct device *dev, int
> zpos)
> schedule_work(&ctx->work);
> }
>
> -static void vidi_win_disable(struct device *dev, int zpos)
> +static void vidi_win_disable(void *in_ctx, int zpos)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
> struct vidi_win_data *win_data;
> int win = zpos;
>
> @@ -405,17 +404,19 @@ static void vidi_subdrv_remove(struct drm_device
> *drm_dev, struct device *dev)
>
> static int vidi_power_on(struct vidi_context *ctx, bool enable)
> {
> - struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
> - struct device *dev = subdrv->dev;
> + DRM_DEBUG_KMS("%s\n", __FILE__);
> +
> + if (enable != false && enable != true)
> + return -EINVAL;
>
> if (enable) {
> ctx->suspended = false;
>
> /* if vblank was enabled status, enable it again. */
> if (test_and_clear_bit(0, &ctx->irq_flags))
> - vidi_enable_vblank(dev);
> + vidi_enable_vblank(ctx);
>
> - vidi_apply(dev);
> + vidi_apply(ctx);
> } else {
> ctx->suspended = true;
> }
> --
> 1.8.4
^ permalink raw reply [flat|nested] 38+ messages in thread
* RE: [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev
2013-10-11 0:30 ` [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev Sean Paul
2013-10-12 6:44 ` Inki Dae
@ 2013-10-14 12:42 ` Inki Dae
2013-10-14 14:18 ` Sean Paul
1 sibling, 1 reply; 38+ messages in thread
From: Inki Dae @ 2013-10-14 12:42 UTC (permalink / raw)
To: 'Sean Paul', dri-devel; +Cc: marcheu
Hi, Sean.
It's a great patch set.:) That's exactly what we want. So I'd like to merge
all patch set to exynos-drm-next if there is no design issue about next
week. And then we can add additional minor patches from others.
Before that, can you re-send all patch set like below?
1. Do not rebase them at top of lvds-bridge patch set.
2. Change all patch set for callbacks to be called
_with_device_object instead of ctx.
The below is my comments.
Thanks for your contributions,
Inki Dae
> -----Original Message-----
> From: Sean Paul [mailto:seanpaul@chromium.org]
> Sent: Friday, October 11, 2013 9:30 AM
> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org; Sean
> Paul
> Subject: [PATCH 06/23] drm/exynos: Pass context in manager ops instead of
> dev
>
> This patch changes the manager ops callbacks from accepting the subdrv
> device pointer to taking a context pointer. This will allow us to move
> closer to decoupling manager/display from subdrv, and subsequently
> decoupling the crtc/plane from the encoder.
>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
> drivers/gpu/drm/exynos/exynos_drm_connector.c | 2 +-
> drivers/gpu/drm/exynos/exynos_drm_drv.h | 33 ++++++------
> drivers/gpu/drm/exynos/exynos_drm_encoder.c | 24 ++++-----
> drivers/gpu/drm/exynos/exynos_drm_fimd.c | 71
+++++++++++++----------
> --
> drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 75
+++++++++++++++--------
> ----
> drivers/gpu/drm/exynos/exynos_drm_vidi.c | 49 ++++++++---------
> 6 files changed, 130 insertions(+), 124 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c
> b/drivers/gpu/drm/exynos/exynos_drm_connector.c
> index e082efb..b70b123 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
> @@ -198,7 +198,7 @@ static int exynos_drm_connector_fill_modes(struct
> drm_connector *connector,
> * resolution then get max width and height from that driver.
> */
> if (ops && ops->get_max_resol)
> - ops->get_max_resol(manager->dev, &width, &height);
> + ops->get_max_resol(manager->ctx, &width, &height);
>
> return drm_helper_probe_single_connector_modes(connector, width,
> height);
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h
> b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> index 09bfe60..0bd444f 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> @@ -162,26 +162,23 @@ struct exynos_drm_display_ops {
> * @win_disable: disable hardware specific overlay.
> */
> struct exynos_drm_manager_ops {
> - int (*initialize)(struct device *subdrv_dev,
> - struct drm_device *drm_dev);
> - void (*dpms)(struct device *subdrv_dev, int mode);
> - void (*apply)(struct device *subdrv_dev);
> - void (*mode_fixup)(struct device *subdrv_dev,
> - struct drm_connector *connector,
> + int (*initialize)(void *ctx, struct drm_device *drm_dev);
> + void (*dpms)(void *ctx, int mode);
> + void (*apply)(void *ctx);
> + void (*mode_fixup)(void *ctx, struct drm_connector *connector,
> const struct drm_display_mode *mode,
> struct drm_display_mode *adjusted_mode);
> - void (*mode_set)(struct device *subdrv_dev, void *mode);
> - void (*get_max_resol)(struct device *subdrv_dev, unsigned int
> *width,
> + void (*mode_set)(void *ctx, void *mode);
> + void (*get_max_resol)(void *ctx, unsigned int *width,
> unsigned int *height);
> - void (*commit)(struct device *subdrv_dev);
> - int (*enable_vblank)(struct device *subdrv_dev);
> - void (*disable_vblank)(struct device *subdrv_dev);
> - void (*wait_for_vblank)(struct device *subdrv_dev);
> - void (*win_mode_set)(struct device *subdrv_dev,
> - struct exynos_drm_overlay *overlay);
> - void (*win_commit)(struct device *subdrv_dev, int zpos);
> - void (*win_enable)(struct device *subdrv_dev, int zpos);
> - void (*win_disable)(struct device *subdrv_dev, int zpos);
> + void (*commit)(void *ctx);
> + int (*enable_vblank)(void *ctx);
> + void (*disable_vblank)(void *ctx);
> + void (*wait_for_vblank)(void *ctx);
> + void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
> + void (*win_commit)(void *ctx, int zpos);
> + void (*win_enable)(void *ctx, int zpos);
> + void (*win_disable)(void *ctx, int zpos);
> };
>
> /*
> @@ -197,12 +194,14 @@ struct exynos_drm_manager_ops {
> * these callbacks should be set by specific drivers such fimd
> * or hdmi driver and are used to control display devices such as
> * analog tv, digital tv and lcd panel and also get timing data for
> them.
> + * @ctx: A pointer to the manager's implementation specific context
> */
> struct exynos_drm_manager {
> struct device *dev;
> int pipe;
> struct exynos_drm_manager_ops *ops;
> struct exynos_drm_display_ops *display_ops;
> + void *ctx;
Plz, remove ctx we can use dev instead.
> };
>
> struct exynos_drm_g2d_private {
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> index a9eb2b0..24484ae 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> @@ -74,7 +74,7 @@ static void exynos_drm_encoder_dpms(struct drm_encoder
> *encoder, int mode)
> case DRM_MODE_DPMS_ON:
> if (manager_ops && manager_ops->apply)
> if (!exynos_encoder->updated)
> - manager_ops->apply(manager->dev);
> + manager_ops->apply(manager->ctx);
>
> exynos_drm_connector_power(encoder, mode);
> exynos_encoder->dpms = mode;
> @@ -107,7 +107,7 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder
> *encoder,
> list_for_each_entry(connector, &dev->mode_config.connector_list,
> head) {
> if (connector->encoder == encoder)
> if (manager_ops && manager_ops->mode_fixup)
> - manager_ops->mode_fixup(manager->dev,
connector,
> + manager_ops->mode_fixup(manager->ctx,
connector,
> mode,
adjusted_mode);
> }
>
> @@ -175,7 +175,7 @@ static void exynos_drm_encoder_mode_set(struct
> drm_encoder *encoder,
> manager_ops = manager->ops;
>
> if (manager_ops && manager_ops->mode_set)
> - manager_ops->mode_set(manager->dev,
> + manager_ops->mode_set(manager->ctx,
> adjusted_mode);
>
> exynos_encoder->old_crtc = encoder->crtc;
> @@ -195,7 +195,7 @@ static void exynos_drm_encoder_commit(struct
> drm_encoder *encoder)
> struct exynos_drm_manager_ops *manager_ops = manager->ops;
>
> if (manager_ops && manager_ops->commit)
> - manager_ops->commit(manager->dev);
> + manager_ops->commit(manager->ctx);
>
> /*
> * this will avoid one issue that overlay data is updated to
> @@ -341,7 +341,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
> drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
>
> if (manager->ops && manager->ops->initialize) {
> - ret = manager->ops->initialize(manager->dev, dev);
> + ret = manager->ops->initialize(manager->ctx, dev);
> if (ret) {
> DRM_ERROR("Manager initialize failed %d\n", ret);
> goto error;
> @@ -408,7 +408,7 @@ void exynos_drm_enable_vblank(struct drm_encoder
> *encoder, void *data)
> return;
>
> if (manager_ops->enable_vblank)
> - manager_ops->enable_vblank(manager->dev);
> + manager_ops->enable_vblank(manager->ctx);
> }
>
> void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
> @@ -422,7 +422,7 @@ void exynos_drm_disable_vblank(struct drm_encoder
> *encoder, void *data)
> return;
>
> if (manager_ops->disable_vblank)
> - manager_ops->disable_vblank(manager->dev);
> + manager_ops->disable_vblank(manager->ctx);
> }
>
> void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void
*data)
> @@ -433,7 +433,7 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder
> *encoder, void *data)
> int mode = *(int *)data;
>
> if (manager_ops && manager_ops->dpms)
> - manager_ops->dpms(manager->dev, mode);
> + manager_ops->dpms(manager->ctx, mode);
>
> /*
> * if this condition is ok then it means that the crtc is already
> @@ -467,7 +467,7 @@ void exynos_drm_encoder_plane_mode_set(struct
> drm_encoder *encoder, void *data)
> struct exynos_drm_overlay *overlay = data;
>
> if (manager_ops && manager_ops->win_mode_set)
> - manager_ops->win_mode_set(manager->dev, overlay);
> + manager_ops->win_mode_set(manager->ctx, overlay);
> }
>
> void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void
> *data)
> @@ -481,7 +481,7 @@ void exynos_drm_encoder_plane_commit(struct
> drm_encoder *encoder, void *data)
> zpos = *(int *)data;
>
> if (manager_ops && manager_ops->win_commit)
> - manager_ops->win_commit(manager->dev, zpos);
> + manager_ops->win_commit(manager->ctx, zpos);
> }
>
> void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void
> *data)
> @@ -495,7 +495,7 @@ void exynos_drm_encoder_plane_enable(struct
> drm_encoder *encoder, void *data)
> zpos = *(int *)data;
>
> if (manager_ops && manager_ops->win_enable)
> - manager_ops->win_enable(manager->dev, zpos);
> + manager_ops->win_enable(manager->ctx, zpos);
> }
>
> void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void
> *data)
> @@ -509,5 +509,5 @@ void exynos_drm_encoder_plane_disable(struct
> drm_encoder *encoder, void *data)
> zpos = *(int *)data;
>
> if (manager_ops && manager_ops->win_disable)
> - manager_ops->win_disable(manager->dev, zpos);
> + manager_ops->win_disable(manager->ctx, zpos);
> }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index 90fcd6f..9c2720a 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -106,6 +106,7 @@ struct fimd_win_data {
>
> struct fimd_context {
> struct exynos_drm_subdrv subdrv;
It seems that crtc device drivers such as fimd and hdmi mixer don't need to
register subdrv. So remove?
> + struct device *dev;
> struct drm_device *drm_dev;
> int irq;
> struct drm_crtc *crtc;
> @@ -182,16 +183,15 @@ static struct exynos_drm_display_ops
> fimd_display_ops = {
> .power_on = fimd_display_power_on,
> };
>
> -static void fimd_win_mode_set(struct device *dev,
> - struct exynos_drm_overlay *overlay)
> +static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay
> *overlay)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> struct fimd_win_data *win_data;
> int win;
> unsigned long offset;
>
> if (!overlay) {
> - dev_err(dev, "overlay is NULL\n");
> + DRM_ERROR("overlay is NULL\n");
> return;
> }
>
> @@ -231,9 +231,8 @@ static void fimd_win_mode_set(struct device *dev,
> overlay->fb_width, overlay->crtc_width);
> }
>
> -static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
> +static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int
> win)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> struct fimd_win_data *win_data = &ctx->win_data[win];
> unsigned long val;
>
> @@ -289,9 +288,8 @@ static void fimd_win_set_pixfmt(struct device *dev,
> unsigned int win)
> writel(val, ctx->regs + WINCON(win));
> }
>
> -static void fimd_win_set_colkey(struct device *dev, unsigned int win)
> +static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int
> win)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> unsigned int keycon0 = 0, keycon1 = 0;
>
> keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
> @@ -330,9 +328,9 @@ static void fimd_shadow_protect_win(struct
> fimd_context *ctx,
> writel(val, ctx->regs + reg);
> }
>
> -static void fimd_win_commit(struct device *dev, int zpos)
> +static void fimd_win_commit(void *in_ctx, int zpos)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> struct fimd_win_data *win_data;
> int win = zpos;
> unsigned long val, alpha, size;
> @@ -427,11 +425,11 @@ static void fimd_win_commit(struct device *dev, int
> zpos)
> DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
> }
>
> - fimd_win_set_pixfmt(dev, win);
> + fimd_win_set_pixfmt(ctx, win);
>
> /* hardware window 0 doesn't support color key. */
> if (win != 0)
> - fimd_win_set_colkey(dev, win);
> + fimd_win_set_colkey(ctx, win);
>
> /* wincon */
> val = readl(ctx->regs + WINCON(win));
> @@ -450,9 +448,9 @@ static void fimd_win_commit(struct device *dev, int
> zpos)
> win_data->enabled = true;
> }
>
> -static void fimd_win_disable(struct device *dev, int zpos)
> +static void fimd_win_disable(void *in_ctx, int zpos)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> struct fimd_win_data *win_data;
> int win = zpos;
> u32 val;
> @@ -491,19 +489,18 @@ static void fimd_win_disable(struct device *dev, int
> zpos)
> win_data->enabled = false;
> }
>
> -static int fimd_mgr_initialize(struct device *subdrv_dev,
> - struct drm_device *drm_dev)
> +static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
> {
> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
> + struct fimd_context *ctx = in_ctx;
>
> ctx->drm_dev = drm_dev;
>
> return 0;
> }
>
> -static void fimd_dpms(struct device *subdrv_dev, int mode)
> +static void fimd_dpms(void *in_ctx, int mode)
> {
> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
> + struct fimd_context *ctx = in_ctx;
>
> DRM_DEBUG_KMS("%d\n", mode);
>
> @@ -518,13 +515,13 @@ static void fimd_dpms(struct device *subdrv_dev, int
> mode)
> * clk_enable could be called double time.
> */
> if (ctx->suspended)
> - pm_runtime_get_sync(subdrv_dev);
> + pm_runtime_get_sync(ctx->dev);
> break;
> case DRM_MODE_DPMS_STANDBY:
> case DRM_MODE_DPMS_SUSPEND:
> case DRM_MODE_DPMS_OFF:
> if (!ctx->suspended)
> - pm_runtime_put_sync(subdrv_dev);
> + pm_runtime_put_sync(ctx->dev);
> break;
> default:
> DRM_DEBUG_KMS("unspecified mode %d\n", mode);
> @@ -534,9 +531,9 @@ static void fimd_dpms(struct device *subdrv_dev, int
> mode)
> mutex_unlock(&ctx->lock);
> }
>
> -static void fimd_apply(struct device *subdrv_dev)
> +static void fimd_apply(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
> + struct fimd_context *ctx = in_ctx;
> struct exynos_drm_manager *mgr = ctx->subdrv.manager;
> struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
> struct fimd_win_data *win_data;
> @@ -545,16 +542,16 @@ static void fimd_apply(struct device *subdrv_dev)
> for (i = 0; i < WINDOWS_NR; i++) {
> win_data = &ctx->win_data[i];
> if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
> - mgr_ops->win_commit(subdrv_dev, i);
> + mgr_ops->win_commit(ctx, i);
> }
>
> if (mgr_ops && mgr_ops->commit)
> - mgr_ops->commit(subdrv_dev);
> + mgr_ops->commit(ctx);
> }
>
> -static void fimd_commit(struct device *dev)
> +static void fimd_commit(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> struct exynos_drm_panel_info *panel = &ctx->panel;
> struct videomode *vm = &panel->vm;
> struct fimd_driver_data *driver_data;
> @@ -608,9 +605,9 @@ static void fimd_commit(struct device *dev)
> writel(val, ctx->regs + VIDCON0);
> }
>
> -static int fimd_enable_vblank(struct device *dev)
> +static int fimd_enable_vblank(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> u32 val;
>
> if (ctx->suspended)
> @@ -633,9 +630,9 @@ static int fimd_enable_vblank(struct device *dev)
> return 0;
> }
>
> -static void fimd_disable_vblank(struct device *dev)
> +static void fimd_disable_vblank(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
> u32 val;
>
> if (ctx->suspended)
> @@ -651,9 +648,9 @@ static void fimd_disable_vblank(struct device *dev)
> }
> }
>
> -static void fimd_wait_for_vblank(struct device *dev)
> +static void fimd_wait_for_vblank(void *in_ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> + struct fimd_context *ctx = in_ctx;
>
> if (ctx->suspended)
> return;
> @@ -845,9 +842,9 @@ static void fimd_window_suspend(struct device *dev)
> for (i = 0; i < WINDOWS_NR; i++) {
> win_data = &ctx->win_data[i];
> win_data->resume = win_data->enabled;
> - fimd_win_disable(dev, i);
> + fimd_win_disable(ctx, i);
> }
> - fimd_wait_for_vblank(dev);
> + fimd_wait_for_vblank(ctx);
> }
>
> static void fimd_window_resume(struct device *dev)
> @@ -963,6 +960,8 @@ static int fimd_probe(struct platform_device *pdev)
> DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
> atomic_set(&ctx->wait_vsync_event, 0);
>
> + fimd_manager.ctx = ctx;
> +
> subdrv = &ctx->subdrv;
>
> subdrv->dev = dev;
> @@ -1042,7 +1041,7 @@ static int fimd_resume(struct device *dev)
> * registers but in case of sleep wakeup, it's not.
> * so fimd_apply function should be called at here.
> */
> - fimd_apply(dev);
> + fimd_apply(ctx);
> }
>
> return 0;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> index aebcc0e..cddb0c8 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> @@ -129,11 +129,9 @@ static struct edid *drm_hdmi_get_edid(struct device
> *dev,
>
> return NULL;
> }
> -
> -static int drm_hdmi_check_mode(struct device *dev,
> +static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
> struct drm_display_mode *mode)
> {
> - struct drm_hdmi_context *ctx = to_context(dev);
> int ret = 0;
>
> /*
> @@ -153,6 +151,14 @@ static int drm_hdmi_check_mode(struct device *dev,
> return 0;
> }
>
> +static int drm_hdmi_check_mode(struct device *dev,
> + struct drm_display_mode *mode)
> +{
> + struct drm_hdmi_context *ctx = to_context(dev);
> +
> + return drm_hdmi_check_mode_ctx(ctx, mode);
> +}
> +
> static int drm_hdmi_power_on(struct device *dev, int mode)
> {
> struct drm_hdmi_context *ctx = to_context(dev);
> @@ -172,9 +178,9 @@ static struct exynos_drm_display_ops
> drm_hdmi_display_ops = {
> .power_on = drm_hdmi_power_on,
> };
>
> -static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
> +static int drm_hdmi_enable_vblank(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
> struct exynos_drm_manager *manager = subdrv->manager;
>
> @@ -185,33 +191,33 @@ static int drm_hdmi_enable_vblank(struct device
> *subdrv_dev)
> return 0;
> }
>
> -static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
> +static void drm_hdmi_disable_vblank(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_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 device *subdrv_dev)
> +static void drm_hdmi_wait_for_vblank(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + 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_mode_fixup(struct device *subdrv_dev,
> - struct drm_connector *connector,
> +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(subdrv_dev, adjusted_mode);
> + mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode);
>
> /* just return if user desired mode exists. */
> if (mode_ok == 0)
> @@ -222,7 +228,7 @@ static void drm_hdmi_mode_fixup(struct device
> *subdrv_dev,
> * to adjusted_mode.
> */
> list_for_each_entry(m, &connector->modes, head) {
> - mode_ok = drm_hdmi_check_mode(subdrv_dev, m);
> + mode_ok = drm_hdmi_check_mode_ctx(ctx, m);
>
> if (mode_ok == 0) {
> struct drm_mode_object base;
> @@ -245,35 +251,34 @@ static void drm_hdmi_mode_fixup(struct device
> *subdrv_dev,
> }
> }
>
> -static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
> +static void drm_hdmi_mode_set(void *in_ctx, void *mode)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_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 device *subdrv_dev,
> - unsigned int *width, unsigned int *height)
> +static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
> + unsigned int *height)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
>
> if (hdmi_ops && hdmi_ops->get_max_resol)
> hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
> }
>
> -static void drm_hdmi_commit(struct device *subdrv_dev)
> +static void drm_hdmi_commit(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + 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(struct device *subdrv_dev,
> - struct drm_device *drm_dev)
> +static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device
> *drm_dev)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> int ret = 0;
>
> if (mixer_ops && mixer_ops->initialize)
> @@ -285,9 +290,9 @@ static int drm_hdmi_mgr_initialize(struct device
> *subdrv_dev,
> return ret;
> }
>
> -static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
> +static void drm_hdmi_dpms(void *in_ctx, int mode)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
>
> if (mixer_ops && mixer_ops->dpms)
> mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
> @@ -296,9 +301,9 @@ static void drm_hdmi_dpms(struct device *subdrv_dev,
> int mode)
> hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
> }
>
> -static void drm_hdmi_apply(struct device *subdrv_dev)
> +static void drm_hdmi_apply(void *in_ctx)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> int i;
>
> for (i = 0; i < MIXER_WIN_NR; i++) {
> @@ -312,18 +317,18 @@ static void drm_hdmi_apply(struct device
*subdrv_dev)
> hdmi_ops->commit(ctx->hdmi_ctx->ctx);
> }
>
> -static void drm_mixer_win_mode_set(struct device *subdrv_dev,
> - struct exynos_drm_overlay *overlay)
> +static void drm_mixer_win_mode_set(void *in_ctx,
> + struct exynos_drm_overlay *overlay)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + 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(struct device *subdrv_dev, int zpos)
> +static void drm_mixer_win_commit(void *in_ctx, int zpos)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
>
> if (win < 0 || win >= MIXER_WIN_NR) {
> @@ -337,9 +342,9 @@ static void drm_mixer_win_commit(struct device
> *subdrv_dev, int zpos)
> ctx->enabled[win] = true;
> }
>
> -static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
> +static void drm_mixer_win_disable(void *in_ctx, int zpos)
> {
> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
> + struct drm_hdmi_context *ctx = in_ctx;
> int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
>
> if (win < 0 || win >= MIXER_WIN_NR) {
> @@ -425,6 +430,8 @@ static int exynos_drm_hdmi_probe(struct
> platform_device *pdev)
> if (!ctx)
> return -ENOMEM;
>
> + hdmi_manager.ctx = ctx;
> +
> subdrv = &ctx->subdrv;
>
> subdrv->dev = dev;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> index 15a97ce..a583a74 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> @@ -152,9 +152,9 @@ static struct exynos_drm_display_ops vidi_display_ops
> = {
> .power_on = vidi_display_power_on,
> };
>
> -static void vidi_dpms(struct device *subdrv_dev, int mode)
> +static void vidi_dpms(void *in_ctx, int mode)
> {
> - struct vidi_context *ctx = get_vidi_context(subdrv_dev);
> + struct vidi_context *ctx = in_ctx;
>
> DRM_DEBUG_KMS("%d\n", mode);
>
> @@ -177,9 +177,9 @@ static void vidi_dpms(struct device *subdrv_dev, int
> mode)
> mutex_unlock(&ctx->lock);
> }
>
> -static void vidi_apply(struct device *subdrv_dev)
> +static void vidi_apply(void *in_ctx)
> {
> - struct vidi_context *ctx = get_vidi_context(subdrv_dev);
> + struct vidi_context *ctx = in_ctx;
> struct exynos_drm_manager *mgr = ctx->subdrv.manager;
> struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
> struct vidi_win_data *win_data;
> @@ -188,24 +188,24 @@ static void vidi_apply(struct device *subdrv_dev)
> for (i = 0; i < WINDOWS_NR; i++) {
> win_data = &ctx->win_data[i];
> if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
> - mgr_ops->win_commit(subdrv_dev, i);
> + mgr_ops->win_commit(ctx, i);
> }
>
> if (mgr_ops && mgr_ops->commit)
> - mgr_ops->commit(subdrv_dev);
> + mgr_ops->commit(ctx);
> }
>
> -static void vidi_commit(struct device *dev)
> +static void vidi_commit(void *in_ctx)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
>
> if (ctx->suspended)
> return;
> }
>
> -static int vidi_enable_vblank(struct device *dev)
> +static int vidi_enable_vblank(void *in_ctx)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
>
> if (ctx->suspended)
> return -EPERM;
> @@ -225,9 +225,9 @@ static int vidi_enable_vblank(struct device *dev)
> return 0;
> }
>
> -static void vidi_disable_vblank(struct device *dev)
> +static void vidi_disable_vblank(void *in_ctx)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
>
> if (ctx->suspended)
> return;
> @@ -236,16 +236,15 @@ static void vidi_disable_vblank(struct device *dev)
> ctx->vblank_on = false;
> }
>
> -static void vidi_win_mode_set(struct device *dev,
> - struct exynos_drm_overlay *overlay)
> +static void vidi_win_mode_set(void *in_ctx, struct exynos_drm_overlay
> *overlay)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
> struct vidi_win_data *win_data;
> int win;
> unsigned long offset;
>
> if (!overlay) {
> - dev_err(dev, "overlay is NULL\n");
> + DRM_ERROR("overlay is NULL\n");
> return;
> }
>
> @@ -289,9 +288,9 @@ static void vidi_win_mode_set(struct device *dev,
> overlay->fb_width, overlay->crtc_width);
> }
>
> -static void vidi_win_commit(struct device *dev, int zpos)
> +static void vidi_win_commit(void *in_ctx, int zpos)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
> struct vidi_win_data *win_data;
> int win = zpos;
>
> @@ -314,9 +313,9 @@ static void vidi_win_commit(struct device *dev, int
> zpos)
> schedule_work(&ctx->work);
> }
>
> -static void vidi_win_disable(struct device *dev, int zpos)
> +static void vidi_win_disable(void *in_ctx, int zpos)
> {
> - struct vidi_context *ctx = get_vidi_context(dev);
> + struct vidi_context *ctx = in_ctx;
> struct vidi_win_data *win_data;
> int win = zpos;
>
> @@ -405,17 +404,19 @@ static void vidi_subdrv_remove(struct drm_device
> *drm_dev, struct device *dev)
>
> static int vidi_power_on(struct vidi_context *ctx, bool enable)
> {
> - struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
> - struct device *dev = subdrv->dev;
> + DRM_DEBUG_KMS("%s\n", __FILE__);
> +
> + if (enable != false && enable != true)
> + return -EINVAL;
>
> if (enable) {
> ctx->suspended = false;
>
> /* if vblank was enabled status, enable it again. */
> if (test_and_clear_bit(0, &ctx->irq_flags))
> - vidi_enable_vblank(dev);
> + vidi_enable_vblank(ctx);
>
> - vidi_apply(dev);
> + vidi_apply(ctx);
> } else {
> ctx->suspended = true;
> }
> --
> 1.8.4
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev
2013-10-14 12:42 ` Inki Dae
@ 2013-10-14 14:18 ` Sean Paul
2013-10-14 15:07 ` Inki Dae
0 siblings, 1 reply; 38+ messages in thread
From: Sean Paul @ 2013-10-14 14:18 UTC (permalink / raw)
To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel
On Mon, Oct 14, 2013 at 8:42 AM, Inki Dae <inki.dae@samsung.com> wrote:
> Hi, Sean.
>
>
> It's a great patch set.:) That's exactly what we want. So I'd like to merge
> all patch set to exynos-drm-next if there is no design issue about next
> week. And then we can add additional minor patches from others.
>
> Before that, can you re-send all patch set like below?
> 1. Do not rebase them at top of lvds-bridge patch set.
> 2. Change all patch set for callbacks to be called
> _with_device_object instead of ctx.
>
> The below is my comments.
>
> Thanks for your contributions,
> Inki Dae
>
>> -----Original Message-----
>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> Sent: Friday, October 11, 2013 9:30 AM
>> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org; Sean
>> Paul
>> Subject: [PATCH 06/23] drm/exynos: Pass context in manager ops instead of
>> dev
>>
>> This patch changes the manager ops callbacks from accepting the subdrv
>> device pointer to taking a context pointer. This will allow us to move
>> closer to decoupling manager/display from subdrv, and subsequently
>> decoupling the crtc/plane from the encoder.
>>
>> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>> ---
>> drivers/gpu/drm/exynos/exynos_drm_connector.c | 2 +-
>> drivers/gpu/drm/exynos/exynos_drm_drv.h | 33 ++++++------
>> drivers/gpu/drm/exynos/exynos_drm_encoder.c | 24 ++++-----
>> drivers/gpu/drm/exynos/exynos_drm_fimd.c | 71
> +++++++++++++----------
>> --
>> drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 75
> +++++++++++++++--------
>> ----
>> drivers/gpu/drm/exynos/exynos_drm_vidi.c | 49 ++++++++---------
>> 6 files changed, 130 insertions(+), 124 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c
>> b/drivers/gpu/drm/exynos/exynos_drm_connector.c
>> index e082efb..b70b123 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
>> @@ -198,7 +198,7 @@ static int exynos_drm_connector_fill_modes(struct
>> drm_connector *connector,
>> * resolution then get max width and height from that driver.
>> */
>> if (ops && ops->get_max_resol)
>> - ops->get_max_resol(manager->dev, &width, &height);
>> + ops->get_max_resol(manager->ctx, &width, &height);
>>
>> return drm_helper_probe_single_connector_modes(connector, width,
>> height);
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h
>> b/drivers/gpu/drm/exynos/exynos_drm_drv.h
>> index 09bfe60..0bd444f 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
>> @@ -162,26 +162,23 @@ struct exynos_drm_display_ops {
>> * @win_disable: disable hardware specific overlay.
>> */
>> struct exynos_drm_manager_ops {
>> - int (*initialize)(struct device *subdrv_dev,
>> - struct drm_device *drm_dev);
>> - void (*dpms)(struct device *subdrv_dev, int mode);
>> - void (*apply)(struct device *subdrv_dev);
>> - void (*mode_fixup)(struct device *subdrv_dev,
>> - struct drm_connector *connector,
>> + int (*initialize)(void *ctx, struct drm_device *drm_dev);
>> + void (*dpms)(void *ctx, int mode);
>> + void (*apply)(void *ctx);
>> + void (*mode_fixup)(void *ctx, struct drm_connector *connector,
>> const struct drm_display_mode *mode,
>> struct drm_display_mode *adjusted_mode);
>> - void (*mode_set)(struct device *subdrv_dev, void *mode);
>> - void (*get_max_resol)(struct device *subdrv_dev, unsigned int
>> *width,
>> + void (*mode_set)(void *ctx, void *mode);
>> + void (*get_max_resol)(void *ctx, unsigned int *width,
>> unsigned int *height);
>> - void (*commit)(struct device *subdrv_dev);
>> - int (*enable_vblank)(struct device *subdrv_dev);
>> - void (*disable_vblank)(struct device *subdrv_dev);
>> - void (*wait_for_vblank)(struct device *subdrv_dev);
>> - void (*win_mode_set)(struct device *subdrv_dev,
>> - struct exynos_drm_overlay *overlay);
>> - void (*win_commit)(struct device *subdrv_dev, int zpos);
>> - void (*win_enable)(struct device *subdrv_dev, int zpos);
>> - void (*win_disable)(struct device *subdrv_dev, int zpos);
>> + void (*commit)(void *ctx);
>> + int (*enable_vblank)(void *ctx);
>> + void (*disable_vblank)(void *ctx);
>> + void (*wait_for_vblank)(void *ctx);
>> + void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
>> + void (*win_commit)(void *ctx, int zpos);
>> + void (*win_enable)(void *ctx, int zpos);
>> + void (*win_disable)(void *ctx, int zpos);
>> };
>>
>> /*
>> @@ -197,12 +194,14 @@ struct exynos_drm_manager_ops {
>> * these callbacks should be set by specific drivers such fimd
>> * or hdmi driver and are used to control display devices such as
>> * analog tv, digital tv and lcd panel and also get timing data for
>> them.
>> + * @ctx: A pointer to the manager's implementation specific context
>> */
>> struct exynos_drm_manager {
>> struct device *dev;
>> int pipe;
>> struct exynos_drm_manager_ops *ops;
>> struct exynos_drm_display_ops *display_ops;
>> + void *ctx;
>
> Plz, remove ctx we can use dev instead.
>
I'd rather not use dev, tbh. I think a good solution would be to pass
exynos_drm_manager && exynos_drm_display through the exynos hooks
instead. This will give us type checking in the compiler, as well as
keeping the ctx pointers out of the abstraction layer. Sound good?
>> };
>>
>> struct exynos_drm_g2d_private {
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> index a9eb2b0..24484ae 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> @@ -74,7 +74,7 @@ static void exynos_drm_encoder_dpms(struct drm_encoder
>> *encoder, int mode)
>> case DRM_MODE_DPMS_ON:
>> if (manager_ops && manager_ops->apply)
>> if (!exynos_encoder->updated)
>> - manager_ops->apply(manager->dev);
>> + manager_ops->apply(manager->ctx);
>>
>> exynos_drm_connector_power(encoder, mode);
>> exynos_encoder->dpms = mode;
>> @@ -107,7 +107,7 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder
>> *encoder,
>> list_for_each_entry(connector, &dev->mode_config.connector_list,
>> head) {
>> if (connector->encoder == encoder)
>> if (manager_ops && manager_ops->mode_fixup)
>> - manager_ops->mode_fixup(manager->dev,
> connector,
>> + manager_ops->mode_fixup(manager->ctx,
> connector,
>> mode,
> adjusted_mode);
>> }
>>
>> @@ -175,7 +175,7 @@ static void exynos_drm_encoder_mode_set(struct
>> drm_encoder *encoder,
>> manager_ops = manager->ops;
>>
>> if (manager_ops && manager_ops->mode_set)
>> - manager_ops->mode_set(manager->dev,
>> + manager_ops->mode_set(manager->ctx,
>> adjusted_mode);
>>
>> exynos_encoder->old_crtc = encoder->crtc;
>> @@ -195,7 +195,7 @@ static void exynos_drm_encoder_commit(struct
>> drm_encoder *encoder)
>> struct exynos_drm_manager_ops *manager_ops = manager->ops;
>>
>> if (manager_ops && manager_ops->commit)
>> - manager_ops->commit(manager->dev);
>> + manager_ops->commit(manager->ctx);
>>
>> /*
>> * this will avoid one issue that overlay data is updated to
>> @@ -341,7 +341,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
>> drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
>>
>> if (manager->ops && manager->ops->initialize) {
>> - ret = manager->ops->initialize(manager->dev, dev);
>> + ret = manager->ops->initialize(manager->ctx, dev);
>> if (ret) {
>> DRM_ERROR("Manager initialize failed %d\n", ret);
>> goto error;
>> @@ -408,7 +408,7 @@ void exynos_drm_enable_vblank(struct drm_encoder
>> *encoder, void *data)
>> return;
>>
>> if (manager_ops->enable_vblank)
>> - manager_ops->enable_vblank(manager->dev);
>> + manager_ops->enable_vblank(manager->ctx);
>> }
>>
>> void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
>> @@ -422,7 +422,7 @@ void exynos_drm_disable_vblank(struct drm_encoder
>> *encoder, void *data)
>> return;
>>
>> if (manager_ops->disable_vblank)
>> - manager_ops->disable_vblank(manager->dev);
>> + manager_ops->disable_vblank(manager->ctx);
>> }
>>
>> void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void
> *data)
>> @@ -433,7 +433,7 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder
>> *encoder, void *data)
>> int mode = *(int *)data;
>>
>> if (manager_ops && manager_ops->dpms)
>> - manager_ops->dpms(manager->dev, mode);
>> + manager_ops->dpms(manager->ctx, mode);
>>
>> /*
>> * if this condition is ok then it means that the crtc is already
>> @@ -467,7 +467,7 @@ void exynos_drm_encoder_plane_mode_set(struct
>> drm_encoder *encoder, void *data)
>> struct exynos_drm_overlay *overlay = data;
>>
>> if (manager_ops && manager_ops->win_mode_set)
>> - manager_ops->win_mode_set(manager->dev, overlay);
>> + manager_ops->win_mode_set(manager->ctx, overlay);
>> }
>>
>> void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void
>> *data)
>> @@ -481,7 +481,7 @@ void exynos_drm_encoder_plane_commit(struct
>> drm_encoder *encoder, void *data)
>> zpos = *(int *)data;
>>
>> if (manager_ops && manager_ops->win_commit)
>> - manager_ops->win_commit(manager->dev, zpos);
>> + manager_ops->win_commit(manager->ctx, zpos);
>> }
>>
>> void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void
>> *data)
>> @@ -495,7 +495,7 @@ void exynos_drm_encoder_plane_enable(struct
>> drm_encoder *encoder, void *data)
>> zpos = *(int *)data;
>>
>> if (manager_ops && manager_ops->win_enable)
>> - manager_ops->win_enable(manager->dev, zpos);
>> + manager_ops->win_enable(manager->ctx, zpos);
>> }
>>
>> void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void
>> *data)
>> @@ -509,5 +509,5 @@ void exynos_drm_encoder_plane_disable(struct
>> drm_encoder *encoder, void *data)
>> zpos = *(int *)data;
>>
>> if (manager_ops && manager_ops->win_disable)
>> - manager_ops->win_disable(manager->dev, zpos);
>> + manager_ops->win_disable(manager->ctx, zpos);
>> }
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> index 90fcd6f..9c2720a 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> @@ -106,6 +106,7 @@ struct fimd_win_data {
>>
>> struct fimd_context {
>> struct exynos_drm_subdrv subdrv;
>
> It seems that crtc device drivers such as fimd and hdmi mixer don't need to
> register subdrv. So remove?
>
Yeah, good catch, this is no longer needed.
>> + struct device *dev;
>> struct drm_device *drm_dev;
>> int irq;
>> struct drm_crtc *crtc;
>> @@ -182,16 +183,15 @@ static struct exynos_drm_display_ops
>> fimd_display_ops = {
>> .power_on = fimd_display_power_on,
>> };
>>
>> -static void fimd_win_mode_set(struct device *dev,
>> - struct exynos_drm_overlay *overlay)
>> +static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay
>> *overlay)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> + struct fimd_context *ctx = in_ctx;
>> struct fimd_win_data *win_data;
>> int win;
>> unsigned long offset;
>>
>> if (!overlay) {
>> - dev_err(dev, "overlay is NULL\n");
>> + DRM_ERROR("overlay is NULL\n");
>> return;
>> }
>>
>> @@ -231,9 +231,8 @@ static void fimd_win_mode_set(struct device *dev,
>> overlay->fb_width, overlay->crtc_width);
>> }
>>
>> -static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
>> +static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int
>> win)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> struct fimd_win_data *win_data = &ctx->win_data[win];
>> unsigned long val;
>>
>> @@ -289,9 +288,8 @@ static void fimd_win_set_pixfmt(struct device *dev,
>> unsigned int win)
>> writel(val, ctx->regs + WINCON(win));
>> }
>>
>> -static void fimd_win_set_colkey(struct device *dev, unsigned int win)
>> +static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int
>> win)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> unsigned int keycon0 = 0, keycon1 = 0;
>>
>> keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
>> @@ -330,9 +328,9 @@ static void fimd_shadow_protect_win(struct
>> fimd_context *ctx,
>> writel(val, ctx->regs + reg);
>> }
>>
>> -static void fimd_win_commit(struct device *dev, int zpos)
>> +static void fimd_win_commit(void *in_ctx, int zpos)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> + struct fimd_context *ctx = in_ctx;
>> struct fimd_win_data *win_data;
>> int win = zpos;
>> unsigned long val, alpha, size;
>> @@ -427,11 +425,11 @@ static void fimd_win_commit(struct device *dev, int
>> zpos)
>> DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
>> }
>>
>> - fimd_win_set_pixfmt(dev, win);
>> + fimd_win_set_pixfmt(ctx, win);
>>
>> /* hardware window 0 doesn't support color key. */
>> if (win != 0)
>> - fimd_win_set_colkey(dev, win);
>> + fimd_win_set_colkey(ctx, win);
>>
>> /* wincon */
>> val = readl(ctx->regs + WINCON(win));
>> @@ -450,9 +448,9 @@ static void fimd_win_commit(struct device *dev, int
>> zpos)
>> win_data->enabled = true;
>> }
>>
>> -static void fimd_win_disable(struct device *dev, int zpos)
>> +static void fimd_win_disable(void *in_ctx, int zpos)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> + struct fimd_context *ctx = in_ctx;
>> struct fimd_win_data *win_data;
>> int win = zpos;
>> u32 val;
>> @@ -491,19 +489,18 @@ static void fimd_win_disable(struct device *dev, int
>> zpos)
>> win_data->enabled = false;
>> }
>>
>> -static int fimd_mgr_initialize(struct device *subdrv_dev,
>> - struct drm_device *drm_dev)
>> +static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
>> {
>> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
>> + struct fimd_context *ctx = in_ctx;
>>
>> ctx->drm_dev = drm_dev;
>>
>> return 0;
>> }
>>
>> -static void fimd_dpms(struct device *subdrv_dev, int mode)
>> +static void fimd_dpms(void *in_ctx, int mode)
>> {
>> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
>> + struct fimd_context *ctx = in_ctx;
>>
>> DRM_DEBUG_KMS("%d\n", mode);
>>
>> @@ -518,13 +515,13 @@ static void fimd_dpms(struct device *subdrv_dev, int
>> mode)
>> * clk_enable could be called double time.
>> */
>> if (ctx->suspended)
>> - pm_runtime_get_sync(subdrv_dev);
>> + pm_runtime_get_sync(ctx->dev);
>> break;
>> case DRM_MODE_DPMS_STANDBY:
>> case DRM_MODE_DPMS_SUSPEND:
>> case DRM_MODE_DPMS_OFF:
>> if (!ctx->suspended)
>> - pm_runtime_put_sync(subdrv_dev);
>> + pm_runtime_put_sync(ctx->dev);
>> break;
>> default:
>> DRM_DEBUG_KMS("unspecified mode %d\n", mode);
>> @@ -534,9 +531,9 @@ static void fimd_dpms(struct device *subdrv_dev, int
>> mode)
>> mutex_unlock(&ctx->lock);
>> }
>>
>> -static void fimd_apply(struct device *subdrv_dev)
>> +static void fimd_apply(void *in_ctx)
>> {
>> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
>> + struct fimd_context *ctx = in_ctx;
>> struct exynos_drm_manager *mgr = ctx->subdrv.manager;
>> struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
>> struct fimd_win_data *win_data;
>> @@ -545,16 +542,16 @@ static void fimd_apply(struct device *subdrv_dev)
>> for (i = 0; i < WINDOWS_NR; i++) {
>> win_data = &ctx->win_data[i];
>> if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
>> - mgr_ops->win_commit(subdrv_dev, i);
>> + mgr_ops->win_commit(ctx, i);
>> }
>>
>> if (mgr_ops && mgr_ops->commit)
>> - mgr_ops->commit(subdrv_dev);
>> + mgr_ops->commit(ctx);
>> }
>>
>> -static void fimd_commit(struct device *dev)
>> +static void fimd_commit(void *in_ctx)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> + struct fimd_context *ctx = in_ctx;
>> struct exynos_drm_panel_info *panel = &ctx->panel;
>> struct videomode *vm = &panel->vm;
>> struct fimd_driver_data *driver_data;
>> @@ -608,9 +605,9 @@ static void fimd_commit(struct device *dev)
>> writel(val, ctx->regs + VIDCON0);
>> }
>>
>> -static int fimd_enable_vblank(struct device *dev)
>> +static int fimd_enable_vblank(void *in_ctx)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> + struct fimd_context *ctx = in_ctx;
>> u32 val;
>>
>> if (ctx->suspended)
>> @@ -633,9 +630,9 @@ static int fimd_enable_vblank(struct device *dev)
>> return 0;
>> }
>>
>> -static void fimd_disable_vblank(struct device *dev)
>> +static void fimd_disable_vblank(void *in_ctx)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> + struct fimd_context *ctx = in_ctx;
>> u32 val;
>>
>> if (ctx->suspended)
>> @@ -651,9 +648,9 @@ static void fimd_disable_vblank(struct device *dev)
>> }
>> }
>>
>> -static void fimd_wait_for_vblank(struct device *dev)
>> +static void fimd_wait_for_vblank(void *in_ctx)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> + struct fimd_context *ctx = in_ctx;
>>
>> if (ctx->suspended)
>> return;
>> @@ -845,9 +842,9 @@ static void fimd_window_suspend(struct device *dev)
>> for (i = 0; i < WINDOWS_NR; i++) {
>> win_data = &ctx->win_data[i];
>> win_data->resume = win_data->enabled;
>> - fimd_win_disable(dev, i);
>> + fimd_win_disable(ctx, i);
>> }
>> - fimd_wait_for_vblank(dev);
>> + fimd_wait_for_vblank(ctx);
>> }
>>
>> static void fimd_window_resume(struct device *dev)
>> @@ -963,6 +960,8 @@ static int fimd_probe(struct platform_device *pdev)
>> DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
>> atomic_set(&ctx->wait_vsync_event, 0);
>>
>> + fimd_manager.ctx = ctx;
>> +
>> subdrv = &ctx->subdrv;
>>
>> subdrv->dev = dev;
>> @@ -1042,7 +1041,7 @@ static int fimd_resume(struct device *dev)
>> * registers but in case of sleep wakeup, it's not.
>> * so fimd_apply function should be called at here.
>> */
>> - fimd_apply(dev);
>> + fimd_apply(ctx);
>> }
>>
>> return 0;
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>> b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>> index aebcc0e..cddb0c8 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>> @@ -129,11 +129,9 @@ static struct edid *drm_hdmi_get_edid(struct device
>> *dev,
>>
>> return NULL;
>> }
>> -
>> -static int drm_hdmi_check_mode(struct device *dev,
>> +static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
>> struct drm_display_mode *mode)
>> {
>> - struct drm_hdmi_context *ctx = to_context(dev);
>> int ret = 0;
>>
>> /*
>> @@ -153,6 +151,14 @@ static int drm_hdmi_check_mode(struct device *dev,
>> return 0;
>> }
>>
>> +static int drm_hdmi_check_mode(struct device *dev,
>> + struct drm_display_mode *mode)
>> +{
>> + struct drm_hdmi_context *ctx = to_context(dev);
>> +
>> + return drm_hdmi_check_mode_ctx(ctx, mode);
>> +}
>> +
>> static int drm_hdmi_power_on(struct device *dev, int mode)
>> {
>> struct drm_hdmi_context *ctx = to_context(dev);
>> @@ -172,9 +178,9 @@ static struct exynos_drm_display_ops
>> drm_hdmi_display_ops = {
>> .power_on = drm_hdmi_power_on,
>> };
>>
>> -static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
>> +static int drm_hdmi_enable_vblank(void *in_ctx)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + struct drm_hdmi_context *ctx = in_ctx;
>> struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
>> struct exynos_drm_manager *manager = subdrv->manager;
>>
>> @@ -185,33 +191,33 @@ static int drm_hdmi_enable_vblank(struct device
>> *subdrv_dev)
>> return 0;
>> }
>>
>> -static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
>> +static void drm_hdmi_disable_vblank(void *in_ctx)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + struct drm_hdmi_context *ctx = in_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 device *subdrv_dev)
>> +static void drm_hdmi_wait_for_vblank(void *in_ctx)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + 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_mode_fixup(struct device *subdrv_dev,
>> - struct drm_connector *connector,
>> +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(subdrv_dev, adjusted_mode);
>> + mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode);
>>
>> /* just return if user desired mode exists. */
>> if (mode_ok == 0)
>> @@ -222,7 +228,7 @@ static void drm_hdmi_mode_fixup(struct device
>> *subdrv_dev,
>> * to adjusted_mode.
>> */
>> list_for_each_entry(m, &connector->modes, head) {
>> - mode_ok = drm_hdmi_check_mode(subdrv_dev, m);
>> + mode_ok = drm_hdmi_check_mode_ctx(ctx, m);
>>
>> if (mode_ok == 0) {
>> struct drm_mode_object base;
>> @@ -245,35 +251,34 @@ static void drm_hdmi_mode_fixup(struct device
>> *subdrv_dev,
>> }
>> }
>>
>> -static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
>> +static void drm_hdmi_mode_set(void *in_ctx, void *mode)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + struct drm_hdmi_context *ctx = in_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 device *subdrv_dev,
>> - unsigned int *width, unsigned int *height)
>> +static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
>> + unsigned int *height)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + struct drm_hdmi_context *ctx = in_ctx;
>>
>> if (hdmi_ops && hdmi_ops->get_max_resol)
>> hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
>> }
>>
>> -static void drm_hdmi_commit(struct device *subdrv_dev)
>> +static void drm_hdmi_commit(void *in_ctx)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + 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(struct device *subdrv_dev,
>> - struct drm_device *drm_dev)
>> +static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device
>> *drm_dev)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + struct drm_hdmi_context *ctx = in_ctx;
>> int ret = 0;
>>
>> if (mixer_ops && mixer_ops->initialize)
>> @@ -285,9 +290,9 @@ static int drm_hdmi_mgr_initialize(struct device
>> *subdrv_dev,
>> return ret;
>> }
>>
>> -static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
>> +static void drm_hdmi_dpms(void *in_ctx, int mode)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + struct drm_hdmi_context *ctx = in_ctx;
>>
>> if (mixer_ops && mixer_ops->dpms)
>> mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
>> @@ -296,9 +301,9 @@ static void drm_hdmi_dpms(struct device *subdrv_dev,
>> int mode)
>> hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
>> }
>>
>> -static void drm_hdmi_apply(struct device *subdrv_dev)
>> +static void drm_hdmi_apply(void *in_ctx)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + struct drm_hdmi_context *ctx = in_ctx;
>> int i;
>>
>> for (i = 0; i < MIXER_WIN_NR; i++) {
>> @@ -312,18 +317,18 @@ static void drm_hdmi_apply(struct device
> *subdrv_dev)
>> hdmi_ops->commit(ctx->hdmi_ctx->ctx);
>> }
>>
>> -static void drm_mixer_win_mode_set(struct device *subdrv_dev,
>> - struct exynos_drm_overlay *overlay)
>> +static void drm_mixer_win_mode_set(void *in_ctx,
>> + struct exynos_drm_overlay *overlay)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + 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(struct device *subdrv_dev, int zpos)
>> +static void drm_mixer_win_commit(void *in_ctx, int zpos)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + struct drm_hdmi_context *ctx = in_ctx;
>> int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
>>
>> if (win < 0 || win >= MIXER_WIN_NR) {
>> @@ -337,9 +342,9 @@ static void drm_mixer_win_commit(struct device
>> *subdrv_dev, int zpos)
>> ctx->enabled[win] = true;
>> }
>>
>> -static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
>> +static void drm_mixer_win_disable(void *in_ctx, int zpos)
>> {
>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>> + struct drm_hdmi_context *ctx = in_ctx;
>> int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
>>
>> if (win < 0 || win >= MIXER_WIN_NR) {
>> @@ -425,6 +430,8 @@ static int exynos_drm_hdmi_probe(struct
>> platform_device *pdev)
>> if (!ctx)
>> return -ENOMEM;
>>
>> + hdmi_manager.ctx = ctx;
>> +
>> subdrv = &ctx->subdrv;
>>
>> subdrv->dev = dev;
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
>> b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
>> index 15a97ce..a583a74 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
>> @@ -152,9 +152,9 @@ static struct exynos_drm_display_ops vidi_display_ops
>> = {
>> .power_on = vidi_display_power_on,
>> };
>>
>> -static void vidi_dpms(struct device *subdrv_dev, int mode)
>> +static void vidi_dpms(void *in_ctx, int mode)
>> {
>> - struct vidi_context *ctx = get_vidi_context(subdrv_dev);
>> + struct vidi_context *ctx = in_ctx;
>>
>> DRM_DEBUG_KMS("%d\n", mode);
>>
>> @@ -177,9 +177,9 @@ static void vidi_dpms(struct device *subdrv_dev, int
>> mode)
>> mutex_unlock(&ctx->lock);
>> }
>>
>> -static void vidi_apply(struct device *subdrv_dev)
>> +static void vidi_apply(void *in_ctx)
>> {
>> - struct vidi_context *ctx = get_vidi_context(subdrv_dev);
>> + struct vidi_context *ctx = in_ctx;
>> struct exynos_drm_manager *mgr = ctx->subdrv.manager;
>> struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
>> struct vidi_win_data *win_data;
>> @@ -188,24 +188,24 @@ static void vidi_apply(struct device *subdrv_dev)
>> for (i = 0; i < WINDOWS_NR; i++) {
>> win_data = &ctx->win_data[i];
>> if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
>> - mgr_ops->win_commit(subdrv_dev, i);
>> + mgr_ops->win_commit(ctx, i);
>> }
>>
>> if (mgr_ops && mgr_ops->commit)
>> - mgr_ops->commit(subdrv_dev);
>> + mgr_ops->commit(ctx);
>> }
>>
>> -static void vidi_commit(struct device *dev)
>> +static void vidi_commit(void *in_ctx)
>> {
>> - struct vidi_context *ctx = get_vidi_context(dev);
>> + struct vidi_context *ctx = in_ctx;
>>
>> if (ctx->suspended)
>> return;
>> }
>>
>> -static int vidi_enable_vblank(struct device *dev)
>> +static int vidi_enable_vblank(void *in_ctx)
>> {
>> - struct vidi_context *ctx = get_vidi_context(dev);
>> + struct vidi_context *ctx = in_ctx;
>>
>> if (ctx->suspended)
>> return -EPERM;
>> @@ -225,9 +225,9 @@ static int vidi_enable_vblank(struct device *dev)
>> return 0;
>> }
>>
>> -static void vidi_disable_vblank(struct device *dev)
>> +static void vidi_disable_vblank(void *in_ctx)
>> {
>> - struct vidi_context *ctx = get_vidi_context(dev);
>> + struct vidi_context *ctx = in_ctx;
>>
>> if (ctx->suspended)
>> return;
>> @@ -236,16 +236,15 @@ static void vidi_disable_vblank(struct device *dev)
>> ctx->vblank_on = false;
>> }
>>
>> -static void vidi_win_mode_set(struct device *dev,
>> - struct exynos_drm_overlay *overlay)
>> +static void vidi_win_mode_set(void *in_ctx, struct exynos_drm_overlay
>> *overlay)
>> {
>> - struct vidi_context *ctx = get_vidi_context(dev);
>> + struct vidi_context *ctx = in_ctx;
>> struct vidi_win_data *win_data;
>> int win;
>> unsigned long offset;
>>
>> if (!overlay) {
>> - dev_err(dev, "overlay is NULL\n");
>> + DRM_ERROR("overlay is NULL\n");
>> return;
>> }
>>
>> @@ -289,9 +288,9 @@ static void vidi_win_mode_set(struct device *dev,
>> overlay->fb_width, overlay->crtc_width);
>> }
>>
>> -static void vidi_win_commit(struct device *dev, int zpos)
>> +static void vidi_win_commit(void *in_ctx, int zpos)
>> {
>> - struct vidi_context *ctx = get_vidi_context(dev);
>> + struct vidi_context *ctx = in_ctx;
>> struct vidi_win_data *win_data;
>> int win = zpos;
>>
>> @@ -314,9 +313,9 @@ static void vidi_win_commit(struct device *dev, int
>> zpos)
>> schedule_work(&ctx->work);
>> }
>>
>> -static void vidi_win_disable(struct device *dev, int zpos)
>> +static void vidi_win_disable(void *in_ctx, int zpos)
>> {
>> - struct vidi_context *ctx = get_vidi_context(dev);
>> + struct vidi_context *ctx = in_ctx;
>> struct vidi_win_data *win_data;
>> int win = zpos;
>>
>> @@ -405,17 +404,19 @@ static void vidi_subdrv_remove(struct drm_device
>> *drm_dev, struct device *dev)
>>
>> static int vidi_power_on(struct vidi_context *ctx, bool enable)
>> {
>> - struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
>> - struct device *dev = subdrv->dev;
>> + DRM_DEBUG_KMS("%s\n", __FILE__);
>> +
>> + if (enable != false && enable != true)
>> + return -EINVAL;
>>
>> if (enable) {
>> ctx->suspended = false;
>>
>> /* if vblank was enabled status, enable it again. */
>> if (test_and_clear_bit(0, &ctx->irq_flags))
>> - vidi_enable_vblank(dev);
>> + vidi_enable_vblank(ctx);
>>
>> - vidi_apply(dev);
>> + vidi_apply(ctx);
>> } else {
>> ctx->suspended = true;
>> }
>> --
>> 1.8.4
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev
2013-10-14 14:18 ` Sean Paul
@ 2013-10-14 15:07 ` Inki Dae
0 siblings, 0 replies; 38+ messages in thread
From: Inki Dae @ 2013-10-14 15:07 UTC (permalink / raw)
To: Sean Paul; +Cc: Stéphane Marchesin, dri-devel
2013/10/14 Sean Paul <seanpaul@chromium.org>:
> On Mon, Oct 14, 2013 at 8:42 AM, Inki Dae <inki.dae@samsung.com> wrote:
>> Hi, Sean.
>>
>>
>> It's a great patch set.:) That's exactly what we want. So I'd like to merge
>> all patch set to exynos-drm-next if there is no design issue about next
>> week. And then we can add additional minor patches from others.
>>
>> Before that, can you re-send all patch set like below?
>> 1. Do not rebase them at top of lvds-bridge patch set.
>> 2. Change all patch set for callbacks to be called
>> _with_device_object instead of ctx.
>>
>> The below is my comments.
>>
>> Thanks for your contributions,
>> Inki Dae
>>
>>> -----Original Message-----
>>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>> Sent: Friday, October 11, 2013 9:30 AM
>>> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>>> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org; Sean
>>> Paul
>>> Subject: [PATCH 06/23] drm/exynos: Pass context in manager ops instead of
>>> dev
>>>
>>> This patch changes the manager ops callbacks from accepting the subdrv
>>> device pointer to taking a context pointer. This will allow us to move
>>> closer to decoupling manager/display from subdrv, and subsequently
>>> decoupling the crtc/plane from the encoder.
>>>
>>> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>>> ---
>>> drivers/gpu/drm/exynos/exynos_drm_connector.c | 2 +-
>>> drivers/gpu/drm/exynos/exynos_drm_drv.h | 33 ++++++------
>>> drivers/gpu/drm/exynos/exynos_drm_encoder.c | 24 ++++-----
>>> drivers/gpu/drm/exynos/exynos_drm_fimd.c | 71
>> +++++++++++++----------
>>> --
>>> drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 75
>> +++++++++++++++--------
>>> ----
>>> drivers/gpu/drm/exynos/exynos_drm_vidi.c | 49 ++++++++---------
>>> 6 files changed, 130 insertions(+), 124 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c
>>> b/drivers/gpu/drm/exynos/exynos_drm_connector.c
>>> index e082efb..b70b123 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
>>> @@ -198,7 +198,7 @@ static int exynos_drm_connector_fill_modes(struct
>>> drm_connector *connector,
>>> * resolution then get max width and height from that driver.
>>> */
>>> if (ops && ops->get_max_resol)
>>> - ops->get_max_resol(manager->dev, &width, &height);
>>> + ops->get_max_resol(manager->ctx, &width, &height);
>>>
>>> return drm_helper_probe_single_connector_modes(connector, width,
>>> height);
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h
>>> b/drivers/gpu/drm/exynos/exynos_drm_drv.h
>>> index 09bfe60..0bd444f 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
>>> @@ -162,26 +162,23 @@ struct exynos_drm_display_ops {
>>> * @win_disable: disable hardware specific overlay.
>>> */
>>> struct exynos_drm_manager_ops {
>>> - int (*initialize)(struct device *subdrv_dev,
>>> - struct drm_device *drm_dev);
>>> - void (*dpms)(struct device *subdrv_dev, int mode);
>>> - void (*apply)(struct device *subdrv_dev);
>>> - void (*mode_fixup)(struct device *subdrv_dev,
>>> - struct drm_connector *connector,
>>> + int (*initialize)(void *ctx, struct drm_device *drm_dev);
>>> + void (*dpms)(void *ctx, int mode);
>>> + void (*apply)(void *ctx);
>>> + void (*mode_fixup)(void *ctx, struct drm_connector *connector,
>>> const struct drm_display_mode *mode,
>>> struct drm_display_mode *adjusted_mode);
>>> - void (*mode_set)(struct device *subdrv_dev, void *mode);
>>> - void (*get_max_resol)(struct device *subdrv_dev, unsigned int
>>> *width,
>>> + void (*mode_set)(void *ctx, void *mode);
>>> + void (*get_max_resol)(void *ctx, unsigned int *width,
>>> unsigned int *height);
>>> - void (*commit)(struct device *subdrv_dev);
>>> - int (*enable_vblank)(struct device *subdrv_dev);
>>> - void (*disable_vblank)(struct device *subdrv_dev);
>>> - void (*wait_for_vblank)(struct device *subdrv_dev);
>>> - void (*win_mode_set)(struct device *subdrv_dev,
>>> - struct exynos_drm_overlay *overlay);
>>> - void (*win_commit)(struct device *subdrv_dev, int zpos);
>>> - void (*win_enable)(struct device *subdrv_dev, int zpos);
>>> - void (*win_disable)(struct device *subdrv_dev, int zpos);
>>> + void (*commit)(void *ctx);
>>> + int (*enable_vblank)(void *ctx);
>>> + void (*disable_vblank)(void *ctx);
>>> + void (*wait_for_vblank)(void *ctx);
>>> + void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
>>> + void (*win_commit)(void *ctx, int zpos);
>>> + void (*win_enable)(void *ctx, int zpos);
>>> + void (*win_disable)(void *ctx, int zpos);
>>> };
>>>
>>> /*
>>> @@ -197,12 +194,14 @@ struct exynos_drm_manager_ops {
>>> * these callbacks should be set by specific drivers such fimd
>>> * or hdmi driver and are used to control display devices such as
>>> * analog tv, digital tv and lcd panel and also get timing data for
>>> them.
>>> + * @ctx: A pointer to the manager's implementation specific context
>>> */
>>> struct exynos_drm_manager {
>>> struct device *dev;
>>> int pipe;
>>> struct exynos_drm_manager_ops *ops;
>>> struct exynos_drm_display_ops *display_ops;
>>> + void *ctx;
>>
>> Plz, remove ctx we can use dev instead.
>>
>
> I'd rather not use dev, tbh. I think a good solution would be to pass
> exynos_drm_manager && exynos_drm_display through the exynos hooks
> instead. This will give us type checking in the compiler, as well as
> keeping the ctx pointers out of the abstraction layer. Sound good?
manager->ops->xxx(manager, ...);
display->ops->xxx(display, ...);
Agree.
>
>>> };
>>>
>>> struct exynos_drm_g2d_private {
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>> b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>> index a9eb2b0..24484ae 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>> @@ -74,7 +74,7 @@ static void exynos_drm_encoder_dpms(struct drm_encoder
>>> *encoder, int mode)
>>> case DRM_MODE_DPMS_ON:
>>> if (manager_ops && manager_ops->apply)
>>> if (!exynos_encoder->updated)
>>> - manager_ops->apply(manager->dev);
>>> + manager_ops->apply(manager->ctx);
>>>
>>> exynos_drm_connector_power(encoder, mode);
>>> exynos_encoder->dpms = mode;
>>> @@ -107,7 +107,7 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder
>>> *encoder,
>>> list_for_each_entry(connector, &dev->mode_config.connector_list,
>>> head) {
>>> if (connector->encoder == encoder)
>>> if (manager_ops && manager_ops->mode_fixup)
>>> - manager_ops->mode_fixup(manager->dev,
>> connector,
>>> + manager_ops->mode_fixup(manager->ctx,
>> connector,
>>> mode,
>> adjusted_mode);
>>> }
>>>
>>> @@ -175,7 +175,7 @@ static void exynos_drm_encoder_mode_set(struct
>>> drm_encoder *encoder,
>>> manager_ops = manager->ops;
>>>
>>> if (manager_ops && manager_ops->mode_set)
>>> - manager_ops->mode_set(manager->dev,
>>> + manager_ops->mode_set(manager->ctx,
>>> adjusted_mode);
>>>
>>> exynos_encoder->old_crtc = encoder->crtc;
>>> @@ -195,7 +195,7 @@ static void exynos_drm_encoder_commit(struct
>>> drm_encoder *encoder)
>>> struct exynos_drm_manager_ops *manager_ops = manager->ops;
>>>
>>> if (manager_ops && manager_ops->commit)
>>> - manager_ops->commit(manager->dev);
>>> + manager_ops->commit(manager->ctx);
>>>
>>> /*
>>> * this will avoid one issue that overlay data is updated to
>>> @@ -341,7 +341,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
>>> drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
>>>
>>> if (manager->ops && manager->ops->initialize) {
>>> - ret = manager->ops->initialize(manager->dev, dev);
>>> + ret = manager->ops->initialize(manager->ctx, dev);
>>> if (ret) {
>>> DRM_ERROR("Manager initialize failed %d\n", ret);
>>> goto error;
>>> @@ -408,7 +408,7 @@ void exynos_drm_enable_vblank(struct drm_encoder
>>> *encoder, void *data)
>>> return;
>>>
>>> if (manager_ops->enable_vblank)
>>> - manager_ops->enable_vblank(manager->dev);
>>> + manager_ops->enable_vblank(manager->ctx);
>>> }
>>>
>>> void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
>>> @@ -422,7 +422,7 @@ void exynos_drm_disable_vblank(struct drm_encoder
>>> *encoder, void *data)
>>> return;
>>>
>>> if (manager_ops->disable_vblank)
>>> - manager_ops->disable_vblank(manager->dev);
>>> + manager_ops->disable_vblank(manager->ctx);
>>> }
>>>
>>> void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void
>> *data)
>>> @@ -433,7 +433,7 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder
>>> *encoder, void *data)
>>> int mode = *(int *)data;
>>>
>>> if (manager_ops && manager_ops->dpms)
>>> - manager_ops->dpms(manager->dev, mode);
>>> + manager_ops->dpms(manager->ctx, mode);
>>>
>>> /*
>>> * if this condition is ok then it means that the crtc is already
>>> @@ -467,7 +467,7 @@ void exynos_drm_encoder_plane_mode_set(struct
>>> drm_encoder *encoder, void *data)
>>> struct exynos_drm_overlay *overlay = data;
>>>
>>> if (manager_ops && manager_ops->win_mode_set)
>>> - manager_ops->win_mode_set(manager->dev, overlay);
>>> + manager_ops->win_mode_set(manager->ctx, overlay);
>>> }
>>>
>>> void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void
>>> *data)
>>> @@ -481,7 +481,7 @@ void exynos_drm_encoder_plane_commit(struct
>>> drm_encoder *encoder, void *data)
>>> zpos = *(int *)data;
>>>
>>> if (manager_ops && manager_ops->win_commit)
>>> - manager_ops->win_commit(manager->dev, zpos);
>>> + manager_ops->win_commit(manager->ctx, zpos);
>>> }
>>>
>>> void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void
>>> *data)
>>> @@ -495,7 +495,7 @@ void exynos_drm_encoder_plane_enable(struct
>>> drm_encoder *encoder, void *data)
>>> zpos = *(int *)data;
>>>
>>> if (manager_ops && manager_ops->win_enable)
>>> - manager_ops->win_enable(manager->dev, zpos);
>>> + manager_ops->win_enable(manager->ctx, zpos);
>>> }
>>>
>>> void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void
>>> *data)
>>> @@ -509,5 +509,5 @@ void exynos_drm_encoder_plane_disable(struct
>>> drm_encoder *encoder, void *data)
>>> zpos = *(int *)data;
>>>
>>> if (manager_ops && manager_ops->win_disable)
>>> - manager_ops->win_disable(manager->dev, zpos);
>>> + manager_ops->win_disable(manager->ctx, zpos);
>>> }
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>> b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>> index 90fcd6f..9c2720a 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>> @@ -106,6 +106,7 @@ struct fimd_win_data {
>>>
>>> struct fimd_context {
>>> struct exynos_drm_subdrv subdrv;
>>
>> It seems that crtc device drivers such as fimd and hdmi mixer don't need to
>> register subdrv. So remove?
>>
>
> Yeah, good catch, this is no longer needed.
>
>>> + struct device *dev;
>>> struct drm_device *drm_dev;
>>> int irq;
>>> struct drm_crtc *crtc;
>>> @@ -182,16 +183,15 @@ static struct exynos_drm_display_ops
>>> fimd_display_ops = {
>>> .power_on = fimd_display_power_on,
>>> };
>>>
>>> -static void fimd_win_mode_set(struct device *dev,
>>> - struct exynos_drm_overlay *overlay)
>>> +static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay
>>> *overlay)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> + struct fimd_context *ctx = in_ctx;
>>> struct fimd_win_data *win_data;
>>> int win;
>>> unsigned long offset;
>>>
>>> if (!overlay) {
>>> - dev_err(dev, "overlay is NULL\n");
>>> + DRM_ERROR("overlay is NULL\n");
>>> return;
>>> }
>>>
>>> @@ -231,9 +231,8 @@ static void fimd_win_mode_set(struct device *dev,
>>> overlay->fb_width, overlay->crtc_width);
>>> }
>>>
>>> -static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
>>> +static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int
>>> win)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> struct fimd_win_data *win_data = &ctx->win_data[win];
>>> unsigned long val;
>>>
>>> @@ -289,9 +288,8 @@ static void fimd_win_set_pixfmt(struct device *dev,
>>> unsigned int win)
>>> writel(val, ctx->regs + WINCON(win));
>>> }
>>>
>>> -static void fimd_win_set_colkey(struct device *dev, unsigned int win)
>>> +static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int
>>> win)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> unsigned int keycon0 = 0, keycon1 = 0;
>>>
>>> keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
>>> @@ -330,9 +328,9 @@ static void fimd_shadow_protect_win(struct
>>> fimd_context *ctx,
>>> writel(val, ctx->regs + reg);
>>> }
>>>
>>> -static void fimd_win_commit(struct device *dev, int zpos)
>>> +static void fimd_win_commit(void *in_ctx, int zpos)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> + struct fimd_context *ctx = in_ctx;
>>> struct fimd_win_data *win_data;
>>> int win = zpos;
>>> unsigned long val, alpha, size;
>>> @@ -427,11 +425,11 @@ static void fimd_win_commit(struct device *dev, int
>>> zpos)
>>> DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
>>> }
>>>
>>> - fimd_win_set_pixfmt(dev, win);
>>> + fimd_win_set_pixfmt(ctx, win);
>>>
>>> /* hardware window 0 doesn't support color key. */
>>> if (win != 0)
>>> - fimd_win_set_colkey(dev, win);
>>> + fimd_win_set_colkey(ctx, win);
>>>
>>> /* wincon */
>>> val = readl(ctx->regs + WINCON(win));
>>> @@ -450,9 +448,9 @@ static void fimd_win_commit(struct device *dev, int
>>> zpos)
>>> win_data->enabled = true;
>>> }
>>>
>>> -static void fimd_win_disable(struct device *dev, int zpos)
>>> +static void fimd_win_disable(void *in_ctx, int zpos)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> + struct fimd_context *ctx = in_ctx;
>>> struct fimd_win_data *win_data;
>>> int win = zpos;
>>> u32 val;
>>> @@ -491,19 +489,18 @@ static void fimd_win_disable(struct device *dev, int
>>> zpos)
>>> win_data->enabled = false;
>>> }
>>>
>>> -static int fimd_mgr_initialize(struct device *subdrv_dev,
>>> - struct drm_device *drm_dev)
>>> +static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
>>> + struct fimd_context *ctx = in_ctx;
>>>
>>> ctx->drm_dev = drm_dev;
>>>
>>> return 0;
>>> }
>>>
>>> -static void fimd_dpms(struct device *subdrv_dev, int mode)
>>> +static void fimd_dpms(void *in_ctx, int mode)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
>>> + struct fimd_context *ctx = in_ctx;
>>>
>>> DRM_DEBUG_KMS("%d\n", mode);
>>>
>>> @@ -518,13 +515,13 @@ static void fimd_dpms(struct device *subdrv_dev, int
>>> mode)
>>> * clk_enable could be called double time.
>>> */
>>> if (ctx->suspended)
>>> - pm_runtime_get_sync(subdrv_dev);
>>> + pm_runtime_get_sync(ctx->dev);
>>> break;
>>> case DRM_MODE_DPMS_STANDBY:
>>> case DRM_MODE_DPMS_SUSPEND:
>>> case DRM_MODE_DPMS_OFF:
>>> if (!ctx->suspended)
>>> - pm_runtime_put_sync(subdrv_dev);
>>> + pm_runtime_put_sync(ctx->dev);
>>> break;
>>> default:
>>> DRM_DEBUG_KMS("unspecified mode %d\n", mode);
>>> @@ -534,9 +531,9 @@ static void fimd_dpms(struct device *subdrv_dev, int
>>> mode)
>>> mutex_unlock(&ctx->lock);
>>> }
>>>
>>> -static void fimd_apply(struct device *subdrv_dev)
>>> +static void fimd_apply(void *in_ctx)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(subdrv_dev);
>>> + struct fimd_context *ctx = in_ctx;
>>> struct exynos_drm_manager *mgr = ctx->subdrv.manager;
>>> struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
>>> struct fimd_win_data *win_data;
>>> @@ -545,16 +542,16 @@ static void fimd_apply(struct device *subdrv_dev)
>>> for (i = 0; i < WINDOWS_NR; i++) {
>>> win_data = &ctx->win_data[i];
>>> if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
>>> - mgr_ops->win_commit(subdrv_dev, i);
>>> + mgr_ops->win_commit(ctx, i);
>>> }
>>>
>>> if (mgr_ops && mgr_ops->commit)
>>> - mgr_ops->commit(subdrv_dev);
>>> + mgr_ops->commit(ctx);
>>> }
>>>
>>> -static void fimd_commit(struct device *dev)
>>> +static void fimd_commit(void *in_ctx)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> + struct fimd_context *ctx = in_ctx;
>>> struct exynos_drm_panel_info *panel = &ctx->panel;
>>> struct videomode *vm = &panel->vm;
>>> struct fimd_driver_data *driver_data;
>>> @@ -608,9 +605,9 @@ static void fimd_commit(struct device *dev)
>>> writel(val, ctx->regs + VIDCON0);
>>> }
>>>
>>> -static int fimd_enable_vblank(struct device *dev)
>>> +static int fimd_enable_vblank(void *in_ctx)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> + struct fimd_context *ctx = in_ctx;
>>> u32 val;
>>>
>>> if (ctx->suspended)
>>> @@ -633,9 +630,9 @@ static int fimd_enable_vblank(struct device *dev)
>>> return 0;
>>> }
>>>
>>> -static void fimd_disable_vblank(struct device *dev)
>>> +static void fimd_disable_vblank(void *in_ctx)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> + struct fimd_context *ctx = in_ctx;
>>> u32 val;
>>>
>>> if (ctx->suspended)
>>> @@ -651,9 +648,9 @@ static void fimd_disable_vblank(struct device *dev)
>>> }
>>> }
>>>
>>> -static void fimd_wait_for_vblank(struct device *dev)
>>> +static void fimd_wait_for_vblank(void *in_ctx)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> + struct fimd_context *ctx = in_ctx;
>>>
>>> if (ctx->suspended)
>>> return;
>>> @@ -845,9 +842,9 @@ static void fimd_window_suspend(struct device *dev)
>>> for (i = 0; i < WINDOWS_NR; i++) {
>>> win_data = &ctx->win_data[i];
>>> win_data->resume = win_data->enabled;
>>> - fimd_win_disable(dev, i);
>>> + fimd_win_disable(ctx, i);
>>> }
>>> - fimd_wait_for_vblank(dev);
>>> + fimd_wait_for_vblank(ctx);
>>> }
>>>
>>> static void fimd_window_resume(struct device *dev)
>>> @@ -963,6 +960,8 @@ static int fimd_probe(struct platform_device *pdev)
>>> DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
>>> atomic_set(&ctx->wait_vsync_event, 0);
>>>
>>> + fimd_manager.ctx = ctx;
>>> +
>>> subdrv = &ctx->subdrv;
>>>
>>> subdrv->dev = dev;
>>> @@ -1042,7 +1041,7 @@ static int fimd_resume(struct device *dev)
>>> * registers but in case of sleep wakeup, it's not.
>>> * so fimd_apply function should be called at here.
>>> */
>>> - fimd_apply(dev);
>>> + fimd_apply(ctx);
>>> }
>>>
>>> return 0;
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>>> b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>>> index aebcc0e..cddb0c8 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>>> @@ -129,11 +129,9 @@ static struct edid *drm_hdmi_get_edid(struct device
>>> *dev,
>>>
>>> return NULL;
>>> }
>>> -
>>> -static int drm_hdmi_check_mode(struct device *dev,
>>> +static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
>>> struct drm_display_mode *mode)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(dev);
>>> int ret = 0;
>>>
>>> /*
>>> @@ -153,6 +151,14 @@ static int drm_hdmi_check_mode(struct device *dev,
>>> return 0;
>>> }
>>>
>>> +static int drm_hdmi_check_mode(struct device *dev,
>>> + struct drm_display_mode *mode)
>>> +{
>>> + struct drm_hdmi_context *ctx = to_context(dev);
>>> +
>>> + return drm_hdmi_check_mode_ctx(ctx, mode);
>>> +}
>>> +
>>> static int drm_hdmi_power_on(struct device *dev, int mode)
>>> {
>>> struct drm_hdmi_context *ctx = to_context(dev);
>>> @@ -172,9 +178,9 @@ static struct exynos_drm_display_ops
>>> drm_hdmi_display_ops = {
>>> .power_on = drm_hdmi_power_on,
>>> };
>>>
>>> -static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
>>> +static int drm_hdmi_enable_vblank(void *in_ctx)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + struct drm_hdmi_context *ctx = in_ctx;
>>> struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
>>> struct exynos_drm_manager *manager = subdrv->manager;
>>>
>>> @@ -185,33 +191,33 @@ static int drm_hdmi_enable_vblank(struct device
>>> *subdrv_dev)
>>> return 0;
>>> }
>>>
>>> -static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
>>> +static void drm_hdmi_disable_vblank(void *in_ctx)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + struct drm_hdmi_context *ctx = in_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 device *subdrv_dev)
>>> +static void drm_hdmi_wait_for_vblank(void *in_ctx)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + 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_mode_fixup(struct device *subdrv_dev,
>>> - struct drm_connector *connector,
>>> +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(subdrv_dev, adjusted_mode);
>>> + mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode);
>>>
>>> /* just return if user desired mode exists. */
>>> if (mode_ok == 0)
>>> @@ -222,7 +228,7 @@ static void drm_hdmi_mode_fixup(struct device
>>> *subdrv_dev,
>>> * to adjusted_mode.
>>> */
>>> list_for_each_entry(m, &connector->modes, head) {
>>> - mode_ok = drm_hdmi_check_mode(subdrv_dev, m);
>>> + mode_ok = drm_hdmi_check_mode_ctx(ctx, m);
>>>
>>> if (mode_ok == 0) {
>>> struct drm_mode_object base;
>>> @@ -245,35 +251,34 @@ static void drm_hdmi_mode_fixup(struct device
>>> *subdrv_dev,
>>> }
>>> }
>>>
>>> -static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
>>> +static void drm_hdmi_mode_set(void *in_ctx, void *mode)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + struct drm_hdmi_context *ctx = in_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 device *subdrv_dev,
>>> - unsigned int *width, unsigned int *height)
>>> +static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
>>> + unsigned int *height)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + struct drm_hdmi_context *ctx = in_ctx;
>>>
>>> if (hdmi_ops && hdmi_ops->get_max_resol)
>>> hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
>>> }
>>>
>>> -static void drm_hdmi_commit(struct device *subdrv_dev)
>>> +static void drm_hdmi_commit(void *in_ctx)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + 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(struct device *subdrv_dev,
>>> - struct drm_device *drm_dev)
>>> +static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device
>>> *drm_dev)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + struct drm_hdmi_context *ctx = in_ctx;
>>> int ret = 0;
>>>
>>> if (mixer_ops && mixer_ops->initialize)
>>> @@ -285,9 +290,9 @@ static int drm_hdmi_mgr_initialize(struct device
>>> *subdrv_dev,
>>> return ret;
>>> }
>>>
>>> -static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
>>> +static void drm_hdmi_dpms(void *in_ctx, int mode)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + struct drm_hdmi_context *ctx = in_ctx;
>>>
>>> if (mixer_ops && mixer_ops->dpms)
>>> mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
>>> @@ -296,9 +301,9 @@ static void drm_hdmi_dpms(struct device *subdrv_dev,
>>> int mode)
>>> hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
>>> }
>>>
>>> -static void drm_hdmi_apply(struct device *subdrv_dev)
>>> +static void drm_hdmi_apply(void *in_ctx)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + struct drm_hdmi_context *ctx = in_ctx;
>>> int i;
>>>
>>> for (i = 0; i < MIXER_WIN_NR; i++) {
>>> @@ -312,18 +317,18 @@ static void drm_hdmi_apply(struct device
>> *subdrv_dev)
>>> hdmi_ops->commit(ctx->hdmi_ctx->ctx);
>>> }
>>>
>>> -static void drm_mixer_win_mode_set(struct device *subdrv_dev,
>>> - struct exynos_drm_overlay *overlay)
>>> +static void drm_mixer_win_mode_set(void *in_ctx,
>>> + struct exynos_drm_overlay *overlay)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + 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(struct device *subdrv_dev, int zpos)
>>> +static void drm_mixer_win_commit(void *in_ctx, int zpos)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + struct drm_hdmi_context *ctx = in_ctx;
>>> int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
>>>
>>> if (win < 0 || win >= MIXER_WIN_NR) {
>>> @@ -337,9 +342,9 @@ static void drm_mixer_win_commit(struct device
>>> *subdrv_dev, int zpos)
>>> ctx->enabled[win] = true;
>>> }
>>>
>>> -static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
>>> +static void drm_mixer_win_disable(void *in_ctx, int zpos)
>>> {
>>> - struct drm_hdmi_context *ctx = to_context(subdrv_dev);
>>> + struct drm_hdmi_context *ctx = in_ctx;
>>> int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
>>>
>>> if (win < 0 || win >= MIXER_WIN_NR) {
>>> @@ -425,6 +430,8 @@ static int exynos_drm_hdmi_probe(struct
>>> platform_device *pdev)
>>> if (!ctx)
>>> return -ENOMEM;
>>>
>>> + hdmi_manager.ctx = ctx;
>>> +
>>> subdrv = &ctx->subdrv;
>>>
>>> subdrv->dev = dev;
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
>>> b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
>>> index 15a97ce..a583a74 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
>>> @@ -152,9 +152,9 @@ static struct exynos_drm_display_ops vidi_display_ops
>>> = {
>>> .power_on = vidi_display_power_on,
>>> };
>>>
>>> -static void vidi_dpms(struct device *subdrv_dev, int mode)
>>> +static void vidi_dpms(void *in_ctx, int mode)
>>> {
>>> - struct vidi_context *ctx = get_vidi_context(subdrv_dev);
>>> + struct vidi_context *ctx = in_ctx;
>>>
>>> DRM_DEBUG_KMS("%d\n", mode);
>>>
>>> @@ -177,9 +177,9 @@ static void vidi_dpms(struct device *subdrv_dev, int
>>> mode)
>>> mutex_unlock(&ctx->lock);
>>> }
>>>
>>> -static void vidi_apply(struct device *subdrv_dev)
>>> +static void vidi_apply(void *in_ctx)
>>> {
>>> - struct vidi_context *ctx = get_vidi_context(subdrv_dev);
>>> + struct vidi_context *ctx = in_ctx;
>>> struct exynos_drm_manager *mgr = ctx->subdrv.manager;
>>> struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
>>> struct vidi_win_data *win_data;
>>> @@ -188,24 +188,24 @@ static void vidi_apply(struct device *subdrv_dev)
>>> for (i = 0; i < WINDOWS_NR; i++) {
>>> win_data = &ctx->win_data[i];
>>> if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
>>> - mgr_ops->win_commit(subdrv_dev, i);
>>> + mgr_ops->win_commit(ctx, i);
>>> }
>>>
>>> if (mgr_ops && mgr_ops->commit)
>>> - mgr_ops->commit(subdrv_dev);
>>> + mgr_ops->commit(ctx);
>>> }
>>>
>>> -static void vidi_commit(struct device *dev)
>>> +static void vidi_commit(void *in_ctx)
>>> {
>>> - struct vidi_context *ctx = get_vidi_context(dev);
>>> + struct vidi_context *ctx = in_ctx;
>>>
>>> if (ctx->suspended)
>>> return;
>>> }
>>>
>>> -static int vidi_enable_vblank(struct device *dev)
>>> +static int vidi_enable_vblank(void *in_ctx)
>>> {
>>> - struct vidi_context *ctx = get_vidi_context(dev);
>>> + struct vidi_context *ctx = in_ctx;
>>>
>>> if (ctx->suspended)
>>> return -EPERM;
>>> @@ -225,9 +225,9 @@ static int vidi_enable_vblank(struct device *dev)
>>> return 0;
>>> }
>>>
>>> -static void vidi_disable_vblank(struct device *dev)
>>> +static void vidi_disable_vblank(void *in_ctx)
>>> {
>>> - struct vidi_context *ctx = get_vidi_context(dev);
>>> + struct vidi_context *ctx = in_ctx;
>>>
>>> if (ctx->suspended)
>>> return;
>>> @@ -236,16 +236,15 @@ static void vidi_disable_vblank(struct device *dev)
>>> ctx->vblank_on = false;
>>> }
>>>
>>> -static void vidi_win_mode_set(struct device *dev,
>>> - struct exynos_drm_overlay *overlay)
>>> +static void vidi_win_mode_set(void *in_ctx, struct exynos_drm_overlay
>>> *overlay)
>>> {
>>> - struct vidi_context *ctx = get_vidi_context(dev);
>>> + struct vidi_context *ctx = in_ctx;
>>> struct vidi_win_data *win_data;
>>> int win;
>>> unsigned long offset;
>>>
>>> if (!overlay) {
>>> - dev_err(dev, "overlay is NULL\n");
>>> + DRM_ERROR("overlay is NULL\n");
>>> return;
>>> }
>>>
>>> @@ -289,9 +288,9 @@ static void vidi_win_mode_set(struct device *dev,
>>> overlay->fb_width, overlay->crtc_width);
>>> }
>>>
>>> -static void vidi_win_commit(struct device *dev, int zpos)
>>> +static void vidi_win_commit(void *in_ctx, int zpos)
>>> {
>>> - struct vidi_context *ctx = get_vidi_context(dev);
>>> + struct vidi_context *ctx = in_ctx;
>>> struct vidi_win_data *win_data;
>>> int win = zpos;
>>>
>>> @@ -314,9 +313,9 @@ static void vidi_win_commit(struct device *dev, int
>>> zpos)
>>> schedule_work(&ctx->work);
>>> }
>>>
>>> -static void vidi_win_disable(struct device *dev, int zpos)
>>> +static void vidi_win_disable(void *in_ctx, int zpos)
>>> {
>>> - struct vidi_context *ctx = get_vidi_context(dev);
>>> + struct vidi_context *ctx = in_ctx;
>>> struct vidi_win_data *win_data;
>>> int win = zpos;
>>>
>>> @@ -405,17 +404,19 @@ static void vidi_subdrv_remove(struct drm_device
>>> *drm_dev, struct device *dev)
>>>
>>> static int vidi_power_on(struct vidi_context *ctx, bool enable)
>>> {
>>> - struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
>>> - struct device *dev = subdrv->dev;
>>> + DRM_DEBUG_KMS("%s\n", __FILE__);
>>> +
>>> + if (enable != false && enable != true)
>>> + return -EINVAL;
>>>
>>> if (enable) {
>>> ctx->suspended = false;
>>>
>>> /* if vblank was enabled status, enable it again. */
>>> if (test_and_clear_bit(0, &ctx->irq_flags))
>>> - vidi_enable_vblank(dev);
>>> + vidi_enable_vblank(ctx);
>>>
>>> - vidi_apply(dev);
>>> + vidi_apply(ctx);
>>> } else {
>>> ctx->suspended = true;
>>> }
>>> --
>>> 1.8.4
>>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-11 0:30 ` [PATCH 12/23] drm/exynos: Split manager/display/subdrv Sean Paul
2013-10-12 0:42 ` Inki Dae
@ 2013-10-14 15:24 ` Inki Dae
2013-10-15 4:09 ` Inki Dae
1 sibling, 1 reply; 38+ messages in thread
From: Inki Dae @ 2013-10-14 15:24 UTC (permalink / raw)
To: Sean Paul; +Cc: Stéphane Marchesin, DRI mailing list
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> index c417c90..ba63c72 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> @@ -26,24 +26,23 @@
> * exynos specific encoder structure.
> *
> * @drm_encoder: encoder object.
> - * @manager: specific encoder has its own manager to control a hardware
> - * appropriately and we can access a hardware drawing on this manager.
> + * @display: the display structure that maps to this encoder
> */
> struct exynos_drm_encoder {
> struct drm_crtc *old_crtc;
> struct drm_encoder drm_encoder;
> - struct exynos_drm_manager *manager;
> + struct exynos_drm_display *display;
> };
>
> static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
> {
> - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
> - struct exynos_drm_display_ops *display_ops = manager->display_ops;
> + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> + struct exynos_drm_display *display = exynos_encoder->display;
>
> DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
>
> - if (display_ops && display_ops->dpms)
> - display_ops->dpms(manager->ctx, mode);
> + if (display->ops->dpms)
> + display->ops->dpms(display->ctx, mode);
It's good to remove apply callback. However, it seems that this patch
has a problem that dma channel of fimd isn't enabled after dpms goes
from off to on. So can you implement win_enable callback of fimd, and
add it to fimd_win_resume function? We should have implemented
win_enable callback.
> }
>
> static bool
> @@ -52,15 +51,17 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
> struct drm_display_mode *adjusted_mode)
> {
> struct drm_device *dev = encoder->dev;
> + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> + struct exynos_drm_display *display = exynos_encoder->display;
> struct drm_connector *connector;
> - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
> - struct exynos_drm_manager_ops *manager_ops = manager->ops;
>
> list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
> - if (connector->encoder == encoder)
> - if (manager_ops && manager_ops->mode_fixup)
> - manager_ops->mode_fixup(manager->ctx, connector,
> - mode, adjusted_mode);
> + if (connector->encoder != encoder)
> + continue;
> +
> + if (display->ops->mode_fixup)
> + display->ops->mode_fixup(display->ctx, connector, mode,
> + adjusted_mode);
> }
>
> return true;
> @@ -102,8 +103,7 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
> {
> struct drm_device *dev = encoder->dev;
> struct drm_connector *connector;
> - struct exynos_drm_manager *manager;
> - struct exynos_drm_manager_ops *manager_ops;
> + struct exynos_drm_display *display;
>
> list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
> if (connector->encoder == encoder) {
> @@ -123,11 +123,10 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
> encoder->crtc);
> }
>
> - manager = exynos_drm_get_manager(encoder);
> - manager_ops = manager->ops;
> + display = exynos_encoder->display;
>
> - if (manager_ops && manager_ops->mode_set)
> - manager_ops->mode_set(manager->ctx,
> + if (display->ops->mode_set)
> + display->ops->mode_set(display->ctx,
> adjusted_mode);
>
> exynos_encoder->old_crtc = encoder->crtc;
> @@ -143,39 +142,15 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
> static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
> {
> struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> - struct exynos_drm_manager *manager = exynos_encoder->manager;
> - struct exynos_drm_manager_ops *manager_ops = manager->ops;
> -
> - if (manager_ops && manager_ops->commit)
> - manager_ops->commit(manager->ctx);
> -}
> + struct exynos_drm_display *display = exynos_encoder->display;
>
> -void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
> -{
> - struct exynos_drm_encoder *exynos_encoder;
> - struct exynos_drm_manager_ops *ops;
> - struct drm_device *dev = fb->dev;
> - struct drm_encoder *encoder;
> + if (display->ops->dpms)
> + display->ops->dpms(display->ctx, DRM_MODE_DPMS_ON);
>
> - /*
> - * make sure that overlay data are updated to real hardware
> - * for all encoders.
> - */
> - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
> - exynos_encoder = to_exynos_encoder(encoder);
> - ops = exynos_encoder->manager->ops;
> -
> - /*
> - * wait for vblank interrupt
> - * - this makes sure that overlay data are updated to
> - * real hardware.
> - */
> - if (ops->wait_for_vblank)
> - ops->wait_for_vblank(exynos_encoder->manager->dev);
> - }
> + if (display->ops->commit)
> + display->ops->commit(display->ctx);
> }
>
> -
> static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
> {
> struct drm_plane *plane;
> @@ -201,10 +176,7 @@ static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
>
> static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
> {
> - struct exynos_drm_encoder *exynos_encoder =
> - to_exynos_encoder(encoder);
> -
> - exynos_encoder->manager->pipe = -1;
> + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
>
> drm_encoder_cleanup(encoder);
> kfree(exynos_encoder);
> @@ -219,13 +191,12 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
> struct drm_encoder *clone;
> struct drm_device *dev = encoder->dev;
> struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> - struct exynos_drm_display_ops *display_ops =
> - exynos_encoder->manager->display_ops;
> + struct exynos_drm_display *display = exynos_encoder->display;
> unsigned int clone_mask = 0;
> int cnt = 0;
>
> list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
> - switch (display_ops->type) {
> + switch (display->type) {
> case EXYNOS_DISPLAY_TYPE_LCD:
> case EXYNOS_DISPLAY_TYPE_HDMI:
> case EXYNOS_DISPLAY_TYPE_VIDI:
> @@ -249,24 +220,20 @@ void exynos_drm_encoder_setup(struct drm_device *dev)
>
> struct drm_encoder *
> exynos_drm_encoder_create(struct drm_device *dev,
> - struct exynos_drm_manager *manager,
> + struct exynos_drm_display *display,
> unsigned long possible_crtcs)
> {
> struct drm_encoder *encoder;
> struct exynos_drm_encoder *exynos_encoder;
> - int ret;
>
> - if (!manager || !possible_crtcs)
> - return NULL;
> -
> - if (!manager->dev)
> + if (!possible_crtcs)
> return NULL;
>
> exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
> if (!exynos_encoder)
> return NULL;
>
> - exynos_encoder->manager = manager;
> + exynos_encoder->display = display;
> encoder = &exynos_encoder->drm_encoder;
> encoder->possible_crtcs = possible_crtcs;
>
> @@ -277,174 +244,12 @@ exynos_drm_encoder_create(struct drm_device *dev,
>
> drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
>
> - if (manager->ops && manager->ops->initialize) {
> - ret = manager->ops->initialize(manager->ctx, dev);
> - if (ret) {
> - DRM_ERROR("Manager initialize failed %d\n", ret);
> - goto error;
> - }
> - }
> -
> - if (manager->display_ops && manager->display_ops->initialize) {
> - ret = manager->display_ops->initialize(manager->ctx, dev);
> - if (ret) {
> - DRM_ERROR("Display initialize failed %d\n", ret);
> - goto error;
> - }
> - }
> -
> DRM_DEBUG_KMS("encoder has been created\n");
>
> return encoder;
> -
> -error:
> - exynos_drm_encoder_destroy(&exynos_encoder->drm_encoder);
> - return NULL;
> }
>
> -struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
> +struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
> {
> - return to_exynos_encoder(encoder)->manager;
> -}
> -
> -void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
> - void (*fn)(struct drm_encoder *, void *))
> -{
> - struct drm_device *dev = crtc->dev;
> - struct drm_encoder *encoder;
> - struct exynos_drm_private *private = dev->dev_private;
> - struct exynos_drm_manager *manager;
> -
> - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
> - /*
> - * if crtc is detached from encoder, check pipe,
> - * otherwise check crtc attached to encoder
> - */
> - if (!encoder->crtc) {
> - manager = to_exynos_encoder(encoder)->manager;
> - if (manager->pipe < 0 ||
> - private->crtc[manager->pipe] != crtc)
> - continue;
> - } else {
> - if (encoder->crtc != crtc)
> - continue;
> - }
> -
> - fn(encoder, data);
> - }
> -}
> -
> -void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
> -{
> - struct exynos_drm_manager *manager =
> - to_exynos_encoder(encoder)->manager;
> - struct exynos_drm_manager_ops *manager_ops = manager->ops;
> - int crtc = *(int *)data;
> -
> - if (manager->pipe != crtc)
> - return;
> -
> - if (manager_ops->enable_vblank)
> - manager_ops->enable_vblank(manager->ctx);
> -}
> -
> -void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
> -{
> - struct exynos_drm_manager *manager =
> - to_exynos_encoder(encoder)->manager;
> - struct exynos_drm_manager_ops *manager_ops = manager->ops;
> - int crtc = *(int *)data;
> -
> - if (manager->pipe != crtc)
> - return;
> -
> - if (manager_ops->disable_vblank)
> - manager_ops->disable_vblank(manager->ctx);
> -}
> -
> -void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
> -{
> - struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> - struct exynos_drm_manager *manager = exynos_encoder->manager;
> - struct exynos_drm_manager_ops *manager_ops = manager->ops;
> - int mode = *(int *)data;
> -
> - if (manager_ops && manager_ops->dpms)
> - manager_ops->dpms(manager->ctx, mode);
> -
> - /*
> - * if this condition is ok then it means that the crtc is already
> - * detached from encoder and last function for detaching is properly
> - * done, so clear pipe from manager to prevent repeated call.
> - */
> - if (mode > DRM_MODE_DPMS_ON) {
> - if (!encoder->crtc)
> - manager->pipe = -1;
> - }
> -}
> -
> -void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
> -{
> - struct exynos_drm_manager *manager =
> - to_exynos_encoder(encoder)->manager;
> - int pipe = *(int *)data;
> -
> - /*
> - * when crtc is detached from encoder, this pipe is used
> - * to select manager operation
> - */
> - manager->pipe = pipe;
> -}
> -
> -void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
> -{
> - struct exynos_drm_manager *manager =
> - to_exynos_encoder(encoder)->manager;
> - struct exynos_drm_manager_ops *manager_ops = manager->ops;
> - struct exynos_drm_overlay *overlay = data;
> -
> - if (manager_ops && manager_ops->win_mode_set)
> - manager_ops->win_mode_set(manager->ctx, overlay);
> -}
> -
> -void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
> -{
> - struct exynos_drm_manager *manager =
> - to_exynos_encoder(encoder)->manager;
> - struct exynos_drm_manager_ops *manager_ops = manager->ops;
> - int zpos = DEFAULT_ZPOS;
> -
> - if (data)
> - zpos = *(int *)data;
> -
> - if (manager_ops && manager_ops->win_commit)
> - manager_ops->win_commit(manager->ctx, zpos);
> -}
> -
> -void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
> -{
> - struct exynos_drm_manager *manager =
> - to_exynos_encoder(encoder)->manager;
> - struct exynos_drm_manager_ops *manager_ops = manager->ops;
> - int zpos = DEFAULT_ZPOS;
> -
> - if (data)
> - zpos = *(int *)data;
> -
> - if (manager_ops && manager_ops->win_enable)
> - manager_ops->win_enable(manager->ctx, zpos);
> -}
> -
> -void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
> -{
> - struct exynos_drm_manager *manager =
> - to_exynos_encoder(encoder)->manager;
> - struct exynos_drm_manager_ops *manager_ops = manager->ops;
> - int zpos = DEFAULT_ZPOS;
> -
> - if (data)
> - zpos = *(int *)data;
> -
> - if (manager_ops && manager_ops->win_disable)
> - manager_ops->win_disable(manager->ctx, zpos);
> + return to_exynos_encoder(encoder)->display;
> }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
> index 0f3e5e2..b7a1620 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
> @@ -18,20 +18,8 @@ struct exynos_drm_manager;
>
> void exynos_drm_encoder_setup(struct drm_device *dev);
> struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
> - struct exynos_drm_manager *mgr,
> - unsigned long possible_crtcs);
> -struct exynos_drm_manager *
> -exynos_drm_get_manager(struct drm_encoder *encoder);
> -void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
> - void (*fn)(struct drm_encoder *, void *));
> -void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
> -void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb);
> + struct exynos_drm_display *mgr,
> + unsigned long possible_crtcs);
> +struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder);
>
> #endif
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
> index ea39e0e..c7c08d0 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
> @@ -22,7 +22,7 @@
> #include "exynos_drm_fb.h"
> #include "exynos_drm_gem.h"
> #include "exynos_drm_iommu.h"
> -#include "exynos_drm_encoder.h"
> +#include "exynos_drm_crtc.h"
>
> #define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb)
>
> @@ -71,7 +71,7 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
> unsigned int i;
>
> /* make sure that overlay data are updated before relesing fb. */
> - exynos_drm_encoder_complete_scanout(fb);
> + exynos_drm_crtc_complete_scanout(fb);
>
> drm_framebuffer_cleanup(fb);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index 838c47d..f3dc808 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -105,7 +105,6 @@ struct fimd_win_data {
> };
>
> struct fimd_context {
> - struct exynos_drm_subdrv subdrv;
> struct device *dev;
> struct drm_device *drm_dev;
> int irq;
> @@ -120,6 +119,7 @@ struct fimd_context {
> u32 vidcon0;
> u32 vidcon1;
> bool suspended;
> + int pipe;
> struct mutex lock;
> wait_queue_head_t wait_vsync_queue;
> atomic_t wait_vsync_event;
> @@ -169,12 +169,16 @@ static int fimd_check_mode(void *in_ctx, struct drm_display_mode *mode)
> }
>
> static struct exynos_drm_display_ops fimd_display_ops = {
> - .type = EXYNOS_DISPLAY_TYPE_LCD,
> .is_connected = fimd_display_is_connected,
> .get_panel = fimd_get_panel,
> .check_mode = fimd_check_mode,
> };
>
> +static struct exynos_drm_display fimd_display = {
> + .type = EXYNOS_DISPLAY_TYPE_LCD,
> + .ops = &fimd_display_ops,
> +};
> +
> static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
> {
> struct fimd_context *ctx = in_ctx;
> @@ -481,15 +485,46 @@ static void fimd_win_disable(void *in_ctx, int zpos)
> win_data->enabled = false;
> }
>
> -static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
> +static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev,
> + int pipe)
> {
> struct fimd_context *ctx = in_ctx;
>
> ctx->drm_dev = drm_dev;
> + ctx->pipe = pipe;
> +
> + /*
> + * enable drm irq mode.
> + * - with irq_enabled = 1, we can use the vblank feature.
> + *
> + * P.S. note that we wouldn't use drm irq handler but
> + * just specific driver own one instead because
> + * drm framework supports only one irq handler.
> + */
> + ctx->drm_dev->irq_enabled = 1;
> +
> + /*
> + * with vblank_disable_allowed = 1, vblank interrupt will be disabled
> + * by drm timer once a current process gives up ownership of
> + * vblank event.(after drm_vblank_put function is called)
> + */
> + drm_dev->vblank_disable_allowed = 1;
> +
> + /* attach this sub driver to iommu mapping if supported. */
> + if (is_drm_iommu_supported(ctx->drm_dev))
> + drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
>
> return 0;
> }
>
> +static void fimd_mgr_remove(void *in_ctx)
> +{
> + struct fimd_context *ctx = in_ctx;
> +
> + if (is_drm_iommu_supported(ctx->drm_dev))
> + drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
> +}
> +
> static void fimd_dpms(void *in_ctx, int mode)
> {
> struct fimd_context *ctx = in_ctx;
> @@ -523,24 +558,6 @@ static void fimd_dpms(void *in_ctx, int mode)
> mutex_unlock(&ctx->lock);
> }
>
> -static void fimd_apply(void *in_ctx)
> -{
> - struct fimd_context *ctx = in_ctx;
> - struct exynos_drm_manager *mgr = ctx->subdrv.manager;
> - struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
> - struct fimd_win_data *win_data;
> - int i;
> -
> - for (i = 0; i < WINDOWS_NR; i++) {
> - win_data = &ctx->win_data[i];
> - if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
> - mgr_ops->win_commit(ctx, i);
> - }
> -
> - if (mgr_ops && mgr_ops->commit)
> - mgr_ops->commit(ctx);
> -}
> -
> static void fimd_commit(void *in_ctx)
> {
> struct fimd_context *ctx = in_ctx;
> @@ -597,6 +614,21 @@ static void fimd_commit(void *in_ctx)
> writel(val, ctx->regs + VIDCON0);
> }
>
> +static void fimd_apply(void *in_ctx)
> +{
> + struct fimd_context *ctx = in_ctx;
> + struct fimd_win_data *win_data;
> + int i;
> +
> + for (i = 0; i < WINDOWS_NR; i++) {
> + win_data = &ctx->win_data[i];
> + if (win_data->enabled)
> + fimd_win_commit(ctx, i);
> + }
> +
> + fimd_commit(ctx);
> +}
> +
> static int fimd_enable_vblank(void *in_ctx)
> {
> struct fimd_context *ctx = in_ctx;
> @@ -661,6 +693,7 @@ static void fimd_wait_for_vblank(void *in_ctx)
>
> static struct exynos_drm_manager_ops fimd_manager_ops = {
> .initialize = fimd_mgr_initialize,
> + .remove = fimd_mgr_remove,
> .dpms = fimd_dpms,
> .apply = fimd_apply,
> .commit = fimd_commit,
> @@ -673,16 +706,13 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
> };
>
> static struct exynos_drm_manager fimd_manager = {
> - .pipe = -1,
> - .ops = &fimd_manager_ops,
> - .display_ops = &fimd_display_ops,
> + .type = EXYNOS_DISPLAY_TYPE_LCD,
> + .ops = &fimd_manager_ops,
> };
>
> static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
> {
> struct fimd_context *ctx = (struct fimd_context *)dev_id;
> - struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
> - struct exynos_drm_manager *manager = subdrv->manager;
> u32 val;
>
> val = readl(ctx->regs + VIDINTCON1);
> @@ -692,11 +722,11 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
> writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
>
> /* check the crtc is detached already from encoder */
> - if (manager->pipe < 0 || !ctx->drm_dev)
> + if (ctx->pipe < 0 || !ctx->drm_dev)
> goto out;
>
> - drm_handle_vblank(ctx->drm_dev, manager->pipe);
> - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
> + drm_handle_vblank(ctx->drm_dev, ctx->pipe);
> + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
>
> /* set wait vsync event to zero and wake up queue. */
> if (atomic_read(&ctx->wait_vsync_event)) {
> @@ -707,39 +737,6 @@ out:
> return IRQ_HANDLED;
> }
>
> -static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
> -{
> - /*
> - * enable drm irq mode.
> - * - with irq_enabled = 1, we can use the vblank feature.
> - *
> - * P.S. note that we wouldn't use drm irq handler but
> - * just specific driver own one instead because
> - * drm framework supports only one irq handler.
> - */
> - drm_dev->irq_enabled = 1;
> -
> - /*
> - * with vblank_disable_allowed = 1, vblank interrupt will be disabled
> - * by drm timer once a current process gives up ownership of
> - * vblank event.(after drm_vblank_put function is called)
> - */
> - drm_dev->vblank_disable_allowed = 1;
> -
> - /* attach this sub driver to iommu mapping if supported. */
> - if (is_drm_iommu_supported(drm_dev))
> - drm_iommu_attach_device(drm_dev, dev);
> -
> - return 0;
> -}
> -
> -static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
> -{
> - /* detach this sub driver from iommu mapping if supported. */
> - if (is_drm_iommu_supported(drm_dev))
> - drm_iommu_detach_device(drm_dev, dev);
> -}
> -
> static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
> {
> struct videomode *vm = &ctx->panel.vm;
> @@ -825,9 +822,8 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
> return 0;
> }
>
> -static void fimd_window_suspend(struct device *dev)
> +static void fimd_window_suspend(struct fimd_context *ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> struct fimd_win_data *win_data;
> int i;
>
> @@ -839,9 +835,8 @@ static void fimd_window_suspend(struct device *dev)
> fimd_wait_for_vblank(ctx);
> }
>
> -static void fimd_window_resume(struct device *dev)
> +static void fimd_window_resume(struct fimd_context *ctx)
> {
> - struct fimd_context *ctx = get_fimd_context(dev);
> struct fimd_win_data *win_data;
> int i;
>
> @@ -854,7 +849,6 @@ static void fimd_window_resume(struct device *dev)
>
> static int fimd_activate(struct fimd_context *ctx, bool enable)
> {
> - struct device *dev = ctx->subdrv.dev;
> if (enable) {
> int ret;
>
> @@ -866,11 +860,11 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
>
> /* if vblank was enabled status, enable it again. */
> if (test_and_clear_bit(0, &ctx->irq_flags))
> - fimd_enable_vblank(dev);
> + fimd_enable_vblank(ctx);
>
> - fimd_window_resume(dev);
> + fimd_window_resume(ctx);
> } else {
> - fimd_window_suspend(dev);
> + fimd_window_suspend(ctx);
>
> fimd_clock(ctx, false);
> ctx->suspended = true;
> @@ -907,7 +901,6 @@ static int fimd_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> struct fimd_context *ctx;
> - struct exynos_drm_subdrv *subdrv;
> struct resource *res;
> int win;
> int ret = -EINVAL;
> @@ -952,15 +945,6 @@ static int fimd_probe(struct platform_device *pdev)
> DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
> atomic_set(&ctx->wait_vsync_event, 0);
>
> - fimd_manager.ctx = ctx;
> -
> - subdrv = &ctx->subdrv;
> -
> - subdrv->dev = dev;
> - subdrv->manager = &fimd_manager;
> - subdrv->probe = fimd_subdrv_probe;
> - subdrv->remove = fimd_subdrv_remove;
> -
> mutex_init(&ctx->lock);
>
> platform_set_drvdata(pdev, ctx);
> @@ -971,7 +955,11 @@ static int fimd_probe(struct platform_device *pdev)
> for (win = 0; win < WINDOWS_NR; win++)
> fimd_clear_win(ctx, win);
>
> - exynos_drm_subdrv_register(subdrv);
> + fimd_manager.ctx = ctx;
> + exynos_drm_manager_register(&fimd_manager);
> +
> + fimd_display.ctx = ctx;
> + exynos_drm_display_register(&fimd_display);
>
> return 0;
> }
> @@ -981,7 +969,8 @@ static int fimd_remove(struct platform_device *pdev)
> struct device *dev = &pdev->dev;
> struct fimd_context *ctx = platform_get_drvdata(pdev);
>
> - exynos_drm_subdrv_unregister(&ctx->subdrv);
> + exynos_drm_display_unregister(&fimd_display);
> + exynos_drm_manager_unregister(&fimd_manager);
>
> if (ctx->suspended)
> goto out;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> index 8173e44..8fc9d6d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> @@ -24,14 +24,11 @@
> #include "exynos_drm_hdmi.h"
>
> #define to_context(dev) platform_get_drvdata(to_platform_device(dev))
> -#define to_subdrv(dev) to_context(dev)
> -#define get_ctx_from_subdrv(subdrv) container_of(subdrv,\
> - struct drm_hdmi_context, subdrv);
>
> /* 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.
> +/* 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;
> @@ -41,7 +38,6 @@ static struct exynos_hdmi_ops *hdmi_ops;
> static struct exynos_mixer_ops *mixer_ops;
>
> struct drm_hdmi_context {
> - struct exynos_drm_subdrv subdrv;
> struct exynos_drm_hdmi_context *hdmi_ctx;
> struct exynos_drm_hdmi_context *mixer_ctx;
>
> @@ -101,6 +97,12 @@ 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);
>
> @@ -118,6 +120,17 @@ static bool drm_hdmi_is_connected(void *in_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)
> {
> @@ -129,6 +142,16 @@ static struct edid *drm_hdmi_get_edid(void *in_ctx,
> 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;
> @@ -151,52 +174,6 @@ static int drm_hdmi_check_mode(void *in_ctx, struct drm_display_mode *mode)
> return 0;
> }
>
> -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 = {
> - .type = EXYNOS_DISPLAY_TYPE_HDMI,
> - .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,
> -};
> -
> -static int drm_hdmi_enable_vblank(void *in_ctx)
> -{
> - struct drm_hdmi_context *ctx = in_ctx;
> - struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
> - struct exynos_drm_manager *manager = subdrv->manager;
> -
> - if (mixer_ops && mixer_ops->enable_vblank)
> - return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
> - manager->pipe);
> -
> - return 0;
> -}
> -
> -static void drm_hdmi_disable_vblank(void *in_ctx)
> -{
> - struct drm_hdmi_context *ctx = in_ctx;
> -
> - 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_mode_fixup(void *in_ctx, struct drm_connector *connector,
> const struct drm_display_mode *mode,
> struct drm_display_mode *adjusted_mode)
> @@ -241,21 +218,57 @@ static void drm_hdmi_mode_fixup(void *in_ctx, struct drm_connector *connector,
> }
> }
>
> -static void drm_hdmi_mode_set(void *in_ctx, void *mode)
> +static void drm_hdmi_display_dpms(void *in_ctx, int mode)
> {
> struct drm_hdmi_context *ctx = in_ctx;
>
> - if (hdmi_ops && hdmi_ops->mode_set)
> - hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
> + if (hdmi_ops && hdmi_ops->dpms)
> + hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
> }
>
> -static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
> - unsigned int *height)
> +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 (hdmi_ops && hdmi_ops->get_max_resol)
> - hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
> + 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)
> @@ -266,11 +279,19 @@ static void drm_hdmi_commit(void *in_ctx)
> hdmi_ops->commit(ctx->hdmi_ctx->ctx);
> }
>
> -static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
> +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);
>
> @@ -280,6 +301,14 @@ static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
> 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;
> @@ -350,14 +379,12 @@ static void drm_mixer_win_disable(void *in_ctx, int zpos)
>
> 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,
> - .mode_fixup = drm_hdmi_mode_fixup,
> - .mode_set = drm_hdmi_mode_set,
> - .get_max_resol = drm_hdmi_get_max_resol,
> .commit = drm_hdmi_commit,
> .win_mode_set = drm_mixer_win_mode_set,
> .win_commit = drm_mixer_win_commit,
> @@ -365,82 +392,33 @@ static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
> };
>
> static struct exynos_drm_manager hdmi_manager = {
> - .pipe = -1,
> - .ops = &drm_hdmi_manager_ops,
> - .display_ops = &drm_hdmi_display_ops,
> + .type = EXYNOS_DISPLAY_TYPE_HDMI,
> + .ops = &drm_hdmi_manager_ops,
> };
>
> -static int hdmi_subdrv_probe(struct drm_device *drm_dev,
> - struct device *dev)
> -{
> - struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
> - struct drm_hdmi_context *ctx;
> -
> - 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 = get_ctx_from_subdrv(subdrv);
> -
> - if (!ctx) {
> - DRM_ERROR("no drm hdmi context.\n");
> - return -EFAULT;
> - }
> -
> - ctx->hdmi_ctx = hdmi_ctx;
> - ctx->mixer_ctx = mixer_ctx;
> -
> - return 0;
> -}
> -
> -static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
> -{
> - struct drm_hdmi_context *ctx;
> - struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
> -
> - ctx = get_ctx_from_subdrv(subdrv);
> -
> - if (mixer_ops->iommu_on)
> - mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
> -}
> -
> static int exynos_drm_hdmi_probe(struct platform_device *pdev)
> {
> - struct device *dev = &pdev->dev;
> - struct exynos_drm_subdrv *subdrv;
> struct drm_hdmi_context *ctx;
>
> - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
> if (!ctx)
> return -ENOMEM;
>
> hdmi_manager.ctx = ctx;
> + exynos_drm_manager_register(&hdmi_manager);
>
> - subdrv = &ctx->subdrv;
> -
> - subdrv->dev = dev;
> - subdrv->manager = &hdmi_manager;
> - subdrv->probe = hdmi_subdrv_probe;
> - subdrv->remove = hdmi_subdrv_remove;
> + hdmi_display.ctx = ctx;
> + exynos_drm_display_register(&hdmi_display);
>
> - platform_set_drvdata(pdev, subdrv);
> -
> - exynos_drm_subdrv_register(subdrv);
> + platform_set_drvdata(pdev, ctx);
>
> return 0;
> }
>
> static int exynos_drm_hdmi_remove(struct platform_device *pdev)
> {
> - struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
> -
> - exynos_drm_subdrv_unregister(&ctx->subdrv);
> + exynos_drm_display_unregister(&hdmi_display);
> + exynos_drm_manager_unregister(&hdmi_manager);
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
> index 923239b..37059ea 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
> @@ -19,10 +19,12 @@
> * 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;
> };
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
> index cff3aed..e0db2b3 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
> @@ -13,7 +13,7 @@
>
> #include <drm/exynos_drm.h>
> #include "exynos_drm_drv.h"
> -#include "exynos_drm_encoder.h"
> +#include "exynos_drm_crtc.h"
> #include "exynos_drm_fb.h"
> #include "exynos_drm_gem.h"
> #include "exynos_drm_plane.h"
> @@ -139,7 +139,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
> overlay->crtc_x, overlay->crtc_y,
> overlay->crtc_width, overlay->crtc_height);
>
> - exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);
> + exynos_drm_crtc_plane_mode_set(crtc, overlay);
>
> return 0;
> }
> @@ -149,8 +149,7 @@ void exynos_plane_commit(struct drm_plane *plane)
> struct exynos_plane *exynos_plane = to_exynos_plane(plane);
> struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
>
> - exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
> - exynos_drm_encoder_plane_commit);
> + exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
> }
>
> void exynos_plane_dpms(struct drm_plane *plane, int mode)
> @@ -162,17 +161,13 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
> if (exynos_plane->enabled)
> return;
>
> - exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
> - exynos_drm_encoder_plane_enable);
> -
> + exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
> exynos_plane->enabled = true;
> } else {
> if (!exynos_plane->enabled)
> return;
>
> - exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
> - exynos_drm_encoder_plane_disable);
> -
> + exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
> exynos_plane->enabled = false;
> }
> }
> --
> 1.8.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-14 15:24 ` Inki Dae
@ 2013-10-15 4:09 ` Inki Dae
2013-10-15 18:12 ` Sean Paul
0 siblings, 1 reply; 38+ messages in thread
From: Inki Dae @ 2013-10-15 4:09 UTC (permalink / raw)
To: Sean Paul; +Cc: Stéphane Marchesin, DRI mailing list
2013/10/15 Inki Dae <inki.dae@samsung.com>:
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> index c417c90..ba63c72 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> @@ -26,24 +26,23 @@
>> * exynos specific encoder structure.
>> *
>> * @drm_encoder: encoder object.
>> - * @manager: specific encoder has its own manager to control a hardware
>> - * appropriately and we can access a hardware drawing on this manager.
>> + * @display: the display structure that maps to this encoder
>> */
>> struct exynos_drm_encoder {
>> struct drm_crtc *old_crtc;
>> struct drm_encoder drm_encoder;
>> - struct exynos_drm_manager *manager;
>> + struct exynos_drm_display *display;
>> };
>>
>> static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
>> {
>> - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
>> - struct exynos_drm_display_ops *display_ops = manager->display_ops;
>> + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
>> + struct exynos_drm_display *display = exynos_encoder->display;
>>
>> DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
>>
>> - if (display_ops && display_ops->dpms)
>> - display_ops->dpms(manager->ctx, mode);
>> + if (display->ops->dpms)
>> + display->ops->dpms(display->ctx, mode);
>
> It's good to remove apply callback. However, it seems that this patch
> has a problem that dma channel of fimd isn't enabled after dpms goes
> from off to on. So can you implement win_enable callback of fimd, and
> add it to fimd_win_resume function? We should have implemented
> win_enable callback.
>
Plz, ignore the above comments, and see the below comments.
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> index 838c47d..f3dc808 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> @@ -105,7 +105,6 @@ struct fimd_win_data {
>> };
>>
>> struct fimd_context {
>> - struct exynos_drm_subdrv subdrv;
>> struct device *dev;
>> struct drm_device *drm_dev;
>> int irq;
>> @@ -120,6 +119,7 @@ struct fimd_context {
>> u32 vidcon0;
>> u32 vidcon1;
>> bool suspended;
>> + int pipe;
>> struct mutex lock;
>> wait_queue_head_t wait_vsync_queue;
>> atomic_t wait_vsync_event;
>> @@ -169,12 +169,16 @@ static int fimd_check_mode(void *in_ctx, struct drm_display_mode *mode)
>> }
>>
>> static struct exynos_drm_display_ops fimd_display_ops = {
>> - .type = EXYNOS_DISPLAY_TYPE_LCD,
>> .is_connected = fimd_display_is_connected,
>> .get_panel = fimd_get_panel,
>> .check_mode = fimd_check_mode,
>> };
>>
>> +static struct exynos_drm_display fimd_display = {
>> + .type = EXYNOS_DISPLAY_TYPE_LCD,
>> + .ops = &fimd_display_ops,
>> +};
>> +
>> static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
>> {
>> struct fimd_context *ctx = in_ctx;
>> @@ -481,15 +485,46 @@ static void fimd_win_disable(void *in_ctx, int zpos)
>> win_data->enabled = false;
>> }
>>
>> -static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
>> +static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev,
>> + int pipe)
>> {
>> struct fimd_context *ctx = in_ctx;
>>
>> ctx->drm_dev = drm_dev;
>> + ctx->pipe = pipe;
>> +
>> + /*
>> + * enable drm irq mode.
>> + * - with irq_enabled = 1, we can use the vblank feature.
>> + *
>> + * P.S. note that we wouldn't use drm irq handler but
>> + * just specific driver own one instead because
>> + * drm framework supports only one irq handler.
>> + */
>> + ctx->drm_dev->irq_enabled = 1;
>> +
>> + /*
>> + * with vblank_disable_allowed = 1, vblank interrupt will be disabled
>> + * by drm timer once a current process gives up ownership of
>> + * vblank event.(after drm_vblank_put function is called)
>> + */
>> + drm_dev->vblank_disable_allowed = 1;
>> +
>> + /* attach this sub driver to iommu mapping if supported. */
>> + if (is_drm_iommu_supported(ctx->drm_dev))
>> + drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
>>
>> return 0;
>> }
>>
>> +static void fimd_mgr_remove(void *in_ctx)
>> +{
>> + struct fimd_context *ctx = in_ctx;
>> +
>> + if (is_drm_iommu_supported(ctx->drm_dev))
>> + drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
>> +}
>> +
>> static void fimd_dpms(void *in_ctx, int mode)
>> {
>> struct fimd_context *ctx = in_ctx;
>> @@ -523,24 +558,6 @@ static void fimd_dpms(void *in_ctx, int mode)
>> mutex_unlock(&ctx->lock);
>> }
>>
>> -static void fimd_apply(void *in_ctx)
>> -{
>> - struct fimd_context *ctx = in_ctx;
>> - struct exynos_drm_manager *mgr = ctx->subdrv.manager;
>> - struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
>> - struct fimd_win_data *win_data;
>> - int i;
>> -
>> - for (i = 0; i < WINDOWS_NR; i++) {
>> - win_data = &ctx->win_data[i];
>> - if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
>> - mgr_ops->win_commit(ctx, i);
>> - }
>> -
>> - if (mgr_ops && mgr_ops->commit)
>> - mgr_ops->commit(ctx);
>> -}
>> -
>> static void fimd_commit(void *in_ctx)
>> {
>> struct fimd_context *ctx = in_ctx;
>> @@ -597,6 +614,21 @@ static void fimd_commit(void *in_ctx)
>> writel(val, ctx->regs + VIDCON0);
>> }
>>
>> +static void fimd_apply(void *in_ctx)
>> +{
>> + struct fimd_context *ctx = in_ctx;
>> + struct fimd_win_data *win_data;
>> + int i;
>> +
>> + for (i = 0; i < WINDOWS_NR; i++) {
>> + win_data = &ctx->win_data[i];
>> + if (win_data->enabled)
>> + fimd_win_commit(ctx, i);
Implement fimd_win_enable function and call it at here,
if (win_data->enabled) {
fimd_win_commit(ctx,i);
fimd_win_enable(ctx, i); <- here
}
And, the below codes, for enable overlay dma channel, should be
removed from fimd_win_commit function,
/* wincon */
val = readl(ctx->regs + WINCON(win));
val |= WINCONx_ENWIN;
writel(val, ctx->regs + WINCON(win));
And, with [PATCH v2] drm/exynos: fimd: clean up pm suspend/resume, it
must work well.
>> + }
>> +
>> + fimd_commit(ctx);
>> +}
>> +
>> static int fimd_enable_vblank(void *in_ctx)
>> {
>> struct fimd_context *ctx = in_ctx;
>> @@ -661,6 +693,7 @@ static void fimd_wait_for_vblank(void *in_ctx)
>>
>> static struct exynos_drm_manager_ops fimd_manager_ops = {
>> .initialize = fimd_mgr_initialize,
>> + .remove = fimd_mgr_remove,
>> .dpms = fimd_dpms,
>> .apply = fimd_apply,
>> .commit = fimd_commit,
>> @@ -673,16 +706,13 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
>> };
>>
>> static struct exynos_drm_manager fimd_manager = {
>> - .pipe = -1,
>> - .ops = &fimd_manager_ops,
>> - .display_ops = &fimd_display_ops,
>> + .type = EXYNOS_DISPLAY_TYPE_LCD,
>> + .ops = &fimd_manager_ops,
>> };
>>
>> static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
>> {
>> struct fimd_context *ctx = (struct fimd_context *)dev_id;
>> - struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
>> - struct exynos_drm_manager *manager = subdrv->manager;
>> u32 val;
>>
>> val = readl(ctx->regs + VIDINTCON1);
>> @@ -692,11 +722,11 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
>> writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
>>
>> /* check the crtc is detached already from encoder */
>> - if (manager->pipe < 0 || !ctx->drm_dev)
>> + if (ctx->pipe < 0 || !ctx->drm_dev)
>> goto out;
>>
>> - drm_handle_vblank(ctx->drm_dev, manager->pipe);
>> - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
>> + drm_handle_vblank(ctx->drm_dev, ctx->pipe);
>> + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
>>
>> /* set wait vsync event to zero and wake up queue. */
>> if (atomic_read(&ctx->wait_vsync_event)) {
>> @@ -707,39 +737,6 @@ out:
>> return IRQ_HANDLED;
>> }
>>
>> -static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
>> -{
>> - /*
>> - * enable drm irq mode.
>> - * - with irq_enabled = 1, we can use the vblank feature.
>> - *
>> - * P.S. note that we wouldn't use drm irq handler but
>> - * just specific driver own one instead because
>> - * drm framework supports only one irq handler.
>> - */
>> - drm_dev->irq_enabled = 1;
>> -
>> - /*
>> - * with vblank_disable_allowed = 1, vblank interrupt will be disabled
>> - * by drm timer once a current process gives up ownership of
>> - * vblank event.(after drm_vblank_put function is called)
>> - */
>> - drm_dev->vblank_disable_allowed = 1;
>> -
>> - /* attach this sub driver to iommu mapping if supported. */
>> - if (is_drm_iommu_supported(drm_dev))
>> - drm_iommu_attach_device(drm_dev, dev);
>> -
>> - return 0;
>> -}
>> -
>> -static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
>> -{
>> - /* detach this sub driver from iommu mapping if supported. */
>> - if (is_drm_iommu_supported(drm_dev))
>> - drm_iommu_detach_device(drm_dev, dev);
>> -}
>> -
>> static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
>> {
>> struct videomode *vm = &ctx->panel.vm;
>> @@ -825,9 +822,8 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
>> return 0;
>> }
>>
>> -static void fimd_window_suspend(struct device *dev)
>> +static void fimd_window_suspend(struct fimd_context *ctx)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> struct fimd_win_data *win_data;
>> int i;
>>
>> @@ -839,9 +835,8 @@ static void fimd_window_suspend(struct device *dev)
>> fimd_wait_for_vblank(ctx);
>> }
>>
>> -static void fimd_window_resume(struct device *dev)
>> +static void fimd_window_resume(struct fimd_context *ctx)
>> {
>> - struct fimd_context *ctx = get_fimd_context(dev);
>> struct fimd_win_data *win_data;
>> int i;
>>
>> @@ -854,7 +849,6 @@ static void fimd_window_resume(struct device *dev)
>>
>> static int fimd_activate(struct fimd_context *ctx, bool enable)
>> {
>> - struct device *dev = ctx->subdrv.dev;
>> if (enable) {
>> int ret;
>>
>> @@ -866,11 +860,11 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
>>
>> /* if vblank was enabled status, enable it again. */
>> if (test_and_clear_bit(0, &ctx->irq_flags))
>> - fimd_enable_vblank(dev);
>> + fimd_enable_vblank(ctx);
>>
>> - fimd_window_resume(dev);
>> + fimd_window_resume(ctx);
>> } else {
>> - fimd_window_suspend(dev);
>> + fimd_window_suspend(ctx);
>>
>> fimd_clock(ctx, false);
>> ctx->suspended = true;
>> @@ -907,7 +901,6 @@ static int fimd_probe(struct platform_device *pdev)
>> {
>> struct device *dev = &pdev->dev;
>> struct fimd_context *ctx;
>> - struct exynos_drm_subdrv *subdrv;
>> struct resource *res;
>> int win;
>> int ret = -EINVAL;
>> @@ -952,15 +945,6 @@ static int fimd_probe(struct platform_device *pdev)
>> DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
>> atomic_set(&ctx->wait_vsync_event, 0);
>>
>> - fimd_manager.ctx = ctx;
>> -
>> - subdrv = &ctx->subdrv;
>> -
>> - subdrv->dev = dev;
>> - subdrv->manager = &fimd_manager;
>> - subdrv->probe = fimd_subdrv_probe;
>> - subdrv->remove = fimd_subdrv_remove;
>> -
>> mutex_init(&ctx->lock);
>>
>> platform_set_drvdata(pdev, ctx);
>> @@ -971,7 +955,11 @@ static int fimd_probe(struct platform_device *pdev)
>> for (win = 0; win < WINDOWS_NR; win++)
>> fimd_clear_win(ctx, win);
>>
>> - exynos_drm_subdrv_register(subdrv);
>> + fimd_manager.ctx = ctx;
>> + exynos_drm_manager_register(&fimd_manager);
>> +
>> + fimd_display.ctx = ctx;
>> + exynos_drm_display_register(&fimd_display);
>>
>> return 0;
>> }
>> @@ -981,7 +969,8 @@ static int fimd_remove(struct platform_device *pdev)
>> struct device *dev = &pdev->dev;
>> struct fimd_context *ctx = platform_get_drvdata(pdev);
>>
>> - exynos_drm_subdrv_unregister(&ctx->subdrv);
>> + exynos_drm_display_unregister(&fimd_display);
>> + exynos_drm_manager_unregister(&fimd_manager);
>>
>> if (ctx->suspended)
>> goto out;
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-15 4:09 ` Inki Dae
@ 2013-10-15 18:12 ` Sean Paul
2013-10-16 2:17 ` Inki Dae
0 siblings, 1 reply; 38+ messages in thread
From: Sean Paul @ 2013-10-15 18:12 UTC (permalink / raw)
To: Inki Dae; +Cc: Stéphane Marchesin, DRI mailing list
On Tue, Oct 15, 2013 at 12:09 AM, Inki Dae <inki.dae@samsung.com> wrote:
> 2013/10/15 Inki Dae <inki.dae@samsung.com>:
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>> index c417c90..ba63c72 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>> @@ -26,24 +26,23 @@
>>> * exynos specific encoder structure.
>>> *
>>> * @drm_encoder: encoder object.
>>> - * @manager: specific encoder has its own manager to control a hardware
>>> - * appropriately and we can access a hardware drawing on this manager.
>>> + * @display: the display structure that maps to this encoder
>>> */
>>> struct exynos_drm_encoder {
>>> struct drm_crtc *old_crtc;
>>> struct drm_encoder drm_encoder;
>>> - struct exynos_drm_manager *manager;
>>> + struct exynos_drm_display *display;
>>> };
>>>
>>> static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
>>> {
>>> - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
>>> - struct exynos_drm_display_ops *display_ops = manager->display_ops;
>>> + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
>>> + struct exynos_drm_display *display = exynos_encoder->display;
>>>
>>> DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
>>>
>>> - if (display_ops && display_ops->dpms)
>>> - display_ops->dpms(manager->ctx, mode);
>>> + if (display->ops->dpms)
>>> + display->ops->dpms(display->ctx, mode);
>>
>> It's good to remove apply callback. However, it seems that this patch
>> has a problem that dma channel of fimd isn't enabled after dpms goes
>> from off to on. So can you implement win_enable callback of fimd, and
>> add it to fimd_win_resume function? We should have implemented
>> win_enable callback.
>>
>
> Plz, ignore the above comments, and see the below comments.
>
>
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>> index 838c47d..f3dc808 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>> @@ -105,7 +105,6 @@ struct fimd_win_data {
>>> };
>>>
>>> struct fimd_context {
>>> - struct exynos_drm_subdrv subdrv;
>>> struct device *dev;
>>> struct drm_device *drm_dev;
>>> int irq;
>>> @@ -120,6 +119,7 @@ struct fimd_context {
>>> u32 vidcon0;
>>> u32 vidcon1;
>>> bool suspended;
>>> + int pipe;
>>> struct mutex lock;
>>> wait_queue_head_t wait_vsync_queue;
>>> atomic_t wait_vsync_event;
>>> @@ -169,12 +169,16 @@ static int fimd_check_mode(void *in_ctx, struct drm_display_mode *mode)
>>> }
>>>
>>> static struct exynos_drm_display_ops fimd_display_ops = {
>>> - .type = EXYNOS_DISPLAY_TYPE_LCD,
>>> .is_connected = fimd_display_is_connected,
>>> .get_panel = fimd_get_panel,
>>> .check_mode = fimd_check_mode,
>>> };
>>>
>>> +static struct exynos_drm_display fimd_display = {
>>> + .type = EXYNOS_DISPLAY_TYPE_LCD,
>>> + .ops = &fimd_display_ops,
>>> +};
>>> +
>>> static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
>>> {
>>> struct fimd_context *ctx = in_ctx;
>>> @@ -481,15 +485,46 @@ static void fimd_win_disable(void *in_ctx, int zpos)
>>> win_data->enabled = false;
>>> }
>>>
>>> -static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
>>> +static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev,
>>> + int pipe)
>>> {
>>> struct fimd_context *ctx = in_ctx;
>>>
>>> ctx->drm_dev = drm_dev;
>>> + ctx->pipe = pipe;
>>> +
>>> + /*
>>> + * enable drm irq mode.
>>> + * - with irq_enabled = 1, we can use the vblank feature.
>>> + *
>>> + * P.S. note that we wouldn't use drm irq handler but
>>> + * just specific driver own one instead because
>>> + * drm framework supports only one irq handler.
>>> + */
>>> + ctx->drm_dev->irq_enabled = 1;
>>> +
>>> + /*
>>> + * with vblank_disable_allowed = 1, vblank interrupt will be disabled
>>> + * by drm timer once a current process gives up ownership of
>>> + * vblank event.(after drm_vblank_put function is called)
>>> + */
>>> + drm_dev->vblank_disable_allowed = 1;
>>> +
>>> + /* attach this sub driver to iommu mapping if supported. */
>>> + if (is_drm_iommu_supported(ctx->drm_dev))
>>> + drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
>>>
>>> return 0;
>>> }
>>>
>>> +static void fimd_mgr_remove(void *in_ctx)
>>> +{
>>> + struct fimd_context *ctx = in_ctx;
>>> +
>>> + if (is_drm_iommu_supported(ctx->drm_dev))
>>> + drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
>>> +}
>>> +
>>> static void fimd_dpms(void *in_ctx, int mode)
>>> {
>>> struct fimd_context *ctx = in_ctx;
>>> @@ -523,24 +558,6 @@ static void fimd_dpms(void *in_ctx, int mode)
>>> mutex_unlock(&ctx->lock);
>>> }
>>>
>>> -static void fimd_apply(void *in_ctx)
>>> -{
>>> - struct fimd_context *ctx = in_ctx;
>>> - struct exynos_drm_manager *mgr = ctx->subdrv.manager;
>>> - struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
>>> - struct fimd_win_data *win_data;
>>> - int i;
>>> -
>>> - for (i = 0; i < WINDOWS_NR; i++) {
>>> - win_data = &ctx->win_data[i];
>>> - if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
>>> - mgr_ops->win_commit(ctx, i);
>>> - }
>>> -
>>> - if (mgr_ops && mgr_ops->commit)
>>> - mgr_ops->commit(ctx);
>>> -}
>>> -
>>> static void fimd_commit(void *in_ctx)
>>> {
>>> struct fimd_context *ctx = in_ctx;
>>> @@ -597,6 +614,21 @@ static void fimd_commit(void *in_ctx)
>>> writel(val, ctx->regs + VIDCON0);
>>> }
>>>
>>> +static void fimd_apply(void *in_ctx)
>>> +{
>>> + struct fimd_context *ctx = in_ctx;
>>> + struct fimd_win_data *win_data;
>>> + int i;
>>> +
>>> + for (i = 0; i < WINDOWS_NR; i++) {
>>> + win_data = &ctx->win_data[i];
>>> + if (win_data->enabled)
>>> + fimd_win_commit(ctx, i);
>
> Implement fimd_win_enable function and call it at here,
>
> if (win_data->enabled) {
> fimd_win_commit(ctx,i);
> fimd_win_enable(ctx, i); <- here
> }
>
> And, the below codes, for enable overlay dma channel, should be
> removed from fimd_win_commit function,
>
> /* wincon */
> val = readl(ctx->regs + WINCON(win));
> val |= WINCONx_ENWIN;
> writel(val, ctx->regs + WINCON(win));
>
I'm not sure I follow why you want this done here. It seems unrelated
to this patch.
>
> And, with [PATCH v2] drm/exynos: fimd: clean up pm suspend/resume, it
> must work well.
I've got a patch to remove all of the
suspend/resume/pm_suspend/pm_resume stuff from all of the individual
drivers and do everything through dpms. This will eliminate the error
modes where the dpms state in the upper layers get out of sync with
the actual state of the hardware. It's also more consistent with other
drm drivers. I'll post it after this set.
Sean
>
>>> + }
>>> +
>>> + fimd_commit(ctx);
>>> +}
>>> +
>>> static int fimd_enable_vblank(void *in_ctx)
>>> {
>>> struct fimd_context *ctx = in_ctx;
>>> @@ -661,6 +693,7 @@ static void fimd_wait_for_vblank(void *in_ctx)
>>>
>>> static struct exynos_drm_manager_ops fimd_manager_ops = {
>>> .initialize = fimd_mgr_initialize,
>>> + .remove = fimd_mgr_remove,
>>> .dpms = fimd_dpms,
>>> .apply = fimd_apply,
>>> .commit = fimd_commit,
>>> @@ -673,16 +706,13 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
>>> };
>>>
>>> static struct exynos_drm_manager fimd_manager = {
>>> - .pipe = -1,
>>> - .ops = &fimd_manager_ops,
>>> - .display_ops = &fimd_display_ops,
>>> + .type = EXYNOS_DISPLAY_TYPE_LCD,
>>> + .ops = &fimd_manager_ops,
>>> };
>>>
>>> static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
>>> {
>>> struct fimd_context *ctx = (struct fimd_context *)dev_id;
>>> - struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
>>> - struct exynos_drm_manager *manager = subdrv->manager;
>>> u32 val;
>>>
>>> val = readl(ctx->regs + VIDINTCON1);
>>> @@ -692,11 +722,11 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
>>> writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
>>>
>>> /* check the crtc is detached already from encoder */
>>> - if (manager->pipe < 0 || !ctx->drm_dev)
>>> + if (ctx->pipe < 0 || !ctx->drm_dev)
>>> goto out;
>>>
>>> - drm_handle_vblank(ctx->drm_dev, manager->pipe);
>>> - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
>>> + drm_handle_vblank(ctx->drm_dev, ctx->pipe);
>>> + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
>>>
>>> /* set wait vsync event to zero and wake up queue. */
>>> if (atomic_read(&ctx->wait_vsync_event)) {
>>> @@ -707,39 +737,6 @@ out:
>>> return IRQ_HANDLED;
>>> }
>>>
>>> -static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
>>> -{
>>> - /*
>>> - * enable drm irq mode.
>>> - * - with irq_enabled = 1, we can use the vblank feature.
>>> - *
>>> - * P.S. note that we wouldn't use drm irq handler but
>>> - * just specific driver own one instead because
>>> - * drm framework supports only one irq handler.
>>> - */
>>> - drm_dev->irq_enabled = 1;
>>> -
>>> - /*
>>> - * with vblank_disable_allowed = 1, vblank interrupt will be disabled
>>> - * by drm timer once a current process gives up ownership of
>>> - * vblank event.(after drm_vblank_put function is called)
>>> - */
>>> - drm_dev->vblank_disable_allowed = 1;
>>> -
>>> - /* attach this sub driver to iommu mapping if supported. */
>>> - if (is_drm_iommu_supported(drm_dev))
>>> - drm_iommu_attach_device(drm_dev, dev);
>>> -
>>> - return 0;
>>> -}
>>> -
>>> -static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
>>> -{
>>> - /* detach this sub driver from iommu mapping if supported. */
>>> - if (is_drm_iommu_supported(drm_dev))
>>> - drm_iommu_detach_device(drm_dev, dev);
>>> -}
>>> -
>>> static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
>>> {
>>> struct videomode *vm = &ctx->panel.vm;
>>> @@ -825,9 +822,8 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
>>> return 0;
>>> }
>>>
>>> -static void fimd_window_suspend(struct device *dev)
>>> +static void fimd_window_suspend(struct fimd_context *ctx)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> struct fimd_win_data *win_data;
>>> int i;
>>>
>>> @@ -839,9 +835,8 @@ static void fimd_window_suspend(struct device *dev)
>>> fimd_wait_for_vblank(ctx);
>>> }
>>>
>>> -static void fimd_window_resume(struct device *dev)
>>> +static void fimd_window_resume(struct fimd_context *ctx)
>>> {
>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>> struct fimd_win_data *win_data;
>>> int i;
>>>
>>> @@ -854,7 +849,6 @@ static void fimd_window_resume(struct device *dev)
>>>
>>> static int fimd_activate(struct fimd_context *ctx, bool enable)
>>> {
>>> - struct device *dev = ctx->subdrv.dev;
>>> if (enable) {
>>> int ret;
>>>
>>> @@ -866,11 +860,11 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
>>>
>>> /* if vblank was enabled status, enable it again. */
>>> if (test_and_clear_bit(0, &ctx->irq_flags))
>>> - fimd_enable_vblank(dev);
>>> + fimd_enable_vblank(ctx);
>>>
>>> - fimd_window_resume(dev);
>>> + fimd_window_resume(ctx);
>>> } else {
>>> - fimd_window_suspend(dev);
>>> + fimd_window_suspend(ctx);
>>>
>>> fimd_clock(ctx, false);
>>> ctx->suspended = true;
>>> @@ -907,7 +901,6 @@ static int fimd_probe(struct platform_device *pdev)
>>> {
>>> struct device *dev = &pdev->dev;
>>> struct fimd_context *ctx;
>>> - struct exynos_drm_subdrv *subdrv;
>>> struct resource *res;
>>> int win;
>>> int ret = -EINVAL;
>>> @@ -952,15 +945,6 @@ static int fimd_probe(struct platform_device *pdev)
>>> DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
>>> atomic_set(&ctx->wait_vsync_event, 0);
>>>
>>> - fimd_manager.ctx = ctx;
>>> -
>>> - subdrv = &ctx->subdrv;
>>> -
>>> - subdrv->dev = dev;
>>> - subdrv->manager = &fimd_manager;
>>> - subdrv->probe = fimd_subdrv_probe;
>>> - subdrv->remove = fimd_subdrv_remove;
>>> -
>>> mutex_init(&ctx->lock);
>>>
>>> platform_set_drvdata(pdev, ctx);
>>> @@ -971,7 +955,11 @@ static int fimd_probe(struct platform_device *pdev)
>>> for (win = 0; win < WINDOWS_NR; win++)
>>> fimd_clear_win(ctx, win);
>>>
>>> - exynos_drm_subdrv_register(subdrv);
>>> + fimd_manager.ctx = ctx;
>>> + exynos_drm_manager_register(&fimd_manager);
>>> +
>>> + fimd_display.ctx = ctx;
>>> + exynos_drm_display_register(&fimd_display);
>>>
>>> return 0;
>>> }
>>> @@ -981,7 +969,8 @@ static int fimd_remove(struct platform_device *pdev)
>>> struct device *dev = &pdev->dev;
>>> struct fimd_context *ctx = platform_get_drvdata(pdev);
>>>
>>> - exynos_drm_subdrv_unregister(&ctx->subdrv);
>>> + exynos_drm_display_unregister(&fimd_display);
>>> + exynos_drm_manager_unregister(&fimd_manager);
>>>
>>> if (ctx->suspended)
>>> goto out;
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 12/23] drm/exynos: Split manager/display/subdrv
2013-10-15 18:12 ` Sean Paul
@ 2013-10-16 2:17 ` Inki Dae
0 siblings, 0 replies; 38+ messages in thread
From: Inki Dae @ 2013-10-16 2:17 UTC (permalink / raw)
To: Sean Paul; +Cc: Stéphane Marchesin, DRI mailing list
2013/10/16 Sean Paul <seanpaul@chromium.org>:
> On Tue, Oct 15, 2013 at 12:09 AM, Inki Dae <inki.dae@samsung.com> wrote:
>> 2013/10/15 Inki Dae <inki.dae@samsung.com>:
>>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>>> index c417c90..ba63c72 100644
>>>> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>>> @@ -26,24 +26,23 @@
>>>> * exynos specific encoder structure.
>>>> *
>>>> * @drm_encoder: encoder object.
>>>> - * @manager: specific encoder has its own manager to control a hardware
>>>> - * appropriately and we can access a hardware drawing on this manager.
>>>> + * @display: the display structure that maps to this encoder
>>>> */
>>>> struct exynos_drm_encoder {
>>>> struct drm_crtc *old_crtc;
>>>> struct drm_encoder drm_encoder;
>>>> - struct exynos_drm_manager *manager;
>>>> + struct exynos_drm_display *display;
>>>> };
>>>>
>>>> static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
>>>> {
>>>> - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
>>>> - struct exynos_drm_display_ops *display_ops = manager->display_ops;
>>>> + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
>>>> + struct exynos_drm_display *display = exynos_encoder->display;
>>>>
>>>> DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
>>>>
>>>> - if (display_ops && display_ops->dpms)
>>>> - display_ops->dpms(manager->ctx, mode);
>>>> + if (display->ops->dpms)
>>>> + display->ops->dpms(display->ctx, mode);
>>>
>>> It's good to remove apply callback. However, it seems that this patch
>>> has a problem that dma channel of fimd isn't enabled after dpms goes
>>> from off to on. So can you implement win_enable callback of fimd, and
>>> add it to fimd_win_resume function? We should have implemented
>>> win_enable callback.
>>>
>>
>> Plz, ignore the above comments, and see the below comments.
>>
>>
>>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>>> index 838c47d..f3dc808 100644
>>>> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>>> @@ -105,7 +105,6 @@ struct fimd_win_data {
>>>> };
>>>>
>>>> struct fimd_context {
>>>> - struct exynos_drm_subdrv subdrv;
>>>> struct device *dev;
>>>> struct drm_device *drm_dev;
>>>> int irq;
>>>> @@ -120,6 +119,7 @@ struct fimd_context {
>>>> u32 vidcon0;
>>>> u32 vidcon1;
>>>> bool suspended;
>>>> + int pipe;
>>>> struct mutex lock;
>>>> wait_queue_head_t wait_vsync_queue;
>>>> atomic_t wait_vsync_event;
>>>> @@ -169,12 +169,16 @@ static int fimd_check_mode(void *in_ctx, struct drm_display_mode *mode)
>>>> }
>>>>
>>>> static struct exynos_drm_display_ops fimd_display_ops = {
>>>> - .type = EXYNOS_DISPLAY_TYPE_LCD,
>>>> .is_connected = fimd_display_is_connected,
>>>> .get_panel = fimd_get_panel,
>>>> .check_mode = fimd_check_mode,
>>>> };
>>>>
>>>> +static struct exynos_drm_display fimd_display = {
>>>> + .type = EXYNOS_DISPLAY_TYPE_LCD,
>>>> + .ops = &fimd_display_ops,
>>>> +};
>>>> +
>>>> static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
>>>> {
>>>> struct fimd_context *ctx = in_ctx;
>>>> @@ -481,15 +485,46 @@ static void fimd_win_disable(void *in_ctx, int zpos)
>>>> win_data->enabled = false;
>>>> }
>>>>
>>>> -static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
>>>> +static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev,
>>>> + int pipe)
>>>> {
>>>> struct fimd_context *ctx = in_ctx;
>>>>
>>>> ctx->drm_dev = drm_dev;
>>>> + ctx->pipe = pipe;
>>>> +
>>>> + /*
>>>> + * enable drm irq mode.
>>>> + * - with irq_enabled = 1, we can use the vblank feature.
>>>> + *
>>>> + * P.S. note that we wouldn't use drm irq handler but
>>>> + * just specific driver own one instead because
>>>> + * drm framework supports only one irq handler.
>>>> + */
>>>> + ctx->drm_dev->irq_enabled = 1;
>>>> +
>>>> + /*
>>>> + * with vblank_disable_allowed = 1, vblank interrupt will be disabled
>>>> + * by drm timer once a current process gives up ownership of
>>>> + * vblank event.(after drm_vblank_put function is called)
>>>> + */
>>>> + drm_dev->vblank_disable_allowed = 1;
>>>> +
>>>> + /* attach this sub driver to iommu mapping if supported. */
>>>> + if (is_drm_iommu_supported(ctx->drm_dev))
>>>> + drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
>>>>
>>>> return 0;
>>>> }
>>>>
>>>> +static void fimd_mgr_remove(void *in_ctx)
>>>> +{
>>>> + struct fimd_context *ctx = in_ctx;
>>>> +
>>>> + if (is_drm_iommu_supported(ctx->drm_dev))
>>>> + drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
>>>> +}
>>>> +
>>>> static void fimd_dpms(void *in_ctx, int mode)
>>>> {
>>>> struct fimd_context *ctx = in_ctx;
>>>> @@ -523,24 +558,6 @@ static void fimd_dpms(void *in_ctx, int mode)
>>>> mutex_unlock(&ctx->lock);
>>>> }
>>>>
>>>> -static void fimd_apply(void *in_ctx)
>>>> -{
>>>> - struct fimd_context *ctx = in_ctx;
>>>> - struct exynos_drm_manager *mgr = ctx->subdrv.manager;
>>>> - struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
>>>> - struct fimd_win_data *win_data;
>>>> - int i;
>>>> -
>>>> - for (i = 0; i < WINDOWS_NR; i++) {
>>>> - win_data = &ctx->win_data[i];
>>>> - if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
>>>> - mgr_ops->win_commit(ctx, i);
>>>> - }
>>>> -
>>>> - if (mgr_ops && mgr_ops->commit)
>>>> - mgr_ops->commit(ctx);
>>>> -}
>>>> -
>>>> static void fimd_commit(void *in_ctx)
>>>> {
>>>> struct fimd_context *ctx = in_ctx;
>>>> @@ -597,6 +614,21 @@ static void fimd_commit(void *in_ctx)
>>>> writel(val, ctx->regs + VIDCON0);
>>>> }
>>>>
>>>> +static void fimd_apply(void *in_ctx)
>>>> +{
>>>> + struct fimd_context *ctx = in_ctx;
>>>> + struct fimd_win_data *win_data;
>>>> + int i;
>>>> +
>>>> + for (i = 0; i < WINDOWS_NR; i++) {
>>>> + win_data = &ctx->win_data[i];
>>>> + if (win_data->enabled)
>>>> + fimd_win_commit(ctx, i);
>>
>> Implement fimd_win_enable function and call it at here,
>>
>> if (win_data->enabled) {
>> fimd_win_commit(ctx,i);
>> fimd_win_enable(ctx, i); <- here
>> }
>>
>> And, the below codes, for enable overlay dma channel, should be
>> removed from fimd_win_commit function,
>>
>> /* wincon */
>> val = readl(ctx->regs + WINCON(win));
>> val |= WINCONx_ENWIN;
>> writel(val, ctx->regs + WINCON(win));
>>
>
> I'm not sure I follow why you want this done here. It seems unrelated
> to this patch.
>
Yes, it's unrelated to this patch. I mean additional work.
>>
>> And, with [PATCH v2] drm/exynos: fimd: clean up pm suspend/resume, it
>> must work well.
>
>
> I've got a patch to remove all of the
> suspend/resume/pm_suspend/pm_resume stuff from all of the individual
> drivers and do everything through dpms. This will eliminate the error
> modes where the dpms state in the upper layers get out of sync with
> the actual state of the hardware. It's also more consistent with other
> drm drivers. I'll post it after this set.
>
It seems like more clear if we _can_do_ so. However, can the dpms be
called when entering sleep? And I think this way - removing all pm
related stuff from device drivers - is not reasonable, and we'd need
more discussion about that with pm people. So add the related patch
set at top of your re-factoring patch set if you want to do so.
Thanks,
Inki Dae
> Sean
>
>>
>>>> + }
>>>> +
>>>> + fimd_commit(ctx);
>>>> +}
>>>> +
>>>> static int fimd_enable_vblank(void *in_ctx)
>>>> {
>>>> struct fimd_context *ctx = in_ctx;
>>>> @@ -661,6 +693,7 @@ static void fimd_wait_for_vblank(void *in_ctx)
>>>>
>>>> static struct exynos_drm_manager_ops fimd_manager_ops = {
>>>> .initialize = fimd_mgr_initialize,
>>>> + .remove = fimd_mgr_remove,
>>>> .dpms = fimd_dpms,
>>>> .apply = fimd_apply,
>>>> .commit = fimd_commit,
>>>> @@ -673,16 +706,13 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
>>>> };
>>>>
>>>> static struct exynos_drm_manager fimd_manager = {
>>>> - .pipe = -1,
>>>> - .ops = &fimd_manager_ops,
>>>> - .display_ops = &fimd_display_ops,
>>>> + .type = EXYNOS_DISPLAY_TYPE_LCD,
>>>> + .ops = &fimd_manager_ops,
>>>> };
>>>>
>>>> static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
>>>> {
>>>> struct fimd_context *ctx = (struct fimd_context *)dev_id;
>>>> - struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
>>>> - struct exynos_drm_manager *manager = subdrv->manager;
>>>> u32 val;
>>>>
>>>> val = readl(ctx->regs + VIDINTCON1);
>>>> @@ -692,11 +722,11 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
>>>> writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
>>>>
>>>> /* check the crtc is detached already from encoder */
>>>> - if (manager->pipe < 0 || !ctx->drm_dev)
>>>> + if (ctx->pipe < 0 || !ctx->drm_dev)
>>>> goto out;
>>>>
>>>> - drm_handle_vblank(ctx->drm_dev, manager->pipe);
>>>> - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
>>>> + drm_handle_vblank(ctx->drm_dev, ctx->pipe);
>>>> + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
>>>>
>>>> /* set wait vsync event to zero and wake up queue. */
>>>> if (atomic_read(&ctx->wait_vsync_event)) {
>>>> @@ -707,39 +737,6 @@ out:
>>>> return IRQ_HANDLED;
>>>> }
>>>>
>>>> -static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
>>>> -{
>>>> - /*
>>>> - * enable drm irq mode.
>>>> - * - with irq_enabled = 1, we can use the vblank feature.
>>>> - *
>>>> - * P.S. note that we wouldn't use drm irq handler but
>>>> - * just specific driver own one instead because
>>>> - * drm framework supports only one irq handler.
>>>> - */
>>>> - drm_dev->irq_enabled = 1;
>>>> -
>>>> - /*
>>>> - * with vblank_disable_allowed = 1, vblank interrupt will be disabled
>>>> - * by drm timer once a current process gives up ownership of
>>>> - * vblank event.(after drm_vblank_put function is called)
>>>> - */
>>>> - drm_dev->vblank_disable_allowed = 1;
>>>> -
>>>> - /* attach this sub driver to iommu mapping if supported. */
>>>> - if (is_drm_iommu_supported(drm_dev))
>>>> - drm_iommu_attach_device(drm_dev, dev);
>>>> -
>>>> - return 0;
>>>> -}
>>>> -
>>>> -static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
>>>> -{
>>>> - /* detach this sub driver from iommu mapping if supported. */
>>>> - if (is_drm_iommu_supported(drm_dev))
>>>> - drm_iommu_detach_device(drm_dev, dev);
>>>> -}
>>>> -
>>>> static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
>>>> {
>>>> struct videomode *vm = &ctx->panel.vm;
>>>> @@ -825,9 +822,8 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
>>>> return 0;
>>>> }
>>>>
>>>> -static void fimd_window_suspend(struct device *dev)
>>>> +static void fimd_window_suspend(struct fimd_context *ctx)
>>>> {
>>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>>> struct fimd_win_data *win_data;
>>>> int i;
>>>>
>>>> @@ -839,9 +835,8 @@ static void fimd_window_suspend(struct device *dev)
>>>> fimd_wait_for_vblank(ctx);
>>>> }
>>>>
>>>> -static void fimd_window_resume(struct device *dev)
>>>> +static void fimd_window_resume(struct fimd_context *ctx)
>>>> {
>>>> - struct fimd_context *ctx = get_fimd_context(dev);
>>>> struct fimd_win_data *win_data;
>>>> int i;
>>>>
>>>> @@ -854,7 +849,6 @@ static void fimd_window_resume(struct device *dev)
>>>>
>>>> static int fimd_activate(struct fimd_context *ctx, bool enable)
>>>> {
>>>> - struct device *dev = ctx->subdrv.dev;
>>>> if (enable) {
>>>> int ret;
>>>>
>>>> @@ -866,11 +860,11 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
>>>>
>>>> /* if vblank was enabled status, enable it again. */
>>>> if (test_and_clear_bit(0, &ctx->irq_flags))
>>>> - fimd_enable_vblank(dev);
>>>> + fimd_enable_vblank(ctx);
>>>>
>>>> - fimd_window_resume(dev);
>>>> + fimd_window_resume(ctx);
>>>> } else {
>>>> - fimd_window_suspend(dev);
>>>> + fimd_window_suspend(ctx);
>>>>
>>>> fimd_clock(ctx, false);
>>>> ctx->suspended = true;
>>>> @@ -907,7 +901,6 @@ static int fimd_probe(struct platform_device *pdev)
>>>> {
>>>> struct device *dev = &pdev->dev;
>>>> struct fimd_context *ctx;
>>>> - struct exynos_drm_subdrv *subdrv;
>>>> struct resource *res;
>>>> int win;
>>>> int ret = -EINVAL;
>>>> @@ -952,15 +945,6 @@ static int fimd_probe(struct platform_device *pdev)
>>>> DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
>>>> atomic_set(&ctx->wait_vsync_event, 0);
>>>>
>>>> - fimd_manager.ctx = ctx;
>>>> -
>>>> - subdrv = &ctx->subdrv;
>>>> -
>>>> - subdrv->dev = dev;
>>>> - subdrv->manager = &fimd_manager;
>>>> - subdrv->probe = fimd_subdrv_probe;
>>>> - subdrv->remove = fimd_subdrv_remove;
>>>> -
>>>> mutex_init(&ctx->lock);
>>>>
>>>> platform_set_drvdata(pdev, ctx);
>>>> @@ -971,7 +955,11 @@ static int fimd_probe(struct platform_device *pdev)
>>>> for (win = 0; win < WINDOWS_NR; win++)
>>>> fimd_clear_win(ctx, win);
>>>>
>>>> - exynos_drm_subdrv_register(subdrv);
>>>> + fimd_manager.ctx = ctx;
>>>> + exynos_drm_manager_register(&fimd_manager);
>>>> +
>>>> + fimd_display.ctx = ctx;
>>>> + exynos_drm_display_register(&fimd_display);
>>>>
>>>> return 0;
>>>> }
>>>> @@ -981,7 +969,8 @@ static int fimd_remove(struct platform_device *pdev)
>>>> struct device *dev = &pdev->dev;
>>>> struct fimd_context *ctx = platform_get_drvdata(pdev);
>>>>
>>>> - exynos_drm_subdrv_unregister(&ctx->subdrv);
>>>> + exynos_drm_display_unregister(&fimd_display);
>>>> + exynos_drm_manager_unregister(&fimd_manager);
>>>>
>>>> if (ctx->suspended)
>>>> goto out;
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2013-10-16 2:17 UTC | newest]
Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-10-11 0:30 [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Sean Paul
2013-10-11 0:30 ` [PATCH 01/23] drm/exynos: Remove useless slab.h include Sean Paul
2013-10-11 0:30 ` [PATCH 02/23] drm/exynos: Merge overlay_ops into manager_ops Sean Paul
2013-10-11 0:30 ` [PATCH 03/23] drm/exynos: Add an initialize function to manager and display Sean Paul
2013-10-11 0:30 ` [PATCH 04/23] drm/exynos: Use manager_op initialize in fimd Sean Paul
2013-10-11 0:30 ` [PATCH 05/23] drm/exynos: hdmi: Implement initialize op for hdmi Sean Paul
2013-10-11 0:30 ` [PATCH 06/23] drm/exynos: Pass context in manager ops instead of dev Sean Paul
2013-10-12 6:44 ` Inki Dae
2013-10-14 12:42 ` Inki Dae
2013-10-14 14:18 ` Sean Paul
2013-10-14 15:07 ` Inki Dae
2013-10-11 0:30 ` [PATCH 07/23] drm/exynos: Pass context in display_ops " Sean Paul
2013-10-11 0:30 ` [PATCH 08/23] drm/exynos: Remove dpms link between encoder/connector Sean Paul
2013-10-11 0:30 ` [PATCH 09/23] drm/exynos: Rename display_op power_on to dpms Sean Paul
2013-10-11 0:30 ` [PATCH 10/23] drm/exynos: Don't keep dpms state in encoder Sean Paul
2013-10-11 0:30 ` [PATCH 11/23] drm/exynos: Use unsigned long for possible_crtcs Sean Paul
2013-10-11 0:30 ` [PATCH 12/23] drm/exynos: Split manager/display/subdrv Sean Paul
2013-10-12 0:42 ` Inki Dae
2013-10-12 2:06 ` Sean Paul
2013-10-12 3:49 ` Inki Dae
2013-10-12 4:19 ` Sean Paul
2013-10-12 4:30 ` Inki Dae
2013-10-14 15:24 ` Inki Dae
2013-10-15 4:09 ` Inki Dae
2013-10-15 18:12 ` Sean Paul
2013-10-16 2:17 ` Inki Dae
2013-10-11 0:30 ` [PATCH 13/23] drm/exynos: hdmi: remove the i2c drivers and use devtree Sean Paul
2013-10-11 0:30 ` [PATCH 14/23] drm/exynos: Remove exynos_drm_hdmi shim Sean Paul
2013-10-11 0:30 ` [PATCH 15/23] drm/exynos: Use drm_mode_copy to copy modes Sean Paul
2013-10-11 0:30 ` [PATCH 16/23] drm/exynos: Disable unused crtc planes from crtc Sean Paul
2013-10-11 0:30 ` [PATCH 17/23] drm/exynos: Add mode_set manager operation Sean Paul
2013-10-11 0:30 ` [PATCH 18/23] drm/exynos: Implement mode_fixup " Sean Paul
2013-10-11 0:30 ` [PATCH 19/23] drm/exynos: Use mode_set to configure fimd Sean Paul
2013-10-11 0:30 ` [PATCH 20/23] drm/exynos: Remove unused/useless fimd_context members Sean Paul
2013-10-11 0:30 ` [PATCH 21/23] drm/exynos: Move dp driver from video/ to drm/ Sean Paul
2013-10-11 0:30 ` [PATCH 22/23] drm/exynos: Move display implementation into dp Sean Paul
2013-10-11 0:30 ` [PATCH 23/23] ARM: dts: Move display-timings node from fimd to dp Sean Paul
2013-10-12 2:26 ` [PATCH 00/23] drm/exynos: Refactor parts of the exynos driver Tomasz Figa
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.