Commit 93bca243 authored by Gustavo Padovan's avatar Gustavo Padovan Committed by Inki Dae

drm/exynos: remove struct exynos_drm_manager

exynos_drm_manager was just a redundant struct to represent the crtc as
well. In this commit we merge exynos_drm_manager into exynos_drm_crtc to
remove an unnecessary level of indirection easing the understand of the
flow on exynos.
Signed-off-by: default avatarGustavo Padovan <gustavo.padovan@collabora.co.uk>
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
parent eb88e422
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 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_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); DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
...@@ -41,8 +40,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -41,8 +40,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
drm_crtc_vblank_off(crtc); drm_crtc_vblank_off(crtc);
} }
if (manager->ops->dpms) if (exynos_crtc->ops->dpms)
manager->ops->dpms(manager, mode); exynos_crtc->ops->dpms(exynos_crtc, mode);
exynos_crtc->dpms = mode; exynos_crtc->dpms = mode;
...@@ -58,16 +57,15 @@ static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) ...@@ -58,16 +57,15 @@ static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
static void exynos_drm_crtc_commit(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_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_manager *manager = exynos_crtc->manager;
struct exynos_drm_plane *exynos_plane = to_exynos_plane(crtc->primary); struct exynos_drm_plane *exynos_plane = to_exynos_plane(crtc->primary);
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
if (manager->ops->win_commit) if (exynos_crtc->ops->win_commit)
manager->ops->win_commit(manager, exynos_plane->zpos); exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos);
if (manager->ops->commit) if (exynos_crtc->ops->commit)
manager->ops->commit(manager); exynos_crtc->ops->commit(exynos_crtc);
exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_ON); exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_ON);
} }
...@@ -78,10 +76,10 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, ...@@ -78,10 +76,10 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_manager *manager = exynos_crtc->manager;
if (manager->ops->mode_fixup) if (exynos_crtc->ops->mode_fixup)
return manager->ops->mode_fixup(manager, mode, adjusted_mode); return exynos_crtc->ops->mode_fixup(exynos_crtc, mode,
adjusted_mode);
return true; return true;
} }
...@@ -92,7 +90,6 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -92,7 +90,6 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_manager *manager = exynos_crtc->manager;
struct drm_framebuffer *fb = crtc->primary->fb; struct drm_framebuffer *fb = crtc->primary->fb;
unsigned int crtc_w; unsigned int crtc_w;
unsigned int crtc_h; unsigned int crtc_h;
...@@ -106,8 +103,8 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -106,8 +103,8 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
crtc_w = fb->width - x; crtc_w = fb->width - x;
crtc_h = fb->height - y; crtc_h = fb->height - y;
if (manager->ops->mode_set) if (exynos_crtc->ops->mode_set)
manager->ops->mode_set(manager, &crtc->mode); exynos_crtc->ops->mode_set(exynos_crtc, &crtc->mode);
return exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0, return exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
crtc_w, crtc_h, x, y, crtc_w, crtc_h); crtc_w, crtc_h, x, y, crtc_w, crtc_h);
...@@ -299,9 +296,11 @@ static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc) ...@@ -299,9 +296,11 @@ static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
drm_object_attach_property(&crtc->base, prop, 0); drm_object_attach_property(&crtc->base, prop, 0);
} }
int exynos_drm_crtc_create(struct exynos_drm_manager *manager, struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
struct drm_device *drm_dev, int pipe, int pipe,
enum exynos_drm_output_type type) enum exynos_drm_output_type type,
struct exynos_drm_crtc_ops *ops,
void *ctx)
{ {
struct exynos_drm_crtc *exynos_crtc; struct exynos_drm_crtc *exynos_crtc;
struct drm_plane *plane; struct drm_plane *plane;
...@@ -311,15 +310,16 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager, ...@@ -311,15 +310,16 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager,
exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
if (!exynos_crtc) if (!exynos_crtc)
return -ENOMEM; return ERR_PTR(-ENOMEM);
init_waitqueue_head(&exynos_crtc->pending_flip_queue); init_waitqueue_head(&exynos_crtc->pending_flip_queue);
atomic_set(&exynos_crtc->pending_flip, 0); atomic_set(&exynos_crtc->pending_flip, 0);
exynos_crtc->dpms = DRM_MODE_DPMS_OFF; exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
exynos_crtc->manager = manager;
exynos_crtc->pipe = pipe; exynos_crtc->pipe = pipe;
exynos_crtc->type = type; exynos_crtc->type = type;
exynos_crtc->ops = ops;
exynos_crtc->ctx = ctx;
plane = exynos_plane_init(drm_dev, 1 << pipe, plane = exynos_plane_init(drm_dev, 1 << pipe,
DRM_PLANE_TYPE_PRIMARY); DRM_PLANE_TYPE_PRIMARY);
if (IS_ERR(plane)) { if (IS_ERR(plane)) {
...@@ -327,7 +327,6 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager, ...@@ -327,7 +327,6 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager,
goto err_plane; goto err_plane;
} }
manager->crtc = &exynos_crtc->base;
crtc = &exynos_crtc->base; crtc = &exynos_crtc->base;
private->crtc[pipe] = crtc; private->crtc[pipe] = crtc;
...@@ -341,13 +340,13 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager, ...@@ -341,13 +340,13 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager,
exynos_drm_crtc_attach_mode_property(crtc); exynos_drm_crtc_attach_mode_property(crtc);
return 0; return exynos_crtc;
err_crtc: err_crtc:
plane->funcs->destroy(plane); plane->funcs->destroy(plane);
err_plane: err_plane:
kfree(exynos_crtc); kfree(exynos_crtc);
return ret; return ERR_PTR(ret);
} }
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
...@@ -355,13 +354,12 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) ...@@ -355,13 +354,12 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
struct exynos_drm_private *private = dev->dev_private; struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc = struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]); to_exynos_crtc(private->crtc[pipe]);
struct exynos_drm_manager *manager = exynos_crtc->manager;
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return -EPERM; return -EPERM;
if (manager->ops->enable_vblank) if (exynos_crtc->ops->enable_vblank)
manager->ops->enable_vblank(manager); exynos_crtc->ops->enable_vblank(exynos_crtc);
return 0; return 0;
} }
...@@ -371,13 +369,12 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) ...@@ -371,13 +369,12 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
struct exynos_drm_private *private = dev->dev_private; struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc = struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]); to_exynos_crtc(private->crtc[pipe]);
struct exynos_drm_manager *manager = exynos_crtc->manager;
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return; return;
if (manager->ops->disable_vblank) if (exynos_crtc->ops->disable_vblank)
manager->ops->disable_vblank(manager); exynos_crtc->ops->disable_vblank(exynos_crtc);
} }
void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
...@@ -408,7 +405,7 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) ...@@ -408,7 +405,7 @@ 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_complete_scanout(struct drm_framebuffer *fb)
{ {
struct exynos_drm_manager *manager; struct exynos_drm_crtc *exynos_crtc;
struct drm_device *dev = fb->dev; struct drm_device *dev = fb->dev;
struct drm_crtc *crtc; struct drm_crtc *crtc;
...@@ -417,15 +414,15 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) ...@@ -417,15 +414,15 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
* for all encoders. * for all encoders.
*/ */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
manager = to_exynos_crtc(crtc)->manager; exynos_crtc = to_exynos_crtc(crtc);
/* /*
* wait for vblank interrupt * wait for vblank interrupt
* - this makes sure that overlay data are updated to * - this makes sure that overlay data are updated to
* real hardware. * real hardware.
*/ */
if (manager->ops->wait_for_vblank) if (exynos_crtc->ops->wait_for_vblank)
manager->ops->wait_for_vblank(manager); exynos_crtc->ops->wait_for_vblank(exynos_crtc);
} }
} }
...@@ -447,8 +444,8 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, ...@@ -447,8 +444,8 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
{ {
struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
if (manager->ops->te_handler) if (exynos_crtc->ops->te_handler)
manager->ops->te_handler(manager); exynos_crtc->ops->te_handler(exynos_crtc);
} }
...@@ -17,9 +17,11 @@ ...@@ -17,9 +17,11 @@
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
int exynos_drm_crtc_create(struct exynos_drm_manager *manager, struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
struct drm_device *drm_dev, int pipe, int pipe,
enum exynos_drm_output_type type); enum exynos_drm_output_type type,
struct exynos_drm_crtc_ops *ops,
void *context);
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); 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_disable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe); void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
......
...@@ -163,7 +163,7 @@ struct exynos_drm_display { ...@@ -163,7 +163,7 @@ struct exynos_drm_display {
}; };
/* /*
* Exynos drm manager ops * Exynos drm crtc ops
* *
* @dpms: control device power. * @dpms: control device power.
* @mode_fixup: fix mode data before applying it * @mode_fixup: fix mode data before applying it
...@@ -180,39 +180,24 @@ struct exynos_drm_display { ...@@ -180,39 +180,24 @@ struct exynos_drm_display {
* @te_handler: trigger to transfer video image at the tearing effect * @te_handler: trigger to transfer video image at the tearing effect
* synchronization signal if there is a page flip request. * synchronization signal if there is a page flip request.
*/ */
struct exynos_drm_manager; struct exynos_drm_crtc;
struct exynos_drm_manager_ops { struct exynos_drm_crtc_ops {
void (*dpms)(struct exynos_drm_manager *mgr, int mode); void (*dpms)(struct exynos_drm_crtc *crtc, int mode);
bool (*mode_fixup)(struct exynos_drm_manager *mgr, bool (*mode_fixup)(struct exynos_drm_crtc *crtc,
const struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode); struct drm_display_mode *adjusted_mode);
void (*mode_set)(struct exynos_drm_manager *mgr, void (*mode_set)(struct exynos_drm_crtc *crtc,
const struct drm_display_mode *mode); const struct drm_display_mode *mode);
void (*commit)(struct exynos_drm_manager *mgr); void (*commit)(struct exynos_drm_crtc *crtc);
int (*enable_vblank)(struct exynos_drm_manager *mgr); int (*enable_vblank)(struct exynos_drm_crtc *crtc);
void (*disable_vblank)(struct exynos_drm_manager *mgr); void (*disable_vblank)(struct exynos_drm_crtc *crtc);
void (*wait_for_vblank)(struct exynos_drm_manager *mgr); void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
void (*win_mode_set)(struct exynos_drm_manager *mgr, void (*win_mode_set)(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane); struct exynos_drm_plane *plane);
void (*win_commit)(struct exynos_drm_manager *mgr, int zpos); void (*win_commit)(struct exynos_drm_crtc *crtc, int zpos);
void (*win_enable)(struct exynos_drm_manager *mgr, int zpos); void (*win_enable)(struct exynos_drm_crtc *crtc, int zpos);
void (*win_disable)(struct exynos_drm_manager *mgr, int zpos); void (*win_disable)(struct exynos_drm_crtc *crtc, int zpos);
void (*te_handler)(struct exynos_drm_manager *mgr); void (*te_handler)(struct exynos_drm_crtc *crtc);
};
/*
* Exynos drm common manager structure, maps 1:1 with a crtc
*
* @list: the list entry for this manager
* @drm_dev: pointer to the drm device
* @crtc: crtc object.
* @ops: pointer to callbacks for exynos drm specific functionality
* @ctx: A pointer to the manager's implementation specific context
*/
struct exynos_drm_manager {
struct list_head list;
struct drm_crtc *crtc;
struct exynos_drm_manager_ops *ops;
}; };
enum exynos_crtc_mode { enum exynos_crtc_mode {
...@@ -224,7 +209,6 @@ enum exynos_crtc_mode { ...@@ -224,7 +209,6 @@ enum exynos_crtc_mode {
* Exynos specific crtc structure. * Exynos specific crtc structure.
* *
* @base: crtc object. * @base: crtc object.
* @manager: the manager associated with this crtc
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
* @pipe: a crtc index created at load() with a new crtc object creation * @pipe: a crtc index created at load() with a new crtc object creation
* and the crtc object would be set to private->crtc array * and the crtc object would be set to private->crtc array
...@@ -235,16 +219,19 @@ enum exynos_crtc_mode { ...@@ -235,16 +219,19 @@ enum exynos_crtc_mode {
* this pipe value. * this pipe value.
* @dpms: store the crtc dpms value * @dpms: store the crtc dpms value
* @mode: store the crtc mode value * @mode: store the crtc mode value
* @ops: pointer to callbacks for exynos drm specific functionality
* @ctx: A pointer to the crtc's implementation specific context
*/ */
struct exynos_drm_crtc { struct exynos_drm_crtc {
struct drm_crtc base; struct drm_crtc base;
struct exynos_drm_manager *manager;
enum exynos_drm_output_type type; enum exynos_drm_output_type type;
unsigned int pipe; unsigned int pipe;
unsigned int dpms; unsigned int dpms;
enum exynos_crtc_mode mode; enum exynos_crtc_mode mode;
wait_queue_head_t pending_flip_queue; wait_queue_head_t pending_flip_queue;
atomic_t pending_flip; atomic_t pending_flip;
struct exynos_drm_crtc_ops *ops;
void *ctx;
}; };
struct exynos_drm_g2d_private { struct exynos_drm_g2d_private {
......
...@@ -157,9 +157,9 @@ struct fimd_win_data { ...@@ -157,9 +157,9 @@ struct fimd_win_data {
}; };
struct fimd_context { struct fimd_context {
struct exynos_drm_manager manager;
struct device *dev; struct device *dev;
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct exynos_drm_crtc *crtc;
struct clk *bus_clk; struct clk *bus_clk;
struct clk *lcd_clk; struct clk *lcd_clk;
void __iomem *regs; void __iomem *regs;
...@@ -185,11 +185,6 @@ struct fimd_context { ...@@ -185,11 +185,6 @@ struct fimd_context {
struct exynos_drm_display *display; struct exynos_drm_display *display;
}; };
static inline struct fimd_context *mgr_to_fimd(struct exynos_drm_manager *mgr)
{
return container_of(mgr, struct fimd_context, manager);
}
static const struct of_device_id fimd_driver_dt_match[] = { static const struct of_device_id fimd_driver_dt_match[] = {
{ .compatible = "samsung,s3c6400-fimd", { .compatible = "samsung,s3c6400-fimd",
.data = &s3c64xx_fimd_driver_data }, .data = &s3c64xx_fimd_driver_data },
...@@ -214,9 +209,9 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data( ...@@ -214,9 +209,9 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
return (struct fimd_driver_data *)of_id->data; return (struct fimd_driver_data *)of_id->data;
} }
static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr) static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
if (ctx->suspended) if (ctx->suspended)
return; return;
...@@ -259,9 +254,9 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win, ...@@ -259,9 +254,9 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win,
writel(val, ctx->regs + SHADOWCON); writel(val, ctx->regs + SHADOWCON);
} }
static void fimd_clear_channel(struct exynos_drm_manager *mgr) static void fimd_clear_channel(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
int win, ch_enabled = 0; int win, ch_enabled = 0;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
...@@ -286,15 +281,14 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr) ...@@ -286,15 +281,14 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr)
unsigned int state = ctx->suspended; unsigned int state = ctx->suspended;
ctx->suspended = 0; ctx->suspended = 0;
fimd_wait_for_vblank(mgr); fimd_wait_for_vblank(crtc);
ctx->suspended = state; ctx->suspended = state;
} }
} }
static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, static int fimd_ctx_initialize(struct fimd_context *ctx,
struct drm_device *drm_dev) struct drm_device *drm_dev)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr);
struct exynos_drm_private *priv; struct exynos_drm_private *priv;
priv = drm_dev->dev_private; priv = drm_dev->dev_private;
...@@ -307,17 +301,15 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, ...@@ -307,17 +301,15 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
* If any channel is already active, iommu will throw * If any channel is already active, iommu will throw
* a PAGE FAULT when enabled. So clear any channel if enabled. * a PAGE FAULT when enabled. So clear any channel if enabled.
*/ */
fimd_clear_channel(mgr); fimd_clear_channel(ctx->crtc);
drm_iommu_attach_device(ctx->drm_dev, ctx->dev); drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
} }
return 0; return 0;
} }
static void fimd_mgr_remove(struct exynos_drm_manager *mgr) static void fimd_ctx_remove(struct fimd_context *ctx)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr);
/* detach this sub driver from iommu mapping if supported. */ /* detach this sub driver from iommu mapping if supported. */
if (is_drm_iommu_supported(ctx->drm_dev)) if (is_drm_iommu_supported(ctx->drm_dev))
drm_iommu_detach_device(ctx->drm_dev, ctx->dev); drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
...@@ -343,7 +335,7 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx, ...@@ -343,7 +335,7 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
return (clkdiv < 0x100) ? clkdiv : 0xff; return (clkdiv < 0x100) ? clkdiv : 0xff;
} }
static bool fimd_mode_fixup(struct exynos_drm_manager *mgr, static bool fimd_mode_fixup(struct exynos_drm_crtc *crtc,
const struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
...@@ -353,17 +345,17 @@ static bool fimd_mode_fixup(struct exynos_drm_manager *mgr, ...@@ -353,17 +345,17 @@ static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
return true; return true;
} }
static void fimd_mode_set(struct exynos_drm_manager *mgr, static void fimd_mode_set(struct exynos_drm_crtc *crtc,
const struct drm_display_mode *in_mode) const struct drm_display_mode *in_mode)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
drm_mode_copy(&ctx->mode, in_mode); drm_mode_copy(&ctx->mode, in_mode);
} }
static void fimd_commit(struct exynos_drm_manager *mgr) static void fimd_commit(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
struct drm_display_mode *mode = &ctx->mode; struct drm_display_mode *mode = &ctx->mode;
struct fimd_driver_data *driver_data = ctx->driver_data; struct fimd_driver_data *driver_data = ctx->driver_data;
void *timing_base = ctx->regs + driver_data->timing_base; void *timing_base = ctx->regs + driver_data->timing_base;
...@@ -461,9 +453,9 @@ static void fimd_commit(struct exynos_drm_manager *mgr) ...@@ -461,9 +453,9 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
writel(val, ctx->regs + VIDCON0); writel(val, ctx->regs + VIDCON0);
} }
static int fimd_enable_vblank(struct exynos_drm_manager *mgr) static int fimd_enable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
u32 val; u32 val;
if (ctx->suspended) if (ctx->suspended)
...@@ -493,9 +485,9 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr) ...@@ -493,9 +485,9 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
return 0; return 0;
} }
static void fimd_disable_vblank(struct exynos_drm_manager *mgr) static void fimd_disable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
u32 val; u32 val;
if (ctx->suspended) if (ctx->suspended)
...@@ -517,10 +509,10 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr) ...@@ -517,10 +509,10 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
} }
} }
static void fimd_win_mode_set(struct exynos_drm_manager *mgr, static void fimd_win_mode_set(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane) struct exynos_drm_plane *plane)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
struct fimd_win_data *win_data; struct fimd_win_data *win_data;
int win; int win;
unsigned long offset; unsigned long offset;
...@@ -676,9 +668,9 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, ...@@ -676,9 +668,9 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
writel(val, ctx->regs + reg); writel(val, ctx->regs + reg);
} }
static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
struct fimd_win_data *win_data; struct fimd_win_data *win_data;
int win = zpos; int win = zpos;
unsigned long val, alpha, size; unsigned long val, alpha, size;
...@@ -799,9 +791,9 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) ...@@ -799,9 +791,9 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
atomic_set(&ctx->win_updated, 1); atomic_set(&ctx->win_updated, 1);
} }
static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) static void fimd_win_disable(struct exynos_drm_crtc *crtc, int zpos)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
struct fimd_win_data *win_data; struct fimd_win_data *win_data;
int win = zpos; int win = zpos;
...@@ -833,9 +825,9 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) ...@@ -833,9 +825,9 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
win_data->enabled = false; win_data->enabled = false;
} }
static void fimd_window_suspend(struct exynos_drm_manager *mgr) static void fimd_window_suspend(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
struct fimd_win_data *win_data; struct fimd_win_data *win_data;
int i; int i;
...@@ -843,13 +835,13 @@ static void fimd_window_suspend(struct exynos_drm_manager *mgr) ...@@ -843,13 +835,13 @@ static void fimd_window_suspend(struct exynos_drm_manager *mgr)
win_data = &ctx->win_data[i]; win_data = &ctx->win_data[i];
win_data->resume = win_data->enabled; win_data->resume = win_data->enabled;
if (win_data->enabled) if (win_data->enabled)
fimd_win_disable(mgr, i); fimd_win_disable(crtc, i);
} }
} }
static void fimd_window_resume(struct exynos_drm_manager *mgr) static void fimd_window_resume(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
struct fimd_win_data *win_data; struct fimd_win_data *win_data;
int i; int i;
...@@ -860,26 +852,26 @@ static void fimd_window_resume(struct exynos_drm_manager *mgr) ...@@ -860,26 +852,26 @@ static void fimd_window_resume(struct exynos_drm_manager *mgr)
} }
} }
static void fimd_apply(struct exynos_drm_manager *mgr) static void fimd_apply(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
struct fimd_win_data *win_data; struct fimd_win_data *win_data;
int i; int i;
for (i = 0; i < WINDOWS_NR; i++) { for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i]; win_data = &ctx->win_data[i];
if (win_data->enabled) if (win_data->enabled)
fimd_win_commit(mgr, i); fimd_win_commit(crtc, i);
else else
fimd_win_disable(mgr, i); fimd_win_disable(crtc, i);
} }
fimd_commit(mgr); fimd_commit(crtc);
} }
static int fimd_poweron(struct exynos_drm_manager *mgr) static int fimd_poweron(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
int ret; int ret;
if (!ctx->suspended) if (!ctx->suspended)
...@@ -903,16 +895,16 @@ static int fimd_poweron(struct exynos_drm_manager *mgr) ...@@ -903,16 +895,16 @@ static int fimd_poweron(struct exynos_drm_manager *mgr)
/* if vblank was enabled status, enable it again. */ /* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags)) { if (test_and_clear_bit(0, &ctx->irq_flags)) {
ret = fimd_enable_vblank(mgr); ret = fimd_enable_vblank(crtc);
if (ret) { if (ret) {
DRM_ERROR("Failed to re-enable vblank [%d]\n", ret); DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
goto enable_vblank_err; goto enable_vblank_err;
} }
} }
fimd_window_resume(mgr); fimd_window_resume(crtc);
fimd_apply(mgr); fimd_apply(crtc);
return 0; return 0;
...@@ -925,9 +917,9 @@ static int fimd_poweron(struct exynos_drm_manager *mgr) ...@@ -925,9 +917,9 @@ static int fimd_poweron(struct exynos_drm_manager *mgr)
return ret; return ret;
} }
static int fimd_poweroff(struct exynos_drm_manager *mgr) static int fimd_poweroff(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
if (ctx->suspended) if (ctx->suspended)
return 0; return 0;
...@@ -937,7 +929,7 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr) ...@@ -937,7 +929,7 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr)
* suspend that connector. Otherwise we might try to scan from * suspend that connector. Otherwise we might try to scan from
* a destroyed buffer later. * a destroyed buffer later.
*/ */
fimd_window_suspend(mgr); fimd_window_suspend(crtc);
clk_disable_unprepare(ctx->lcd_clk); clk_disable_unprepare(ctx->lcd_clk);
clk_disable_unprepare(ctx->bus_clk); clk_disable_unprepare(ctx->bus_clk);
...@@ -948,18 +940,18 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr) ...@@ -948,18 +940,18 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr)
return 0; return 0;
} }
static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) static void fimd_dpms(struct exynos_drm_crtc *crtc, int mode)
{ {
DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
switch (mode) { switch (mode) {
case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_ON:
fimd_poweron(mgr); fimd_poweron(crtc);
break; break;
case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF: case DRM_MODE_DPMS_OFF:
fimd_poweroff(mgr); fimd_poweroff(crtc);
break; break;
default: default:
DRM_DEBUG_KMS("unspecified mode %d\n", mode); DRM_DEBUG_KMS("unspecified mode %d\n", mode);
...@@ -996,9 +988,9 @@ static void fimd_trigger(struct device *dev) ...@@ -996,9 +988,9 @@ static void fimd_trigger(struct device *dev)
atomic_set(&ctx->triggering, 0); atomic_set(&ctx->triggering, 0);
} }
static void fimd_te_handler(struct exynos_drm_manager *mgr) static void fimd_te_handler(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = mgr_to_fimd(mgr); struct fimd_context *ctx = crtc->ctx;
/* Checks the crtc is detached already from encoder */ /* Checks the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev) if (ctx->pipe < 0 || !ctx->drm_dev)
...@@ -1021,7 +1013,7 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr) ...@@ -1021,7 +1013,7 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr)
drm_handle_vblank(ctx->drm_dev, ctx->pipe); drm_handle_vblank(ctx->drm_dev, ctx->pipe);
} }
static struct exynos_drm_manager_ops fimd_manager_ops = { static struct exynos_drm_crtc_ops fimd_crtc_ops = {
.dpms = fimd_dpms, .dpms = fimd_dpms,
.mode_fixup = fimd_mode_fixup, .mode_fixup = fimd_mode_fixup,
.mode_set = fimd_mode_set, .mode_set = fimd_mode_set,
...@@ -1075,9 +1067,14 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ...@@ -1075,9 +1067,14 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
struct fimd_context *ctx = dev_get_drvdata(dev); struct fimd_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
fimd_mgr_initialize(&ctx->manager, drm_dev); ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
exynos_drm_crtc_create(&ctx->manager, drm_dev, ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
EXYNOS_DISPLAY_TYPE_LCD); &fimd_crtc_ops, ctx);
if (IS_ERR(ctx->crtc))
return PTR_ERR(ctx->crtc);
fimd_ctx_initialize(ctx, drm_dev);
if (ctx->display) if (ctx->display)
exynos_drm_create_enc_conn(drm_dev, ctx->display); exynos_drm_create_enc_conn(drm_dev, ctx->display);
...@@ -1090,12 +1087,12 @@ static void fimd_unbind(struct device *dev, struct device *master, ...@@ -1090,12 +1087,12 @@ static void fimd_unbind(struct device *dev, struct device *master,
{ {
struct fimd_context *ctx = dev_get_drvdata(dev); struct fimd_context *ctx = dev_get_drvdata(dev);
fimd_dpms(&ctx->manager, DRM_MODE_DPMS_OFF); fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
if (ctx->display) if (ctx->display)
exynos_dpi_remove(ctx->display); exynos_dpi_remove(ctx->display);
fimd_mgr_remove(&ctx->manager); fimd_ctx_remove(ctx);
} }
static const struct component_ops fimd_component_ops = { static const struct component_ops fimd_component_ops = {
...@@ -1118,8 +1115,6 @@ static int fimd_probe(struct platform_device *pdev) ...@@ -1118,8 +1115,6 @@ static int fimd_probe(struct platform_device *pdev)
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
ctx->manager.ops = &fimd_manager_ops;
ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC, ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
EXYNOS_DISPLAY_TYPE_LCD); EXYNOS_DISPLAY_TYPE_LCD);
if (ret) if (ret)
......
...@@ -68,7 +68,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -68,7 +68,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
uint32_t src_w, uint32_t src_h) uint32_t src_w, uint32_t src_h)
{ {
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
unsigned int actual_w; unsigned int actual_w;
unsigned int actual_h; unsigned int actual_h;
int nr; int nr;
...@@ -133,8 +133,8 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -133,8 +133,8 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
plane->crtc = crtc; plane->crtc = crtc;
if (manager->ops->win_mode_set) if (exynos_crtc->ops->win_mode_set)
manager->ops->win_mode_set(manager, exynos_plane); exynos_crtc->ops->win_mode_set(exynos_crtc, exynos_plane);
return 0; return 0;
} }
...@@ -142,24 +142,24 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -142,24 +142,24 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
void exynos_plane_dpms(struct drm_plane *plane, int mode) void exynos_plane_dpms(struct drm_plane *plane, int mode)
{ {
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_manager *manager; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc);
if (mode == DRM_MODE_DPMS_ON) { if (mode == DRM_MODE_DPMS_ON) {
if (exynos_plane->enabled) if (exynos_plane->enabled)
return; return;
manager = to_exynos_crtc(plane->crtc)->manager; if (exynos_crtc->ops->win_enable)
if (manager->ops->win_enable) exynos_crtc->ops->win_enable(exynos_crtc,
manager->ops->win_enable(manager, exynos_plane->zpos); exynos_plane->zpos);
exynos_plane->enabled = true; exynos_plane->enabled = true;
} else { } else {
if (!exynos_plane->enabled) if (!exynos_plane->enabled)
return; return;
manager = to_exynos_crtc(plane->crtc)->manager; if (exynos_crtc->ops->win_disable)
if (manager->ops->win_disable) exynos_crtc->ops->win_disable(exynos_crtc,
manager->ops->win_disable(manager, exynos_plane->zpos); exynos_plane->zpos);
exynos_plane->enabled = false; exynos_plane->enabled = false;
} }
...@@ -173,7 +173,7 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -173,7 +173,7 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
uint32_t src_w, uint32_t src_h) uint32_t src_w, uint32_t src_h)
{ {
struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
int ret; int ret;
...@@ -183,8 +183,8 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -183,8 +183,8 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (manager->ops->win_commit) if (exynos_crtc->ops->win_commit)
manager->ops->win_commit(manager, exynos_plane->zpos); exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos);
return 0; return 0;
} }
......
...@@ -47,11 +47,10 @@ struct vidi_win_data { ...@@ -47,11 +47,10 @@ struct vidi_win_data {
}; };
struct vidi_context { struct vidi_context {
struct exynos_drm_manager manager;
struct exynos_drm_display display; struct exynos_drm_display display;
struct platform_device *pdev; struct platform_device *pdev;
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct drm_crtc *crtc; struct exynos_drm_crtc *crtc;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_connector connector; struct drm_connector connector;
struct vidi_win_data win_data[WINDOWS_NR]; struct vidi_win_data win_data[WINDOWS_NR];
...@@ -68,11 +67,6 @@ struct vidi_context { ...@@ -68,11 +67,6 @@ struct vidi_context {
int pipe; int pipe;
}; };
static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
{
return container_of(m, struct vidi_context, manager);
}
static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d) static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
{ {
return container_of(d, struct vidi_context, display); return container_of(d, struct vidi_context, display);
...@@ -103,23 +97,23 @@ static const char fake_edid_info[] = { ...@@ -103,23 +97,23 @@ static const char fake_edid_info[] = {
0x00, 0x00, 0x00, 0x06 0x00, 0x00, 0x00, 0x06
}; };
static void vidi_apply(struct exynos_drm_manager *mgr) static void vidi_apply(struct exynos_drm_crtc *crtc)
{ {
struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_context *ctx = crtc->ctx;
struct exynos_drm_manager_ops *mgr_ops = mgr->ops; struct exynos_drm_crtc_ops *crtc_ops = crtc->ops;
struct vidi_win_data *win_data; struct vidi_win_data *win_data;
int i; int i;
for (i = 0; i < WINDOWS_NR; i++) { for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i]; win_data = &ctx->win_data[i];
if (win_data->enabled && (mgr_ops && mgr_ops->win_commit)) if (win_data->enabled && (crtc_ops && crtc_ops->win_commit))
mgr_ops->win_commit(mgr, i); crtc_ops->win_commit(crtc, i);
} }
} }
static int vidi_enable_vblank(struct exynos_drm_manager *mgr) static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_context *ctx = crtc->ctx;
if (ctx->suspended) if (ctx->suspended)
return -EPERM; return -EPERM;
...@@ -132,16 +126,16 @@ static int vidi_enable_vblank(struct exynos_drm_manager *mgr) ...@@ -132,16 +126,16 @@ static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
/* /*
* in case of page flip request, vidi_finish_pageflip function * in case of page flip request, vidi_finish_pageflip function
* will not be called because direct_vblank is true and then * will not be called because direct_vblank is true and then
* that function will be called by manager_ops->win_commit callback * that function will be called by crtc_ops->win_commit callback
*/ */
schedule_work(&ctx->work); schedule_work(&ctx->work);
return 0; return 0;
} }
static void vidi_disable_vblank(struct exynos_drm_manager *mgr) static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_context *ctx = crtc->ctx;
if (ctx->suspended) if (ctx->suspended)
return; return;
...@@ -150,10 +144,10 @@ static void vidi_disable_vblank(struct exynos_drm_manager *mgr) ...@@ -150,10 +144,10 @@ static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
ctx->vblank_on = false; ctx->vblank_on = false;
} }
static void vidi_win_mode_set(struct exynos_drm_manager *mgr, static void vidi_win_mode_set(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane) struct exynos_drm_plane *plane)
{ {
struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_context *ctx = crtc->ctx;
struct vidi_win_data *win_data; struct vidi_win_data *win_data;
int win; int win;
unsigned long offset; unsigned long offset;
...@@ -203,9 +197,9 @@ static void vidi_win_mode_set(struct exynos_drm_manager *mgr, ...@@ -203,9 +197,9 @@ static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
plane->fb_width, plane->crtc_width); plane->fb_width, plane->crtc_width);
} }
static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos) static void vidi_win_commit(struct exynos_drm_crtc *crtc, int zpos)
{ {
struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_context *ctx = crtc->ctx;
struct vidi_win_data *win_data; struct vidi_win_data *win_data;
int win = zpos; int win = zpos;
...@@ -228,9 +222,9 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos) ...@@ -228,9 +222,9 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
schedule_work(&ctx->work); schedule_work(&ctx->work);
} }
static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos) static void vidi_win_disable(struct exynos_drm_crtc *crtc, int zpos)
{ {
struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_context *ctx = crtc->ctx;
struct vidi_win_data *win_data; struct vidi_win_data *win_data;
int win = zpos; int win = zpos;
...@@ -246,9 +240,9 @@ static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos) ...@@ -246,9 +240,9 @@ static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
/* TODO. */ /* TODO. */
} }
static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) static int vidi_power_on(struct exynos_drm_crtc *crtc, bool enable)
{ {
struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_context *ctx = crtc->ctx;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
...@@ -260,9 +254,9 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) ...@@ -260,9 +254,9 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
/* if vblank was enabled status, enable it again. */ /* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags)) if (test_and_clear_bit(0, &ctx->irq_flags))
vidi_enable_vblank(mgr); vidi_enable_vblank(crtc);
vidi_apply(mgr); vidi_apply(crtc);
} else { } else {
ctx->suspended = true; ctx->suspended = true;
} }
...@@ -270,9 +264,9 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) ...@@ -270,9 +264,9 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
return 0; return 0;
} }
static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) static void vidi_dpms(struct exynos_drm_crtc *crtc, int mode)
{ {
struct vidi_context *ctx = manager_to_vidi(mgr); struct vidi_context *ctx = crtc->ctx;
DRM_DEBUG_KMS("%d\n", mode); DRM_DEBUG_KMS("%d\n", mode);
...@@ -280,12 +274,12 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) ...@@ -280,12 +274,12 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
switch (mode) { switch (mode) {
case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_ON:
vidi_power_on(mgr, true); vidi_power_on(crtc, true);
break; break;
case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF: case DRM_MODE_DPMS_OFF:
vidi_power_on(mgr, false); vidi_power_on(crtc, false);
break; break;
default: default:
DRM_DEBUG_KMS("unspecified mode %d\n", mode); DRM_DEBUG_KMS("unspecified mode %d\n", mode);
...@@ -295,10 +289,9 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) ...@@ -295,10 +289,9 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
mutex_unlock(&ctx->lock); mutex_unlock(&ctx->lock);
} }
static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, static int vidi_ctx_initialize(struct vidi_context *ctx,
struct drm_device *drm_dev) struct drm_device *drm_dev)
{ {
struct vidi_context *ctx = manager_to_vidi(mgr);
struct exynos_drm_private *priv = drm_dev->dev_private; struct exynos_drm_private *priv = drm_dev->dev_private;
ctx->drm_dev = drm_dev; ctx->drm_dev = drm_dev;
...@@ -307,7 +300,7 @@ static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, ...@@ -307,7 +300,7 @@ static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
return 0; return 0;
} }
static struct exynos_drm_manager_ops vidi_manager_ops = { static struct exynos_drm_crtc_ops vidi_crtc_ops = {
.dpms = vidi_dpms, .dpms = vidi_dpms,
.enable_vblank = vidi_enable_vblank, .enable_vblank = vidi_enable_vblank,
.disable_vblank = vidi_disable_vblank, .disable_vblank = vidi_disable_vblank,
...@@ -553,22 +546,21 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) ...@@ -553,22 +546,21 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
{ {
struct vidi_context *ctx = dev_get_drvdata(dev); struct vidi_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
struct drm_crtc *crtc = ctx->crtc;
int ret; int ret;
vidi_mgr_initialize(&ctx->manager, drm_dev); ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
EXYNOS_DISPLAY_TYPE_VIDI,
ret = exynos_drm_crtc_create(&ctx->manager, drm_dev, ctx->pipe, &vidi_crtc_ops, ctx);
EXYNOS_DISPLAY_TYPE_VIDI); if (IS_ERR(ctx->crtc)) {
if (ret) {
DRM_ERROR("failed to create crtc.\n"); DRM_ERROR("failed to create crtc.\n");
return ret; return PTR_ERR(ctx->crtc);
} }
vidi_ctx_initialize(ctx, drm_dev);
ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display); ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
if (ret) { if (ret) {
crtc->funcs->destroy(crtc); ctx->crtc->base.funcs->destroy(&ctx->crtc->base);
DRM_ERROR("failed to create encoder and connector.\n");
return ret; return ret;
} }
...@@ -594,7 +586,6 @@ static int vidi_probe(struct platform_device *pdev) ...@@ -594,7 +586,6 @@ static int vidi_probe(struct platform_device *pdev)
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
ctx->manager.ops = &vidi_manager_ops;
ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI; ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
ctx->display.ops = &vidi_display_ops; ctx->display.ops = &vidi_display_ops;
ctx->default_win = 0; ctx->default_win = 0;
......
...@@ -84,10 +84,10 @@ enum mixer_version_id { ...@@ -84,10 +84,10 @@ enum mixer_version_id {
}; };
struct mixer_context { struct mixer_context {
struct exynos_drm_manager manager;
struct platform_device *pdev; struct platform_device *pdev;
struct device *dev; struct device *dev;
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct exynos_drm_crtc *crtc;
int pipe; int pipe;
bool interlace; bool interlace;
bool powered; bool powered;
...@@ -103,11 +103,6 @@ struct mixer_context { ...@@ -103,11 +103,6 @@ struct mixer_context {
atomic_t wait_vsync_event; atomic_t wait_vsync_event;
}; };
static inline struct mixer_context *mgr_to_mixer(struct exynos_drm_manager *mgr)
{
return container_of(mgr, struct mixer_context, manager);
}
struct mixer_drv_data { struct mixer_drv_data {
enum mixer_version_id version; enum mixer_version_id version;
bool is_vp_enabled; bool is_vp_enabled;
...@@ -854,11 +849,10 @@ static int vp_resources_init(struct mixer_context *mixer_ctx) ...@@ -854,11 +849,10 @@ static int vp_resources_init(struct mixer_context *mixer_ctx)
return 0; return 0;
} }
static int mixer_initialize(struct exynos_drm_manager *mgr, static int mixer_initialize(struct mixer_context *mixer_ctx,
struct drm_device *drm_dev) struct drm_device *drm_dev)
{ {
int ret; int ret;
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
struct exynos_drm_private *priv; struct exynos_drm_private *priv;
priv = drm_dev->dev_private; priv = drm_dev->dev_private;
...@@ -887,17 +881,15 @@ static int mixer_initialize(struct exynos_drm_manager *mgr, ...@@ -887,17 +881,15 @@ static int mixer_initialize(struct exynos_drm_manager *mgr,
return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev); return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
} }
static void mixer_mgr_remove(struct exynos_drm_manager *mgr) static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
{ {
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
if (is_drm_iommu_supported(mixer_ctx->drm_dev)) if (is_drm_iommu_supported(mixer_ctx->drm_dev))
drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev); drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
} }
static int mixer_enable_vblank(struct exynos_drm_manager *mgr) static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct mixer_context *mixer_ctx = crtc->ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res; struct mixer_resources *res = &mixer_ctx->mixer_res;
if (!mixer_ctx->powered) { if (!mixer_ctx->powered) {
...@@ -912,19 +904,19 @@ static int mixer_enable_vblank(struct exynos_drm_manager *mgr) ...@@ -912,19 +904,19 @@ static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
return 0; return 0;
} }
static void mixer_disable_vblank(struct exynos_drm_manager *mgr) static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct mixer_context *mixer_ctx = crtc->ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res; struct mixer_resources *res = &mixer_ctx->mixer_res;
/* disable vsync interrupt */ /* disable vsync interrupt */
mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
} }
static void mixer_win_mode_set(struct exynos_drm_manager *mgr, static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane) struct exynos_drm_plane *plane)
{ {
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct mixer_context *mixer_ctx = crtc->ctx;
struct hdmi_win_data *win_data; struct hdmi_win_data *win_data;
int win; int win;
...@@ -973,9 +965,9 @@ static void mixer_win_mode_set(struct exynos_drm_manager *mgr, ...@@ -973,9 +965,9 @@ static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
win_data->scan_flags = plane->scan_flag; win_data->scan_flags = plane->scan_flag;
} }
static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos) static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
{ {
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct mixer_context *mixer_ctx = crtc->ctx;
int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
DRM_DEBUG_KMS("win: %d\n", win); DRM_DEBUG_KMS("win: %d\n", win);
...@@ -995,9 +987,9 @@ static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos) ...@@ -995,9 +987,9 @@ static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
mixer_ctx->win_data[win].enabled = true; mixer_ctx->win_data[win].enabled = true;
} }
static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos) static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
{ {
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct mixer_context *mixer_ctx = crtc->ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res; struct mixer_resources *res = &mixer_ctx->mixer_res;
int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
unsigned long flags; unsigned long flags;
...@@ -1023,9 +1015,9 @@ static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos) ...@@ -1023,9 +1015,9 @@ static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
mixer_ctx->win_data[win].enabled = false; mixer_ctx->win_data[win].enabled = false;
} }
static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
{ {
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); struct mixer_context *mixer_ctx = crtc->ctx;
int err; int err;
mutex_lock(&mixer_ctx->mixer_mutex); mutex_lock(&mixer_ctx->mixer_mutex);
...@@ -1035,7 +1027,7 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) ...@@ -1035,7 +1027,7 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
} }
mutex_unlock(&mixer_ctx->mixer_mutex); mutex_unlock(&mixer_ctx->mixer_mutex);
err = drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe); err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
if (err < 0) { if (err < 0) {
DRM_DEBUG_KMS("failed to acquire vblank counter\n"); DRM_DEBUG_KMS("failed to acquire vblank counter\n");
return; return;
...@@ -1052,26 +1044,26 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) ...@@ -1052,26 +1044,26 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
HZ/20)) HZ/20))
DRM_DEBUG_KMS("vblank wait timed out.\n"); DRM_DEBUG_KMS("vblank wait timed out.\n");
drm_vblank_put(mgr->crtc->dev, mixer_ctx->pipe); drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
} }
static void mixer_window_suspend(struct exynos_drm_manager *mgr) static void mixer_window_suspend(struct exynos_drm_crtc *crtc)
{ {
struct mixer_context *ctx = mgr_to_mixer(mgr); struct mixer_context *ctx = crtc->ctx;
struct hdmi_win_data *win_data; struct hdmi_win_data *win_data;
int i; int i;
for (i = 0; i < MIXER_WIN_NR; i++) { for (i = 0; i < MIXER_WIN_NR; i++) {
win_data = &ctx->win_data[i]; win_data = &ctx->win_data[i];
win_data->resume = win_data->enabled; win_data->resume = win_data->enabled;
mixer_win_disable(mgr, i); mixer_win_disable(crtc, i);
} }
mixer_wait_for_vblank(mgr); mixer_wait_for_vblank(crtc);
} }
static void mixer_window_resume(struct exynos_drm_manager *mgr) static void mixer_window_resume(struct exynos_drm_crtc *crtc)
{ {
struct mixer_context *ctx = mgr_to_mixer(mgr); struct mixer_context *ctx = crtc->ctx;
struct hdmi_win_data *win_data; struct hdmi_win_data *win_data;
int i; int i;
...@@ -1080,13 +1072,13 @@ static void mixer_window_resume(struct exynos_drm_manager *mgr) ...@@ -1080,13 +1072,13 @@ static void mixer_window_resume(struct exynos_drm_manager *mgr)
win_data->enabled = win_data->resume; win_data->enabled = win_data->resume;
win_data->resume = false; win_data->resume = false;
if (win_data->enabled) if (win_data->enabled)
mixer_win_commit(mgr, i); mixer_win_commit(crtc, i);
} }
} }
static void mixer_poweron(struct exynos_drm_manager *mgr) static void mixer_poweron(struct exynos_drm_crtc *crtc)
{ {
struct mixer_context *ctx = mgr_to_mixer(mgr); struct mixer_context *ctx = crtc->ctx;
struct mixer_resources *res = &ctx->mixer_res; struct mixer_resources *res = &ctx->mixer_res;
mutex_lock(&ctx->mixer_mutex); mutex_lock(&ctx->mixer_mutex);
...@@ -1115,12 +1107,12 @@ static void mixer_poweron(struct exynos_drm_manager *mgr) ...@@ -1115,12 +1107,12 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
mixer_reg_write(res, MXR_INT_EN, ctx->int_en); mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
mixer_win_reset(ctx); mixer_win_reset(ctx);
mixer_window_resume(mgr); mixer_window_resume(crtc);
} }
static void mixer_poweroff(struct exynos_drm_manager *mgr) static void mixer_poweroff(struct exynos_drm_crtc *crtc)
{ {
struct mixer_context *ctx = mgr_to_mixer(mgr); struct mixer_context *ctx = crtc->ctx;
struct mixer_resources *res = &ctx->mixer_res; struct mixer_resources *res = &ctx->mixer_res;
mutex_lock(&ctx->mixer_mutex); mutex_lock(&ctx->mixer_mutex);
...@@ -1131,7 +1123,7 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr) ...@@ -1131,7 +1123,7 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
mutex_unlock(&ctx->mixer_mutex); mutex_unlock(&ctx->mixer_mutex);
mixer_stop(ctx); mixer_stop(ctx);
mixer_window_suspend(mgr); mixer_window_suspend(crtc);
ctx->int_en = mixer_reg_read(res, MXR_INT_EN); ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
...@@ -1149,16 +1141,16 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr) ...@@ -1149,16 +1141,16 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
pm_runtime_put_sync(ctx->dev); pm_runtime_put_sync(ctx->dev);
} }
static void mixer_dpms(struct exynos_drm_manager *mgr, int mode) static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
{ {
switch (mode) { switch (mode) {
case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_ON:
mixer_poweron(mgr); mixer_poweron(crtc);
break; break;
case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF: case DRM_MODE_DPMS_OFF:
mixer_poweroff(mgr); mixer_poweroff(crtc);
break; break;
default: default:
DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
...@@ -1186,7 +1178,7 @@ int mixer_check_mode(struct drm_display_mode *mode) ...@@ -1186,7 +1178,7 @@ int mixer_check_mode(struct drm_display_mode *mode)
return -EINVAL; return -EINVAL;
} }
static struct exynos_drm_manager_ops mixer_manager_ops = { static struct exynos_drm_crtc_ops mixer_crtc_ops = {
.dpms = mixer_dpms, .dpms = mixer_dpms,
.enable_vblank = mixer_enable_vblank, .enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank, .disable_vblank = mixer_disable_vblank,
...@@ -1257,25 +1249,30 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) ...@@ -1257,25 +1249,30 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
int ret; int ret;
ret = mixer_initialize(&ctx->manager, drm_dev); ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
if (ret) EXYNOS_DISPLAY_TYPE_HDMI,
return ret; &mixer_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) {
ret = exynos_drm_crtc_create(&ctx->manager, drm_dev, ctx->pipe, ret = PTR_ERR(ctx->crtc);
EXYNOS_DISPLAY_TYPE_HDMI); goto free_ctx;
if (ret) {
mixer_mgr_remove(&ctx->manager);
return ret;
} }
ret = mixer_initialize(ctx, drm_dev);
if (ret)
goto free_ctx;
return 0; return 0;
free_ctx:
devm_kfree(dev, ctx);
return ret;
} }
static void mixer_unbind(struct device *dev, struct device *master, void *data) static void mixer_unbind(struct device *dev, struct device *master, void *data)
{ {
struct mixer_context *ctx = dev_get_drvdata(dev); struct mixer_context *ctx = dev_get_drvdata(dev);
mixer_mgr_remove(&ctx->manager); mixer_ctx_remove(ctx);
} }
static const struct component_ops mixer_component_ops = { static const struct component_ops mixer_component_ops = {
...@@ -1298,8 +1295,6 @@ static int mixer_probe(struct platform_device *pdev) ...@@ -1298,8 +1295,6 @@ static int mixer_probe(struct platform_device *pdev)
mutex_init(&ctx->mixer_mutex); mutex_init(&ctx->mixer_mutex);
ctx->manager.ops = &mixer_manager_ops;
if (dev->of_node) { if (dev->of_node) {
const struct of_device_id *match; const struct of_device_id *match;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment