From 29cb602532b0a82f22322cece8a89f022368d557 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Wed, 5 Sep 2012 14:12:06 +0900 Subject: drm/exynos: added device object to subdrv's remove callback as argument when remove callback of exynos_drm_subdrv is called, it could need device object for sub driver to control things specific to hw such as runtime pm. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_core.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 84dd099eae3b..80cba2f413f4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -94,7 +94,7 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev, DRM_DEBUG_DRIVER("%s\n", __FILE__); if (subdrv->remove) - subdrv->remove(dev); + subdrv->remove(dev, subdrv->dev); if (subdrv->encoder) { struct drm_encoder *encoder = subdrv->encoder; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index e22704b249d7..24c45d86bab0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -266,7 +266,7 @@ struct exynos_drm_subdrv { struct exynos_drm_manager *manager; int (*probe)(struct drm_device *drm_dev, struct device *dev); - void (*remove)(struct drm_device *dev); + void (*remove)(struct drm_device *drm_dev, struct device *dev); int (*open)(struct drm_device *drm_dev, struct device *dev, struct drm_file *file); void (*close)(struct drm_device *drm_dev, struct device *dev, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index b19cd93e7047..47396e13b460 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -678,7 +678,7 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev) return 0; } -static void fimd_subdrv_remove(struct drm_device *drm_dev) +static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev) { DRM_DEBUG_KMS("%s\n", __FILE__); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index e364165f1a2a..c95f7dedb8a0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -453,7 +453,7 @@ static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) return 0; } -static void vidi_subdrv_remove(struct drm_device *drm_dev) +static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev) { DRM_DEBUG_KMS("%s\n", __FILE__); -- cgit v1.2.3 From 41fecf3e8268b8f285c91620c20895e946db9177 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 17 Aug 2012 13:23:25 +0900 Subject: drm/exynos: separated subdrv_probe function into two parts. Changelog v2: fixed the issue that when sub driver is probed, no kms drivers such as fimd or hdmi are failed. no kms drivers have no manager so if manager is null then encoder and connector creation should be ignored. Changelog v1: this patch separates exynos_drm_subdrv_probe function into sub driver's probe call and encoder/connector creation so that exynos drm core module can take exception when some operation was failed properly. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_core.c | 100 +++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 31 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 80cba2f413f4..7b0432b7a364 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -34,33 +34,15 @@ static LIST_HEAD(exynos_drm_subdrv_list); -static int exynos_drm_subdrv_probe(struct drm_device *dev, +static int exynos_drm_create_enc_conn(struct drm_device *dev, struct exynos_drm_subdrv *subdrv) { struct drm_encoder *encoder; struct drm_connector *connector; + int ret; DRM_DEBUG_DRIVER("%s\n", __FILE__); - if (subdrv->probe) { - int ret; - - /* - * this probe callback would be called by sub driver - * after setting of all resources to this sub driver, - * such as clock, irq and register map are done or by load() - * of exynos drm driver. - * - * P.S. note that this driver is considered for modularization. - */ - ret = subdrv->probe(dev, subdrv->dev); - if (ret) - return ret; - } - - if (!subdrv->manager) - return 0; - subdrv->manager->dev = subdrv->dev; /* create and initialize a encoder for this sub driver. */ @@ -78,24 +60,22 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev, connector = exynos_drm_connector_create(dev, encoder); if (!connector) { DRM_ERROR("failed to create connector\n"); - encoder->funcs->destroy(encoder); - return -EFAULT; + ret = -EFAULT; + goto err_destroy_encoder; } subdrv->encoder = encoder; subdrv->connector = connector; return 0; + +err_destroy_encoder: + encoder->funcs->destroy(encoder); + return ret; } -static void exynos_drm_subdrv_remove(struct drm_device *dev, - struct exynos_drm_subdrv *subdrv) +static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv) { - DRM_DEBUG_DRIVER("%s\n", __FILE__); - - if (subdrv->remove) - subdrv->remove(dev, subdrv->dev); - if (subdrv->encoder) { struct drm_encoder *encoder = subdrv->encoder; encoder->funcs->destroy(encoder); @@ -109,9 +89,43 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev, } } +static int exynos_drm_subdrv_probe(struct drm_device *dev, + struct exynos_drm_subdrv *subdrv) +{ + if (subdrv->probe) { + int ret; + + subdrv->drm_dev = dev; + + /* + * this probe callback would be called by sub driver + * after setting of all resources to this sub driver, + * such as clock, irq and register map are done or by load() + * of exynos drm driver. + * + * P.S. note that this driver is considered for modularization. + */ + ret = subdrv->probe(dev, subdrv->dev); + if (ret) + return ret; + } + + return 0; +} + +static void exynos_drm_subdrv_remove(struct drm_device *dev, + struct exynos_drm_subdrv *subdrv) +{ + DRM_DEBUG_DRIVER("%s\n", __FILE__); + + if (subdrv->remove) + subdrv->remove(dev, subdrv->dev); +} + int exynos_drm_device_register(struct drm_device *dev) { struct exynos_drm_subdrv *subdrv, *n; + unsigned int fine_cnt = 0; int err; DRM_DEBUG_DRIVER("%s\n", __FILE__); @@ -120,14 +134,36 @@ int exynos_drm_device_register(struct drm_device *dev) return -EINVAL; list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { - subdrv->drm_dev = dev; err = exynos_drm_subdrv_probe(dev, subdrv); if (err) { DRM_DEBUG("exynos drm subdrv probe failed.\n"); 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); @@ -143,8 +179,10 @@ int exynos_drm_device_unregister(struct drm_device *dev) return -EINVAL; } - list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) + list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { exynos_drm_subdrv_remove(dev, subdrv); + exynos_drm_destroy_enc_conn(subdrv); + } return 0; } -- cgit v1.2.3 From 5d55393a85f9a3c9ce93d17ae85b53c4f9f33bff Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 17 Aug 2012 17:08:04 +0900 Subject: drm/exynos: separeated fimd_power_on into some parts. Changelog v2: fix pm operation when resume. Changelog v1: this patch separetes fimd_power_on into fimd_activate and fimd_clock and fimd_activate function will call fimd_clock to control fimd power and vsync interrupt. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 60 +++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 20 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 47396e13b460..28733cd52745 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -747,16 +747,10 @@ static void fimd_clear_win(struct fimd_context *ctx, int win) writel(val, ctx->regs + SHADOWCON); } -static int fimd_power_on(struct fimd_context *ctx, bool enable) +static int fimd_clock(struct fimd_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) { int ret; @@ -769,18 +763,31 @@ static int fimd_power_on(struct fimd_context *ctx, bool enable) clk_disable(ctx->bus_clk); return ret; } + } else { + clk_disable(ctx->lcd_clk); + clk_disable(ctx->bus_clk); + } + + return 0; +} + +static int fimd_activate(struct fimd_context *ctx, bool enable) +{ + if (enable) { + int ret; + struct device *dev = ctx->subdrv.dev; + + ret = fimd_clock(ctx, true); + if (ret < 0) + return ret; ctx->suspended = false; /* if vblank was enabled status, enable it again. */ if (test_and_clear_bit(0, &ctx->irq_flags)) fimd_enable_vblank(dev); - - fimd_apply(dev); } else { - clk_disable(ctx->lcd_clk); - clk_disable(ctx->bus_clk); - + fimd_clock(ctx, false); ctx->suspended = true; } @@ -930,15 +937,15 @@ static int fimd_suspend(struct device *dev) { struct fimd_context *ctx = get_fimd_context(dev); - if (pm_runtime_suspended(dev)) - return 0; - /* * do not use pm_runtime_suspend(). if pm_runtime_suspend() is * called here, an error would be returned by that interface * because the usage_count of pm runtime is more than 1. */ - return fimd_power_on(ctx, false); + if (!pm_runtime_suspended(dev)) + return fimd_activate(ctx, false); + + return 0; } static int fimd_resume(struct device *dev) @@ -950,8 +957,21 @@ static int fimd_resume(struct device *dev) * of pm runtime would still be 1 so in this case, fimd driver * should be on directly not drawing on pm runtime interface. */ - if (!pm_runtime_suspended(dev)) - return fimd_power_on(ctx, true); + if (pm_runtime_suspended(dev)) { + int ret; + + ret = fimd_activate(ctx, true); + if (ret < 0) + return ret; + + /* + * in case of dpms on(standby), fimd_apply function will + * be called by encoder's dpms callback to update fimd's + * registers but in case of sleep wakeup, it's not. + * so fimd_apply function should be called at here. + */ + fimd_apply(dev); + } return 0; } @@ -964,7 +984,7 @@ static int fimd_runtime_suspend(struct device *dev) DRM_DEBUG_KMS("%s\n", __FILE__); - return fimd_power_on(ctx, false); + return fimd_activate(ctx, false); } static int fimd_runtime_resume(struct device *dev) @@ -973,7 +993,7 @@ static int fimd_runtime_resume(struct device *dev) DRM_DEBUG_KMS("%s\n", __FILE__); - return fimd_power_on(ctx, true); + return fimd_activate(ctx, true); } #endif -- cgit v1.2.3 From 50caf25c583b938c681b61e64dac58da9b640f2f Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 20 Aug 2012 21:29:25 +0900 Subject: drm/exynos: fixed duplicated mode setting. this patch fixes that when drm_crtc_helper_set_mode() is called, mode data for hardware overlay and conntroller are updated two times. for example, in case that drm_crtc_helper_set_mode() is called, overlay_ops->commit() and manager_ops->commit() callbacks can be called two times, first at drm_crtc_helper_set_mode() and second at drm_helper_connector_dpms(). Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_connector.c | 41 ++++++++++++++++++++++++++- drivers/gpu/drm/exynos/exynos_drm_connector.h | 2 ++ drivers/gpu/drm/exynos/exynos_drm_crtc.c | 3 +- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 30 +++++++++++++------- 4 files changed, 62 insertions(+), 14 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index 9dce3b9c3896..59e79ff4b2eb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c @@ -40,6 +40,7 @@ struct exynos_drm_connector { struct drm_connector drm_connector; uint32_t encoder_id; struct exynos_drm_manager *manager; + uint32_t dpms; }; /* convert exynos_video_timings to drm_display_mode */ @@ -224,6 +225,43 @@ 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 = connector->encoder; + 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) +{ + DRM_DEBUG_KMS("%s\n", __FILE__); + + /* + * 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) { @@ -283,7 +321,7 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs exynos_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = exynos_drm_connector_dpms, .fill_modes = exynos_drm_connector_fill_modes, .detect = exynos_drm_connector_detect, .destroy = exynos_drm_connector_destroy, @@ -332,6 +370,7 @@ 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->encoder = encoder; err = drm_mode_connector_attach_encoder(connector, encoder); diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h index 1c7b2b5b579c..40a55c2de4bc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.h +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.h @@ -31,4 +31,6 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, struct drm_encoder *encoder); +void exynos_drm_display_power(struct drm_connector *connector, int mode); + #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index abb1e2f8227f..b612bf5bc1a8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -97,6 +97,7 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc) DRM_DEBUG_KMS("%s\n", __FILE__); + exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); exynos_plane_commit(exynos_crtc->plane); exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); } @@ -126,8 +127,6 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, DRM_DEBUG_KMS("%s\n", __FILE__); - exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); - /* * copy the mode data adjusted by mode_fixup() into crtc->mode * so that hardware can be seet to proper mode. diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 2c037cd7d2d4..08ba62fe2f16 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -31,6 +31,7 @@ #include "exynos_drm_drv.h" #include "exynos_drm_encoder.h" +#include "exynos_drm_connector.h" #define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\ drm_encoder) @@ -49,21 +50,17 @@ struct exynos_drm_encoder { int dpms; }; -static void exynos_drm_display_power(struct drm_encoder *encoder, int mode) +static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_connector *connector; - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->encoder == encoder) { - struct exynos_drm_display_ops *display_ops = - manager->display_ops; - DRM_DEBUG_KMS("connector[%d] dpms[%d]\n", connector->base.id, mode); - if (display_ops && display_ops->power_on) - display_ops->power_on(manager->dev, mode); + + exynos_drm_display_power(connector, mode); } } } @@ -88,13 +85,13 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_ON: if (manager_ops && manager_ops->apply) manager_ops->apply(manager->dev); - exynos_drm_display_power(encoder, mode); + 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_display_power(encoder, mode); + exynos_drm_connector_power(encoder, mode); exynos_encoder->dpms = mode; break; default: @@ -138,8 +135,6 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, DRM_DEBUG_KMS("%s\n", __FILE__); - exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_ON); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->encoder == encoder) if (manager_ops && manager_ops->mode_set) @@ -337,6 +332,19 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data) if (manager_ops && manager_ops->dpms) manager_ops->dpms(manager->dev, mode); + /* + * set current mode to new one so that data aren't updated into + * registers by drm_helper_connector_dpms two times. + * + * in case that drm_crtc_helper_set_mode() is called, + * overlay_ops->commit() and manager_ops->commit() callbacks + * can be called two times, first at drm_crtc_helper_set_mode() + * and second at drm_helper_connector_dpms(). + * so with this setting, when drm_helper_connector_dpms() is called + * encoder->funcs->dpms() will be ignored. + */ + exynos_encoder->dpms = mode; + /* * if this condition is ok then it means that the crtc is already * detached from encoder and last function for detaching is properly -- cgit v1.2.3 From b011941f0ffdefb87585d9ed786164037d0d50df Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 20 Aug 2012 19:55:14 +0900 Subject: drm/exynos: add wait_for_vblank callback interface. Changelog v2: fixed comments. Changelog v1: this interface can be used to make sure that hardware overlay is disabled to avoid that memory region is accessed by dma after gem buffer was released. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 17 +++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_encoder.c | 10 ++++++++++ 2 files changed, 27 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 24c45d86bab0..eec77aa6962f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -37,6 +37,20 @@ #define MAX_FB_BUFFER 4 #define DEFAULT_ZPOS -1 +#define _wait_for(COND, MS) ({ \ + unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ + int ret__ = 0; \ + while (!(COND)) { \ + if (time_after(jiffies, timeout__)) { \ + ret__ = -ETIMEDOUT; \ + break; \ + } \ + } \ + ret__; \ +}) + +#define wait_for(COND, MS) _wait_for(COND, MS) + struct drm_device; struct exynos_drm_overlay; struct drm_connector; @@ -61,6 +75,8 @@ enum exynos_drm_output_type { * @commit: apply hardware specific overlay data to registers. * @enable: enable hardware specific overlay. * @disable: disable hardware specific overlay. + * @wait_for_vblank: wait for vblank interrupt to make sure that + * hardware overlay is disabled. */ struct exynos_drm_overlay_ops { void (*mode_set)(struct device *subdrv_dev, @@ -68,6 +84,7 @@ struct exynos_drm_overlay_ops { void (*commit)(struct device *subdrv_dev, int zpos); void (*enable)(struct device *subdrv_dev, int zpos); void (*disable)(struct device *subdrv_dev, int zpos); + void (*wait_for_vblank)(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 08ba62fe2f16..f4531167fda6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -430,4 +430,14 @@ void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data) if (overlay_ops && overlay_ops->disable) overlay_ops->disable(manager->dev, zpos); + + /* + * wait for vblank interrupt + * - this makes sure that hardware overlay is disabled to avoid + * for the dma accesses to memory after gem buffer was released + * because the setting for disabling the overlay will be updated + * at vsync. + */ + if (overlay_ops->wait_for_vblank) + overlay_ops->wait_for_vblank(manager->dev); } -- cgit v1.2.3 From 479cbc3eeed060879dc89652e497d7719f7ee1dc Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 20 Aug 2012 19:58:05 +0900 Subject: drm/exynos: make sure that hardware overlay for fimd is disabled Changelog v2: wait for VSYNC instead of BACKPORCH. Changelog v1: the values set to registers will be updated into real registers at vsync so dma operation could be malfunctioned when accessed to memory after gem buffer was released. this patch makes sure that hw overlay is disabled before the gem buffer is released. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 28733cd52745..1da741fc7460 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -570,10 +570,22 @@ static void fimd_win_disable(struct device *dev, int zpos) win_data->enabled = false; } +static void fimd_wait_for_vblank(struct device *dev) +{ + struct fimd_context *ctx = get_fimd_context(dev); + int ret; + + ret = wait_for((__raw_readl(ctx->regs + VIDCON1) & + VIDCON1_VSTATUS_VSYNC), 50); + if (ret < 0) + DRM_DEBUG_KMS("vblank wait timed out.\n"); +} + static struct exynos_drm_overlay_ops fimd_overlay_ops = { .mode_set = fimd_win_mode_set, .commit = fimd_win_commit, .disable = fimd_win_disable, + .wait_for_vblank = fimd_wait_for_vblank, }; static struct exynos_drm_manager fimd_manager = { -- cgit v1.2.3 From 3d05859fd78bbc0b04cca929aea494f5e6b8235b Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 17 Aug 2012 18:35:47 +0900 Subject: drm/exynos: make sure that hardware overlay for hdmi is disabled the values set to registers will be updated into real registers at vsync so dma operation could be malfunctioned when accessed to memory after gem buffer was released. this patch makes sure that hw overlay is disabled before the gem buffer is released. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 11 +++++++++++ drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 1 + drivers/gpu/drm/exynos/exynos_mixer.c | 13 +++++++++++++ 3 files changed, 25 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index 3fdf0b65f47e..0584132dc608 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -274,10 +274,21 @@ static void drm_mixer_disable(struct device *subdrv_dev, int zpos) ctx->enabled[win] = false; } +static void drm_mixer_wait_for_vblank(struct device *subdrv_dev) +{ + struct drm_hdmi_context *ctx = to_context(subdrv_dev); + + DRM_DEBUG_KMS("%s\n", __FILE__); + + if (mixer_ops && mixer_ops->wait_for_vblank) + mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx); +} + static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = { .mode_set = drm_mixer_mode_set, .commit = drm_mixer_commit, .disable = drm_mixer_disable, + .wait_for_vblank = drm_mixer_wait_for_vblank, }; static struct exynos_drm_manager hdmi_manager = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h index a91c42088e42..d9f9e9fcc2b6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h @@ -67,6 +67,7 @@ struct exynos_mixer_ops { void (*dpms)(void *ctx, int mode); /* overlay */ + 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_disable)(void *ctx, int zpos); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 25b97d5e5fcb..8a43ee17039e 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -726,6 +726,18 @@ static void mixer_dpms(void *ctx, int mode) } } +static void mixer_wait_for_vblank(void *ctx) +{ + struct mixer_context *mixer_ctx = ctx; + struct mixer_resources *res = &mixer_ctx->mixer_res; + int ret; + + ret = wait_for((mixer_reg_read(res, MXR_INT_STATUS) & + MXR_INT_STATUS_VSYNC), 50); + if (ret < 0) + DRM_DEBUG_KMS("vblank wait timed out.\n"); +} + static void mixer_win_mode_set(void *ctx, struct exynos_drm_overlay *overlay) { @@ -818,6 +830,7 @@ static struct exynos_mixer_ops mixer_ops = { .dpms = mixer_dpms, /* overlay */ + .wait_for_vblank = mixer_wait_for_vblank, .win_mode_set = mixer_win_mode_set, .win_commit = mixer_win_commit, .win_disable = mixer_win_disable, -- cgit v1.2.3 From 01ed812671c1163b35bf6ce9be221bd371bf9a8f Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 20 Aug 2012 20:05:56 +0900 Subject: drm/exynos: check NV12M format specific to Exynos properly this patch adds buf_cnt variable in exynos_drm_fb structure and that means a buffer count to drm framebuffer and also adds two functions to get/set the buffer count from/to exynos_drm_fb structure. if pixel format is not DRM_FORMAT_NV12MT then it gets a buffer count to drm framebuffer refering to mode_cmd->handles and offsets. but when booted, the buffer count will always be 1 because pixel format of console framebuffer is RGB format. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 65 +++++++++++++++++++++++++++++-- drivers/gpu/drm/exynos/exynos_drm_fb.h | 20 ++++------ drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 3 ++ drivers/gpu/drm/exynos/exynos_drm_plane.c | 2 +- 4 files changed, 73 insertions(+), 17 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 4ccfe4328fab..98f8b839673a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -41,10 +41,12 @@ * exynos specific framebuffer structure. * * @fb: drm framebuffer obejct. + * @buf_cnt: a buffer count to drm framebuffer. * @exynos_gem_obj: array of exynos specific gem object containing a gem object. */ struct exynos_drm_fb { struct drm_framebuffer fb; + unsigned int buf_cnt; struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER]; }; @@ -101,6 +103,25 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { .dirty = exynos_drm_fb_dirty, }; +void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb, + unsigned int cnt) +{ + struct exynos_drm_fb *exynos_fb; + + exynos_fb = to_exynos_fb(fb); + + exynos_fb->buf_cnt = cnt; +} + +unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb) +{ + struct exynos_drm_fb *exynos_fb; + + exynos_fb = to_exynos_fb(fb); + + return exynos_fb->buf_cnt; +} + struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, @@ -127,6 +148,43 @@ exynos_drm_framebuffer_init(struct drm_device *dev, return &exynos_fb->fb; } +static u32 exynos_drm_format_num_buffers(struct drm_mode_fb_cmd2 *mode_cmd) +{ + unsigned int cnt = 0; + + if (mode_cmd->pixel_format != DRM_FORMAT_NV12) + return drm_format_num_planes(mode_cmd->pixel_format); + + while (cnt != MAX_FB_BUFFER) { + if (!mode_cmd->handles[cnt]) + break; + cnt++; + } + + /* + * check if NV12 or NV12M. + * + * NV12 + * handles[0] = base1, offsets[0] = 0 + * handles[1] = base1, offsets[1] = Y_size + * + * NV12M + * handles[0] = base1, offsets[0] = 0 + * handles[1] = base2, offsets[1] = 0 + */ + if (cnt == 2) { + /* + * in case of NV12 format, offsets[1] is not 0 and + * handles[0] is same as handles[1]. + */ + if (mode_cmd->offsets[1] && + mode_cmd->handles[0] == mode_cmd->handles[1]) + cnt = 1; + } + + return cnt; +} + static struct drm_framebuffer * exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) @@ -134,7 +192,6 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_gem_object *obj; struct drm_framebuffer *fb; struct exynos_drm_fb *exynos_fb; - int nr; int i; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -152,9 +209,11 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, } exynos_fb = to_exynos_fb(fb); - nr = exynos_drm_format_num_buffers(fb->pixel_format); + exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd); + + DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt); - for (i = 1; i < nr; i++) { + for (i = 1; i < exynos_fb->buf_cnt; i++) { obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[i]); if (!obj) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index 50823756cdea..96262e54f76d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -28,19 +28,6 @@ #ifndef _EXYNOS_DRM_FB_H_ #define _EXYNOS_DRM_FB_H -static inline int exynos_drm_format_num_buffers(uint32_t format) -{ - switch (format) { - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV12MT: - return 2; - case DRM_FORMAT_YUV420: - return 3; - default: - return 1; - } -} - struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, @@ -52,4 +39,11 @@ struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, void exynos_drm_mode_config_init(struct drm_device *dev); +/* set a buffer count to drm framebuffer. */ +void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb, + unsigned int cnt); + +/* get a buffer count to drm framebuffer. */ +unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb); + #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index f4ac43356583..d7205f8b2301 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -79,6 +79,9 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, return -EFAULT; } + /* buffer count to framebuffer always is 1 at booting time. */ + exynos_drm_fb_set_buf_cnt(fb, 1); + offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); offset += fbi->var.yoffset * fb->pitches[0]; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index e1f94b746bd7..8c3036dd512b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -47,7 +47,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); - nr = exynos_drm_format_num_buffers(fb->pixel_format); + nr = exynos_drm_fb_get_buf_cnt(fb); for (i = 0; i < nr; i++) { struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i); -- cgit v1.2.3 From 1b85a0715f4615f953733c4afa6ec59cd0e73b52 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 17 Aug 2012 17:58:38 +0900 Subject: drm/exynos: update crtc to plane safely if old_crtc isn't same as encoder->crtc then it means that user changed crtc id to another one so a plane to old_crtc should be disabled so that current plane can be updated safely and plane->crtc should be set to new crtc(encoder->crtc) Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 59 +++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index f4531167fda6..92f9acf77b7f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -45,6 +45,7 @@ * @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; @@ -124,22 +125,74 @@ 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 overlay_ops->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_manager *manager = exynos_drm_get_manager(encoder); - struct exynos_drm_manager_ops *manager_ops = manager->ops; + struct exynos_drm_manager *manager; + struct exynos_drm_manager_ops *manager_ops; DRM_DEBUG_KMS("%s\n", __FILE__); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) + 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); + } + + manager = exynos_drm_get_manager(encoder); + manager_ops = manager->ops; + if (manager_ops && manager_ops->mode_set) manager_ops->mode_set(manager->dev, adjusted_mode); + + exynos_encoder->old_crtc = encoder->crtc; + } } } -- cgit v1.2.3 From bcf4cef94294992f7cd11d5a90fa58b0eae6c795 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 24 Aug 2012 10:54:12 -0700 Subject: drm/exynos: Disable plane when released this patch ensures that each plane connected to encoder is disabled when released, by adding disable callback function of encoder helper we had faced with one issue that invalid memory is accessed by dma once drm is released and then the dma is turned on again. actually, in our case, page fault was incurred with iommu. the reason is that a gem buffer accessed by the dma is also released once drm is released. so this patch would fix this issue ensuring the dma is disabled when released. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 92f9acf77b7f..96a10c38cd72 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -214,12 +214,27 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder) manager_ops->commit(manager->dev); } +static void exynos_drm_encoder_disable(struct drm_encoder *encoder) +{ + struct drm_plane *plane; + struct drm_device *dev = encoder->dev; + + exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + + /* all planes connected to this encoder should be also disabled. */ + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + if (plane->crtc == encoder->crtc) + plane->funcs->disable_plane(plane); + } +} + static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { .dpms = exynos_drm_encoder_dpms, .mode_fixup = exynos_drm_encoder_mode_fixup, .mode_set = exynos_drm_encoder_mode_set, .prepare = exynos_drm_encoder_prepare, .commit = exynos_drm_encoder_commit, + .disable = exynos_drm_encoder_disable, }; static void exynos_drm_encoder_destroy(struct drm_encoder *encoder) -- cgit v1.2.3 From 6b6bae24c7caac8f2a80f24e5ff5e82276eb03fd Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Tue, 11 Sep 2012 10:45:36 +0900 Subject: drm/exynos: add pid to g2d_runqueue_node this patch adds pid to g2d_runqueue_node as member to identify which process owns this node. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 1065e90d0919..dcbc4cb423be 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -122,6 +122,7 @@ struct g2d_runqueue_node { struct list_head list; struct list_head run_cmdlist; struct list_head event_list; + pid_t pid; struct completion complete; int async; }; @@ -679,6 +680,7 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, } mutex_lock(&g2d->runqueue_mutex); + runqueue_node->pid = current->pid; list_add_tail(&runqueue_node->list, &g2d->runqueue); if (!g2d->runqueue_node) g2d_exec_runqueue(g2d); -- cgit v1.2.3 From 471d60fe594ed1a7ae28a3f911d1200ae51efbdc Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Tue, 11 Sep 2012 16:35:23 +0900 Subject: drm/exynos: fix duplicated mutex lock issue exynos_drm_crtc_dpms function doesn't need mutex lock because mutex lock was called by drm framework so this patch removes mutex lock call from that function to avoid duplicated mutex locking. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index b612bf5bc1a8..8bd4d7ed964b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -66,7 +66,6 @@ struct exynos_drm_crtc { static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) { - struct drm_device *dev = crtc->dev; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); @@ -76,12 +75,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) return; } - mutex_lock(&dev->struct_mutex); - exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); exynos_crtc->dpms = mode; - - mutex_unlock(&dev->struct_mutex); } static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) -- cgit v1.2.3 From ef6223dc6bab64c99b5c869b652fa13436afc38a Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Tue, 11 Sep 2012 18:25:21 +0900 Subject: drm/exynos: check crtc's dpms mode at page flip when page flip is requested, crtc's dpms mode should be on. if not on, return -EINVAL so that it doesn't access hardware. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 8bd4d7ed964b..07c5d2a0bdc0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -207,6 +207,12 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, DRM_DEBUG_KMS("%s\n", __FILE__); + /* when the page flip is requested, crtc's dpms should be on */ + if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { + DRM_ERROR("failed page flip request.\n"); + return -EINVAL; + } + mutex_lock(&dev->struct_mutex); if (event) { -- cgit v1.2.3 From 32aeab17457c13e6a448ba0f6f3c03d6705e5592 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 14 Sep 2012 13:29:47 +0900 Subject: drm/exynos: check crtc's dpms mode at SetCrtc when fb changing is requested, crtc's dpms mode should be on. if not on, return -EPERM so that the hardware can't be accessed. if user requesed dpms off and next SetCrtc with an another fb then the hardware can be accessed with dpms off to write overlay data onto some registers so this patch will prevent from accessing the hardware with dpms off. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 07c5d2a0bdc0..ac004a3288da 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -155,6 +155,12 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, DRM_DEBUG_KMS("%s\n", __FILE__); + /* when framebuffer changing is requested, crtc's dpms should be on */ + if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { + DRM_ERROR("failed framebuffer changing request.\n"); + return -EPERM; + } + crtc_w = crtc->fb->width - x; crtc_h = crtc->fb->height - y; -- cgit v1.2.3 From 291257cf4cb0da1e32b672b88e73d22d845c8f93 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Wed, 19 Sep 2012 11:02:43 +0900 Subject: drm/exynos: support drm_wait_vblank feature for VIDI this patch adds drm_wait_vblank support to Virtual Display module so user can use DRM_IOCT_WAIT_VBLANK ioctl with this patch. for this, you should set _DRM_VBLANK_EXYNOS_VIDI flags to vblwait->request.type Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 22 +++++++++++++++++++++- include/drm/exynos_drm.h | 10 ++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index c95f7dedb8a0..54b44159caf1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -56,6 +56,7 @@ struct vidi_context { unsigned int connected; bool vblank_on; bool suspended; + bool direct_vblank; struct work_struct work; struct mutex lock; }; @@ -224,6 +225,15 @@ static int vidi_enable_vblank(struct device *dev) if (!test_and_set_bit(0, &ctx->irq_flags)) ctx->vblank_on = true; + ctx->direct_vblank = true; + + /* + * 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 + */ + schedule_work(&ctx->work); + return 0; } @@ -425,7 +435,17 @@ static void vidi_fake_vblank_handler(struct work_struct *work) /* refresh rate is about 50Hz. */ usleep_range(16000, 20000); - drm_handle_vblank(subdrv->drm_dev, manager->pipe); + mutex_lock(&ctx->lock); + + if (ctx->direct_vblank) { + drm_handle_vblank(subdrv->drm_dev, manager->pipe); + ctx->direct_vblank = false; + mutex_unlock(&ctx->lock); + return; + } + + mutex_unlock(&ctx->lock); + vidi_finish_pageflip(subdrv->drm_dev, manager->pipe); } diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h index c20b00181530..0d1c503042d5 100644 --- a/include/drm/exynos_drm.h +++ b/include/drm/exynos_drm.h @@ -107,6 +107,16 @@ struct drm_exynos_vidi_connection { uint64_t edid; }; +/* Indicate Exynos specific vblank flags */ +enum e_drm_exynos_vblank { + /* + * this flags is used for Virtual Display module + * to use DRM_IOCTL_WAIT_VBLANK feature. for this, + * user should set this flag to vblwait->request.type + */ + _DRM_VBLANK_EXYNOS_VIDI = 2, +}; + /* memory type definitions. */ enum e_drm_exynos_gem_mem_type { /* Physically Continuous memory and used as default. */ -- cgit v1.2.3 From 53bd5556547d72fb9c572d66c3b7bfe0f096972b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 18 Sep 2012 15:51:30 +0530 Subject: drm/exynos: Fix potential NULL pointer dereference drm_mode_create() returns NULL if it fails to create a new display mode. Check the value returned to avoid NULL pointer deferencing later. Signed-off-by: Sachin Kamat Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_connector.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index 59e79ff4b2eb..87cf3783efdc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c @@ -150,8 +150,12 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) count = drm_add_edid_modes(connector, edid); kfree(edid); } else { - struct drm_display_mode *mode = drm_mode_create(connector->dev); struct exynos_drm_panel_info *panel; + struct drm_display_mode *mode = drm_mode_create(connector->dev); + if (!mode) { + DRM_ERROR("failed to create a new display mode.\n"); + return 0; + } if (display_ops->get_panel) panel = display_ops->get_panel(manager->dev); -- cgit v1.2.3 From e2e1338900208ab36e3b86349ffdb3eba52302f8 Mon Sep 17 00:00:00 2001 From: Leela Krishna Amudala Date: Fri, 21 Sep 2012 16:52:15 +0530 Subject: drm/exynos: add platform_device_id table and driver data for drm fimd Two device ids are created for exynos4-fb and exynos5-fb. Also, added driver data for exynos4 and exynos5 to pick the timing base address at runtime to write data into appropriate register address. Signed-off-by: Leela Krishna Amudala Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 43 +++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 1da741fc7460..73c52ed040fa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -57,6 +57,18 @@ #define get_fimd_context(dev) platform_get_drvdata(to_platform_device(dev)) +struct fimd_driver_data { + unsigned int timing_base; +}; + +struct fimd_driver_data exynos4_fimd_driver_data = { + .timing_base = 0x0, +}; + +struct fimd_driver_data exynos5_fimd_driver_data = { + .timing_base = 0x20000, +}; + struct fimd_win_data { unsigned int offset_x; unsigned int offset_y; @@ -91,6 +103,13 @@ struct fimd_context { struct exynos_drm_panel_info *panel; }; +static inline struct fimd_driver_data *drm_fimd_get_driver_data( + struct platform_device *pdev) +{ + return (struct fimd_driver_data *) + platform_get_device_id(pdev)->driver_data; +} + static bool fimd_display_is_connected(struct device *dev) { DRM_DEBUG_KMS("%s\n", __FILE__); @@ -194,32 +213,35 @@ static void fimd_commit(struct device *dev) struct fimd_context *ctx = get_fimd_context(dev); struct exynos_drm_panel_info *panel = ctx->panel; struct fb_videomode *timing = &panel->timing; + struct fimd_driver_data *driver_data; + struct platform_device *pdev = to_platform_device(dev); u32 val; + driver_data = drm_fimd_get_driver_data(pdev); if (ctx->suspended) return; DRM_DEBUG_KMS("%s\n", __FILE__); /* setup polarity values from machine code. */ - writel(ctx->vidcon1, ctx->regs + VIDCON1); + writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); /* setup vertical timing values. */ val = VIDTCON0_VBPD(timing->upper_margin - 1) | VIDTCON0_VFPD(timing->lower_margin - 1) | VIDTCON0_VSPW(timing->vsync_len - 1); - writel(val, ctx->regs + VIDTCON0); + writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); /* setup horizontal timing values. */ val = VIDTCON1_HBPD(timing->left_margin - 1) | VIDTCON1_HFPD(timing->right_margin - 1) | VIDTCON1_HSPW(timing->hsync_len - 1); - writel(val, ctx->regs + VIDTCON1); + writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); /* setup horizontal and vertical display size. */ val = VIDTCON2_LINEVAL(timing->yres - 1) | VIDTCON2_HOZVAL(timing->xres - 1); - writel(val, ctx->regs + VIDTCON2); + writel(val, ctx->regs + driver_data->timing_base + VIDTCON2); /* setup clock source, clock divider, enable dma. */ val = ctx->vidcon0; @@ -1009,6 +1031,18 @@ static int fimd_runtime_resume(struct device *dev) } #endif +static struct platform_device_id fimd_driver_ids[] = { + { + .name = "exynos4-fb", + .driver_data = (unsigned long)&exynos4_fimd_driver_data, + }, { + .name = "exynos5-fb", + .driver_data = (unsigned long)&exynos5_fimd_driver_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, fimd_driver_ids); + static const struct dev_pm_ops fimd_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume) SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL) @@ -1017,6 +1051,7 @@ static const struct dev_pm_ops fimd_pm_ops = { struct platform_driver fimd_driver = { .probe = fimd_probe, .remove = __devexit_p(fimd_remove), + .id_table = fimd_driver_ids, .driver = { .name = "exynos4-fb", .owner = THIS_MODULE, -- cgit v1.2.3 From 58f6aad7d93f7ce009d371aa5065b70d593d3b17 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 24 Sep 2012 20:04:24 +0900 Subject: drm/exynos: fix display power call issue. Changelog v3: make exynos_drm_display_power function use exynos_drm_best_encoder function instead of connector->encoder to get a valid encoder. connector->encoder could be NULL because with DRM_IOCTL_MODE_RMFB request, connector->encoder is NULL so fix this issue. Changelog v2: remove static prefix so that exynos_drm_best_encoder function could be called by other modules. Changelog v1: this patch fixes the issue that display power callback isn't called. with DRM_IOCTL_MODE_RMFB request, encoder->connector becomes NULL so display_ops->power_on() wouldn't be called so this patch makes exynos_drm_best_encoder function to be used to get a valid encoder of each connector. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_connector.c | 5 ++--- drivers/gpu/drm/exynos/exynos_drm_connector.h | 2 ++ drivers/gpu/drm/exynos/exynos_drm_encoder.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index 87cf3783efdc..da074746967c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c @@ -199,8 +199,7 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector, return ret; } -static struct drm_encoder *exynos_drm_best_encoder( - struct drm_connector *connector) +struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct exynos_drm_connector *exynos_connector = @@ -231,7 +230,7 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = { void exynos_drm_display_power(struct drm_connector *connector, int mode) { - struct drm_encoder *encoder = connector->encoder; + 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; diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h index 40a55c2de4bc..22f6cc442c3d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.h +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.h @@ -31,6 +31,8 @@ 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 96a10c38cd72..db1f7edc53ae 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -57,7 +57,7 @@ static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode) struct drm_connector *connector; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { + if (exynos_drm_best_encoder(connector) == encoder) { DRM_DEBUG_KMS("connector[%d] dpms[%d]\n", connector->base.id, mode); -- cgit v1.2.3 From 2ab97921786f614bc9296722d8a2e2ce32d1760b Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 27 Sep 2012 19:25:21 +0900 Subject: drm/exynos: fix to calculate CRTC shown via screen This patch is to exactly calculate CRTC shown via screen for all cases. Refer exynos_plane_get_size() function for this. Also source position of fb is fixed when start position of CRTC is negative number. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_plane.c | 56 +++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 8c3036dd512b..2a27b5678893 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -32,6 +32,42 @@ static const uint32_t formats[] = { DRM_FORMAT_NV12MT, }; +/* + * This function is to get X or Y size shown via screen. This needs length and + * start position of CRTC. + * + * <--- length ---> + * CRTC ---------------- + * ^ start ^ end + * + * There are six cases from a to b. + * + * <----- SCREEN -----> + * 0 last + * ----------|------------------|---------- + * CRTCs + * a ------- + * b ------- + * c -------------------------- + * d -------- + * e ------- + * f ------- + */ +static int exynos_plane_get_size(int start, unsigned length, unsigned last) +{ + int end = start + length; + int size = 0; + + if (start <= 0) { + if (end > 0) + size = min_t(unsigned, end, last); + } else if (start <= last) { + size = min_t(unsigned, last - start, length); + } + + return size; +} + int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, @@ -64,8 +100,24 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, (unsigned long)overlay->dma_addr[i]); } - actual_w = min((unsigned)(crtc->mode.hdisplay - crtc_x), crtc_w); - actual_h = min((unsigned)(crtc->mode.vdisplay - crtc_y), crtc_h); + actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay); + actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay); + + if (crtc_x < 0) { + if (actual_w) + src_x -= crtc_x; + else + src_x += crtc_w; + crtc_x = 0; + } + + if (crtc_y < 0) { + if (actual_h) + src_y -= crtc_y; + else + src_y += crtc_h; + crtc_y = 0; + } /* set drm framebuffer data. */ overlay->fb_x = src_x; -- cgit v1.2.3 From fab9f8d093a60e524efbf6afe6c10e10c91f1642 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 27 Sep 2012 19:26:03 +0900 Subject: drm/exynos: fix kcalloc size of g2d cmdlist node The size argument means just one element size when we call kcalloc, so G2D_CMDLIST_NUM * sizeof(*node) is wrong. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index dcbc4cb423be..3fbe5915ccce 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -165,8 +165,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) return -ENOMEM; } - node = kcalloc(G2D_CMDLIST_NUM, G2D_CMDLIST_NUM * sizeof(*node), - GFP_KERNEL); + node = kcalloc(G2D_CMDLIST_NUM, sizeof(*node), GFP_KERNEL); if (!node) { dev_err(dev, "failed to allocate memory\n"); ret = -ENOMEM; -- cgit v1.2.3 From c119ed05b6b82f5e70725e63e844a6487a748b95 Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Thu, 4 Oct 2012 20:48:44 +0530 Subject: drm: exynos: hdmi: support for platform variants This patch implements check if HDMI is version 1.3 by using a driver variant instead of platform data. Signed-off-by: Tomasz Stanislawski Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index a6aea6f3ea1a..b3a802b5a129 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2262,6 +2262,26 @@ void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy) hdmi_hdmiphy = hdmiphy; } +enum hdmi_type { + HDMI_TYPE13, + HDMI_TYPE14, +}; + +static struct platform_device_id hdmi_driver_types[] = { + { + .name = "s5pv210-hdmi", + .driver_data = HDMI_TYPE13, + }, { + .name = "exynos4-hdmi", + .driver_data = HDMI_TYPE13, + }, { + .name = "exynos4-hdmi14", + .driver_data = HDMI_TYPE14, + }, { + /* end node */ + } +}; + static int __devinit hdmi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -2270,6 +2290,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev) struct exynos_drm_hdmi_pdata *pdata; struct resource *res; int ret; + enum hdmi_type hdmi_type; DRM_DEBUG_KMS("[%d]\n", __LINE__); @@ -2300,7 +2321,8 @@ static int __devinit hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drm_hdmi_ctx); - hdata->is_v13 = pdata->is_v13; + hdmi_type = platform_get_device_id(pdev)->driver_data; + hdata->is_v13 = (hdmi_type == HDMI_TYPE13); hdata->cfg_hpd = pdata->cfg_hpd; hdata->get_hpd = pdata->get_hpd; hdata->dev = dev; @@ -2447,6 +2469,7 @@ static SIMPLE_DEV_PM_OPS(hdmi_pm_ops, hdmi_suspend, hdmi_resume); struct platform_driver hdmi_driver = { .probe = hdmi_probe, .remove = __devexit_p(hdmi_remove), + .id_table = hdmi_driver_types, .driver = { .name = "exynos4-hdmi", .owner = THIS_MODULE, -- cgit v1.2.3 From 07c8bdd79c7d7cc4142ba01a97a06133a429fe77 Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Thu, 4 Oct 2012 20:48:45 +0530 Subject: drm: exynos: hdmi: fix interrupt handling This patch fixes 'unsigned < 0' check in probe. Moreover it releases an interrupt at remove. Signed-off-by: Tomasz Stanislawski Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index b3a802b5a129..3902917cbd03 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -64,8 +64,8 @@ struct hdmi_context { struct mutex hdmi_mutex; void __iomem *regs; - unsigned int external_irq; - unsigned int internal_irq; + int external_irq; + int internal_irq; struct i2c_client *ddc_port; struct i2c_client *hdmiphy_port; @@ -2424,6 +2424,7 @@ static int __devexit hdmi_remove(struct platform_device *pdev) pm_runtime_disable(dev); free_irq(hdata->internal_irq, hdata); + free_irq(hdata->external_irq, hdata); hdmi_resources_cleanup(hdata); -- cgit v1.2.3 From fca57122c45942b9013a74afeab9bf15b9eba19a Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Thu, 4 Oct 2012 20:48:46 +0530 Subject: drm: exynos: hdmi: use s5p-hdmi platform data The 'exynos-drm-hdmi' driver makes use of s5p-tv platform devices. Therefore the driver should use the same platform data to prevent crashes caused by dereferencing incorrect types. This patch corrects the exynos-drm-hdmi driver to the platform data from s5p-hdmi. Signed-off-by: Tomasz Stanislawski Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 55 ++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 31 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 3902917cbd03..90dce8c45f8d 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -40,6 +40,9 @@ #include "exynos_hdmi.h" +#include +#include + #define MAX_WIDTH 1920 #define MAX_HEIGHT 1080 #define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) @@ -76,8 +79,7 @@ struct hdmi_context { struct hdmi_resources res; void *parent_ctx; - void (*cfg_hpd)(bool external); - int (*get_hpd)(void); + int hpd_gpio; }; /* HDMI Version 1.3 */ @@ -2024,8 +2026,6 @@ static void hdmi_poweron(struct hdmi_context *hdata) hdata->powered = true; - if (hdata->cfg_hpd) - hdata->cfg_hpd(true); mutex_unlock(&hdata->hdmi_mutex); pm_runtime_get_sync(hdata->dev); @@ -2061,8 +2061,6 @@ static void hdmi_poweroff(struct hdmi_context *hdata) pm_runtime_put_sync(hdata->dev); mutex_lock(&hdata->hdmi_mutex); - if (hdata->cfg_hpd) - hdata->cfg_hpd(false); hdata->powered = false; @@ -2110,17 +2108,13 @@ static irqreturn_t hdmi_external_irq_thread(int irq, void *arg) struct exynos_drm_hdmi_context *ctx = arg; struct hdmi_context *hdata = ctx->ctx; - if (!hdata->get_hpd) - goto out; - mutex_lock(&hdata->hdmi_mutex); - hdata->hpd = hdata->get_hpd(); + 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); -out: return IRQ_HANDLED; } @@ -2143,18 +2137,9 @@ static irqreturn_t hdmi_internal_irq_thread(int irq, void *arg) HDMI_INTC_FLAG_HPD_PLUG); } - mutex_lock(&hdata->hdmi_mutex); - hdata->hpd = hdmi_reg_read(hdata, HDMI_HPD_STATUS); - if (hdata->powered && hdata->hpd) { - mutex_unlock(&hdata->hdmi_mutex); - goto out; - } - mutex_unlock(&hdata->hdmi_mutex); - if (ctx->drm_dev) drm_helper_hpd_irq_event(ctx->drm_dev); -out: return IRQ_HANDLED; } @@ -2287,7 +2272,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct exynos_drm_hdmi_context *drm_hdmi_ctx; struct hdmi_context *hdata; - struct exynos_drm_hdmi_pdata *pdata; + struct s5p_hdmi_platform_data *pdata; struct resource *res; int ret; enum hdmi_type hdmi_type; @@ -2323,8 +2308,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev) hdmi_type = platform_get_device_id(pdev)->driver_data; hdata->is_v13 = (hdmi_type == HDMI_TYPE13); - hdata->cfg_hpd = pdata->cfg_hpd; - hdata->get_hpd = pdata->get_hpd; + hdata->hpd_gpio = pdata->hpd_gpio; hdata->dev = dev; ret = hdmi_resources_init(hdata); @@ -2342,11 +2326,17 @@ static int __devinit hdmi_probe(struct platform_device *pdev) goto err_resource; } + ret = gpio_request(hdata->hpd_gpio, "HPD"); + if (ret) { + DRM_ERROR("failed to request HPD gpio\n"); + goto err_resource; + } + /* DDC i2c driver */ if (i2c_add_driver(&ddc_driver)) { DRM_ERROR("failed to register ddc i2c driver\n"); ret = -ENOENT; - goto err_resource; + goto err_gpio; } hdata->ddc_port = hdmi_ddc; @@ -2360,32 +2350,31 @@ static int __devinit hdmi_probe(struct platform_device *pdev) hdata->hdmiphy_port = hdmi_hdmiphy; - hdata->external_irq = platform_get_irq_byname(pdev, "external_irq"); + hdata->external_irq = gpio_to_irq(hdata->hpd_gpio); if (hdata->external_irq < 0) { - DRM_ERROR("failed to get platform irq\n"); + DRM_ERROR("failed to get GPIO external irq\n"); ret = hdata->external_irq; goto err_hdmiphy; } - hdata->internal_irq = platform_get_irq_byname(pdev, "internal_irq"); + hdata->internal_irq = platform_get_irq(pdev, 0); if (hdata->internal_irq < 0) { DRM_ERROR("failed to get platform internal irq\n"); ret = hdata->internal_irq; goto err_hdmiphy; } + hdata->hpd = gpio_get_value(hdata->hpd_gpio); + ret = request_threaded_irq(hdata->external_irq, NULL, hdmi_external_irq_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "hdmi_external", drm_hdmi_ctx); if (ret) { - DRM_ERROR("failed to register hdmi internal interrupt\n"); + DRM_ERROR("failed to register hdmi external interrupt\n"); goto err_hdmiphy; } - if (hdata->cfg_hpd) - hdata->cfg_hpd(false); - ret = request_threaded_irq(hdata->internal_irq, NULL, hdmi_internal_irq_thread, IRQF_ONESHOT, "hdmi_internal", drm_hdmi_ctx); @@ -2407,6 +2396,8 @@ err_hdmiphy: i2c_del_driver(&hdmiphy_driver); err_ddc: i2c_del_driver(&ddc_driver); +err_gpio: + gpio_free(hdata->hpd_gpio); err_resource: hdmi_resources_cleanup(hdata); err_data: @@ -2426,6 +2417,8 @@ static int __devexit hdmi_remove(struct platform_device *pdev) free_irq(hdata->internal_irq, hdata); free_irq(hdata->external_irq, hdata); + gpio_free(hdata->hpd_gpio); + hdmi_resources_cleanup(hdata); /* hdmiphy i2c driver */ -- cgit v1.2.3 From 5295e53d548ba592f54ef03c3444bac56f3d553d Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Thu, 4 Oct 2012 20:48:47 +0530 Subject: drm: exynos: hdmi: turn off HPD interrupt in HDMI chip The plug/unplug interrupt are handled by a separate interrupt. So there is no need to replicate this mechanism in HDMI core. Signed-off-by: Tomasz Stanislawski Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 90dce8c45f8d..e3ab840aaff2 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1532,12 +1532,9 @@ static void hdmi_conf_reset(struct hdmi_context *hdata) static void hdmi_conf_init(struct hdmi_context *hdata) { - /* enable HPD interrupts */ + /* disable HPD interrupts */ hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL | HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); - mdelay(10); - hdmi_reg_writemask(hdata, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL | - HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); /* choose HDMI mode */ hdmi_reg_writemask(hdata, HDMI_MODE_SEL, -- cgit v1.2.3 From 9ff15948c5d533836e0621d21b867df020ef0571 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Thu, 4 Oct 2012 20:48:49 +0530 Subject: drm: exynos: hdmi: add support for exynos5 ddc This patch adds support for exynos5 ddc with device tree enabled. Signed-off-by: Rahul Sharma Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_ddc.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c index 7e1051d07f1f..ef287794a995 100644 --- a/drivers/gpu/drm/exynos/exynos_ddc.c +++ b/drivers/gpu/drm/exynos/exynos_ddc.c @@ -26,29 +26,41 @@ static int s5p_ddc_probe(struct i2c_client *client, { hdmi_attach_ddc_client(client); - dev_info(&client->adapter->dev, "attached s5p_ddc " - "into i2c adapter successfully\n"); + 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 s5p_ddc " - "from i2c adapter successfully\n"); + dev_info(&client->adapter->dev, + "detached %s from i2c adapter successfully\n", + client->name); return 0; } static struct i2c_device_id ddc_idtable[] = { {"s5p_ddc", 0}, + {"exynos5-hdmiddc", 0}, { }, }; +static struct of_device_id hdmiddc_match_types[] = { + { + .compatible = "samsung,exynos5-hdmiddc", + }, { + /* end node */ + } +}; + struct i2c_driver ddc_driver = { .driver = { - .name = "s5p_ddc", + .name = "exynos-hdmiddc", .owner = THIS_MODULE, + .of_match_table = hdmiddc_match_types, }, .id_table = ddc_idtable, .probe = s5p_ddc_probe, -- cgit v1.2.3 From 93c645ee14f2e40cf2a21e6dc88cdd1c800d392a Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Thu, 4 Oct 2012 20:48:50 +0530 Subject: drm: exynos: hdmi: add support for exynos5 hdmiphy This patch adds support for exynos5 hdmi phy with device tree enabled. Signed-off-by: Rahul Sharma Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmiphy.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c index 9fe2995ab9f9..a33073b03fff 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c +++ b/drivers/gpu/drm/exynos/exynos_hdmiphy.c @@ -42,13 +42,23 @@ static int hdmiphy_remove(struct i2c_client *client) static const struct i2c_device_id hdmiphy_id[] = { { "s5p_hdmiphy", 0 }, + { "exynos5-hdmiphy", 0 }, { }, }; +static struct of_device_id hdmiphy_match_types[] = { + { + .compatible = "samsung,exynos5-hdmiphy", + }, { + /* end node */ + } +}; + struct i2c_driver hdmiphy_driver = { .driver = { - .name = "s5p-hdmiphy", + .name = "exynos-hdmiphy", .owner = THIS_MODULE, + .of_match_table = hdmiphy_match_types, }, .id_table = hdmiphy_id, .probe = hdmiphy_probe, -- cgit v1.2.3 From 1e12344120df6b1959f47382bac02952bee6226c Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Thu, 4 Oct 2012 20:48:51 +0530 Subject: drm: exynos: hdmi: add support for platform variants for mixer This patch adds the support for multiple mixer versions avaialble in various platform variants. Version is passed as a driver data field instead of paltform data. Signed-off-by: Rahul Sharma Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 8a43ee17039e..e312fb1dafdd 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -73,6 +73,11 @@ struct mixer_resources { struct clk *sclk_dac; }; +enum mixer_version_id { + MXR_VER_0_0_0_16, + MXR_VER_16_0_33_0, +}; + struct mixer_context { struct device *dev; int pipe; @@ -83,6 +88,11 @@ struct mixer_context { struct mutex mixer_mutex; struct mixer_resources mixer_res; struct hdmi_win_data win_data[MIXER_WIN_NR]; + enum mixer_version_id mxr_ver; +}; + +struct mixer_drv_data { + enum mixer_version_id version; }; static const u8 filter_y_horiz_tap8[] = { @@ -1023,11 +1033,25 @@ fail: return ret; } +static struct mixer_drv_data exynos4_mxr_drv_data = { + .version = MXR_VER_0_0_0_16, +}; + +static struct platform_device_id mixer_driver_types[] = { + { + .name = "s5p-mixer", + .driver_data = (unsigned long)&exynos4_mxr_drv_data, + }, { + /* end node */ + } +}; + static int __devinit 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"); @@ -1047,8 +1071,11 @@ static int __devinit mixer_probe(struct platform_device *pdev) mutex_init(&ctx->mixer_mutex); + drv = (struct mixer_drv_data *)platform_get_device_id( + pdev)->driver_data; ctx->dev = &pdev->dev; drm_hdmi_ctx->ctx = (void *)ctx; + ctx->mxr_ver = drv->version; platform_set_drvdata(pdev, drm_hdmi_ctx); @@ -1101,4 +1128,5 @@ struct platform_driver mixer_driver = { }, .probe = mixer_probe, .remove = __devexit_p(mixer_remove), + .id_table = mixer_driver_types, }; -- cgit v1.2.3 From 1b8e5747a9b65928a5a126d128847b29128cae34 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Thu, 4 Oct 2012 20:48:52 +0530 Subject: drm: exynos: hdmi: add support to disable video processor in mixer This patch adds support for disabling the video processor code based on the platform type. This is done based on a field in the mixer driver data which changes with the platform variant. Signed-off-by: Rahul Sharma Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 151 ++++++++++++++++++++++------------ 1 file changed, 98 insertions(+), 53 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e312fb1dafdd..167734529229 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -83,6 +83,7 @@ struct mixer_context { int pipe; bool interlace; bool powered; + bool vp_enabled; u32 int_en; struct mutex mixer_mutex; @@ -93,6 +94,7 @@ struct mixer_context { struct mixer_drv_data { enum mixer_version_id version; + bool is_vp_enabled; }; static const u8 filter_y_horiz_tap8[] = { @@ -261,7 +263,8 @@ static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable) mixer_reg_writemask(res, MXR_STATUS, enable ? MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE); - vp_reg_write(res, VP_SHADOW_UPDATE, enable ? + if (ctx->vp_enabled) + vp_reg_write(res, VP_SHADOW_UPDATE, enable ? VP_SHADOW_UPDATE_ENABLE : 0); } @@ -343,8 +346,11 @@ static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable) mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE); break; case 2: - vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON); - mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE); + if (ctx->vp_enabled) { + vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON); + mixer_reg_writemask(res, MXR_CFG, val, + MXR_CFG_VP_ENABLE); + } break; } } @@ -602,7 +608,8 @@ static void mixer_win_reset(struct mixer_context *ctx) */ val = MXR_LAYER_CFG_GRP1_VAL(3); val |= MXR_LAYER_CFG_GRP0_VAL(2); - val |= MXR_LAYER_CFG_VP_VAL(1); + if (ctx->vp_enabled) + val |= MXR_LAYER_CFG_VP_VAL(1); mixer_reg_write(res, MXR_LAYER_CFG, val); /* setting background color */ @@ -625,14 +632,17 @@ static void mixer_win_reset(struct mixer_context *ctx) val = MXR_GRP_CFG_ALPHA_VAL(0); mixer_reg_write(res, MXR_VIDEO_CFG, val); - /* configuration of Video Processor Registers */ - vp_win_reset(ctx); - vp_default_filter(res); + if (ctx->vp_enabled) { + /* configuration of Video Processor Registers */ + vp_win_reset(ctx); + vp_default_filter(res); + } /* disable all layers */ mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE); mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE); - mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); + if (ctx->vp_enabled) + mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); mixer_vsync_set_update(ctx, true); spin_unlock_irqrestore(&res->reg_slock, flags); @@ -655,8 +665,10 @@ static void mixer_poweron(struct mixer_context *ctx) pm_runtime_get_sync(ctx->dev); clk_enable(res->mixer); - clk_enable(res->vp); - clk_enable(res->sclk_mixer); + if (ctx->vp_enabled) { + clk_enable(res->vp); + clk_enable(res->sclk_mixer); + } mixer_reg_write(res, MXR_INT_EN, ctx->int_en); mixer_win_reset(ctx); @@ -676,8 +688,10 @@ static void mixer_poweroff(struct mixer_context *ctx) ctx->int_en = mixer_reg_read(res, MXR_INT_EN); clk_disable(res->mixer); - clk_disable(res->vp); - clk_disable(res->sclk_mixer); + if (ctx->vp_enabled) { + clk_disable(res->vp); + clk_disable(res->sclk_mixer); + } pm_runtime_put_sync(ctx->dev); @@ -810,7 +824,7 @@ static void mixer_win_commit(void *ctx, int win) DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); - if (win > 1) + if (win > 1 && mixer_ctx->vp_enabled) vp_video_buffer(mixer_ctx, win); else mixer_graph_buffer(mixer_ctx, win); @@ -946,39 +960,20 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, ret = -ENODEV; goto fail; } - mixer_res->vp = clk_get(dev, "vp"); - if (IS_ERR_OR_NULL(mixer_res->vp)) { - dev_err(dev, "failed to get clock 'vp'\n"); - ret = -ENODEV; - goto fail; - } - mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer"); - if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) { - dev_err(dev, "failed to get clock 'sclk_mixer'\n"); - ret = -ENODEV; - goto fail; - } + mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) { dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); ret = -ENODEV; goto fail; } - mixer_res->sclk_dac = clk_get(dev, "sclk_dac"); - if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) { - dev_err(dev, "failed to get clock 'sclk_dac'\n"); - ret = -ENODEV; - goto fail; - } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(dev, "get memory resource failed.\n"); ret = -ENXIO; goto fail; } - clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi); - mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (mixer_res->mixer_regs == NULL) { @@ -987,54 +982,92 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, goto fail; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp"); + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { - dev_err(dev, "get memory resource failed.\n"); + dev_err(dev, "get interrupt resource failed.\n"); ret = -ENXIO; goto fail; } - mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (mixer_res->vp_regs == NULL) { - dev_err(dev, "register mapping failed.\n"); - ret = -ENXIO; + ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler, + 0, "drm_mixer", ctx); + if (ret) { + dev_err(dev, "request interrupt failed.\n"); goto fail; } + mixer_res->irq = res->start; - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq"); + return 0; + +fail: + if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) + clk_put(mixer_res->sclk_hdmi); + if (!IS_ERR_OR_NULL(mixer_res->mixer)) + clk_put(mixer_res->mixer); + return ret; +} + +static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *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; + int ret; + + mixer_res->vp = clk_get(dev, "vp"); + if (IS_ERR_OR_NULL(mixer_res->vp)) { + dev_err(dev, "failed to get clock 'vp'\n"); + ret = -ENODEV; + goto fail; + } + mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer"); + if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) { + dev_err(dev, "failed to get clock 'sclk_mixer'\n"); + ret = -ENODEV; + goto fail; + } + mixer_res->sclk_dac = clk_get(dev, "sclk_dac"); + if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) { + dev_err(dev, "failed to get clock 'sclk_dac'\n"); + ret = -ENODEV; + goto fail; + } + + if (mixer_res->sclk_hdmi) + clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res == NULL) { - dev_err(dev, "get interrupt resource failed.\n"); + dev_err(dev, "get memory resource failed.\n"); ret = -ENXIO; goto fail; } - ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler, - 0, "drm_mixer", ctx); - if (ret) { - dev_err(dev, "request interrupt failed.\n"); + mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (mixer_res->vp_regs == NULL) { + dev_err(dev, "register mapping failed.\n"); + ret = -ENXIO; goto fail; } - mixer_res->irq = res->start; return 0; fail: if (!IS_ERR_OR_NULL(mixer_res->sclk_dac)) clk_put(mixer_res->sclk_dac); - if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) - clk_put(mixer_res->sclk_hdmi); if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer)) clk_put(mixer_res->sclk_mixer); if (!IS_ERR_OR_NULL(mixer_res->vp)) clk_put(mixer_res->vp); - if (!IS_ERR_OR_NULL(mixer_res->mixer)) - clk_put(mixer_res->mixer); return ret; } static struct mixer_drv_data exynos4_mxr_drv_data = { .version = MXR_VER_0_0_0_16, + .is_vp_enabled = 1, }; static struct platform_device_id mixer_driver_types[] = { @@ -1075,14 +1108,26 @@ static int __devinit mixer_probe(struct platform_device *pdev) pdev)->driver_data; ctx->dev = &pdev->dev; drm_hdmi_ctx->ctx = (void *)ctx; + ctx->vp_enabled = drv->is_vp_enabled; ctx->mxr_ver = drv->version; platform_set_drvdata(pdev, drm_hdmi_ctx); /* acquire resources: regs, irqs, clocks */ ret = mixer_resources_init(drm_hdmi_ctx, pdev); - if (ret) + if (ret) { + DRM_ERROR("mixer_resources_init failed\n"); goto fail; + } + + if (ctx->vp_enabled) { + /* acquire vp resources: regs, irqs, clocks */ + ret = vp_resources_init(drm_hdmi_ctx, pdev); + if (ret) { + DRM_ERROR("vp_resources_init failed\n"); + goto fail; + } + } /* register specific callback point to common hdmi. */ exynos_mixer_ops_register(&mixer_ops); -- cgit v1.2.3 From aaf8b49e928d58501759e94cc744e97ad9812e68 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Thu, 4 Oct 2012 20:48:53 +0530 Subject: drm: exynos: hdmi: add support for exynos5 mixer This patch adds support for exynos5 mixer with device tree enabled. Signed-off-by: Rahul Sharma Signed-off-by: Fahad Kunnathadi Signed-off-by: Kyungmin.park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 49 ++++++++++++++++++++++++++++++++--- drivers/gpu/drm/exynos/regs-mixer.h | 3 +++ 2 files changed, 49 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 167734529229..39d2b95087ae 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -481,6 +481,18 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) vp_regs_dump(ctx); } +static void mixer_layer_update(struct mixer_context *ctx) +{ + struct mixer_resources *res = &ctx->mixer_res; + u32 val; + + val = mixer_reg_read(res, MXR_CFG); + + /* allow one update per vsync only */ + if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK)) + mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); +} + static void mixer_graph_buffer(struct mixer_context *ctx, int win) { struct mixer_resources *res = &ctx->mixer_res; @@ -561,6 +573,11 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) mixer_cfg_scan(ctx, win_data->mode_height); mixer_cfg_rgb_fmt(ctx, win_data->mode_height); mixer_cfg_layer(ctx, win, true); + + /* layer update mandatory for mixer 16.0.33.0 */ + if (ctx->mxr_ver == MXR_VER_16_0_33_0) + mixer_layer_update(ctx); + mixer_run(ctx); mixer_vsync_set_update(ctx, true); @@ -1065,6 +1082,11 @@ fail: return ret; } +static struct mixer_drv_data exynos5_mxr_drv_data = { + .version = MXR_VER_16_0_33_0, + .is_vp_enabled = 0, +}; + static struct mixer_drv_data exynos4_mxr_drv_data = { .version = MXR_VER_0_0_0_16, .is_vp_enabled = 1, @@ -1074,6 +1096,18 @@ static struct platform_device_id mixer_driver_types[] = { { .name = "s5p-mixer", .driver_data = (unsigned long)&exynos4_mxr_drv_data, + }, { + .name = "exynos5-mixer", + .driver_data = (unsigned long)&exynos5_mxr_drv_data, + }, { + /* end node */ + } +}; + +static struct of_device_id mixer_match_types[] = { + { + .compatible = "samsung,exynos5-mixer", + .data = &exynos5_mxr_drv_data, }, { /* end node */ } @@ -1104,8 +1138,16 @@ static int __devinit mixer_probe(struct platform_device *pdev) mutex_init(&ctx->mixer_mutex); - drv = (struct mixer_drv_data *)platform_get_device_id( - pdev)->driver_data; + if (dev->of_node) { + const struct of_device_id *match; + match = of_match_node(of_match_ptr(mixer_match_types), + pdev->dev.of_node); + drv = match->data; + } else { + drv = (struct mixer_drv_data *) + platform_get_device_id(pdev)->driver_data; + } + ctx->dev = &pdev->dev; drm_hdmi_ctx->ctx = (void *)ctx; ctx->vp_enabled = drv->is_vp_enabled; @@ -1167,9 +1209,10 @@ static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL); struct platform_driver mixer_driver = { .driver = { - .name = "s5p-mixer", + .name = "exynos-mixer", .owner = THIS_MODULE, .pm = &mixer_pm_ops, + .of_match_table = mixer_match_types, }, .probe = mixer_probe, .remove = __devexit_p(mixer_remove), diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h index fd2f4d14cf6d..5d8dbc0301e6 100644 --- a/drivers/gpu/drm/exynos/regs-mixer.h +++ b/drivers/gpu/drm/exynos/regs-mixer.h @@ -69,6 +69,7 @@ (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit)) /* bits for MXR_STATUS */ +#define MXR_STATUS_SOFT_RESET (1 << 8) #define MXR_STATUS_16_BURST (1 << 7) #define MXR_STATUS_BURST_MASK (1 << 7) #define MXR_STATUS_BIG_ENDIAN (1 << 3) @@ -77,6 +78,8 @@ #define MXR_STATUS_REG_RUN (1 << 0) /* bits for MXR_CFG */ +#define MXR_CFG_LAYER_UPDATE (1 << 31) +#define MXR_CFG_LAYER_UPDATE_COUNT_MASK (3 << 29) #define MXR_CFG_RGB601_0_255 (0 << 9) #define MXR_CFG_RGB601_16_235 (1 << 9) #define MXR_CFG_RGB709_0_255 (2 << 9) -- cgit v1.2.3 From 5a325071a0ac9636f07d6328bafc9e42ce13752c Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Thu, 4 Oct 2012 20:48:54 +0530 Subject: drm: exynos: hdmi: replace is_v13 with version check in hdmi This patch removed the is_v13 variable from the hdmi driver context. It is replaced with condition check for the hdmi version. This cleans the way for handling further hdmi versions. Signed-off-by: Rahul Sharma Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index e3ab840aaff2..89e798b47ded 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -47,6 +47,11 @@ #define MAX_HEIGHT 1080 #define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) +enum hdmi_type { + HDMI_TYPE13, + HDMI_TYPE14, +}; + struct hdmi_resources { struct clk *hdmi; struct clk *sclk_hdmi; @@ -62,7 +67,6 @@ struct hdmi_context { struct drm_device *drm_dev; bool hpd; bool powered; - bool is_v13; bool dvi_mode; struct mutex hdmi_mutex; @@ -80,6 +84,8 @@ struct hdmi_context { void *parent_ctx; int hpd_gpio; + + enum hdmi_type type; }; /* HDMI Version 1.3 */ @@ -1211,7 +1217,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix) static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix) { - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) hdmi_v13_regs_dump(hdata, prefix); else hdmi_v14_regs_dump(hdata, prefix); @@ -1252,7 +1258,7 @@ static int hdmi_v14_conf_index(struct drm_display_mode *mode) static int hdmi_conf_index(struct hdmi_context *hdata, struct drm_display_mode *mode) { - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) return hdmi_v13_conf_index(mode); return hdmi_v14_conf_index(mode); @@ -1348,7 +1354,7 @@ static int hdmi_check_timing(void *ctx, void *timing) check_timing->yres, check_timing->refresh, check_timing->vmode); - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) return hdmi_v13_check_timing(check_timing); else return hdmi_v14_check_timing(check_timing); @@ -1414,7 +1420,7 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr) hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]); hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]); - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4); else hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); @@ -1518,7 +1524,7 @@ static void hdmi_conf_reset(struct hdmi_context *hdata) { u32 reg; - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) reg = HDMI_V13_CORE_RSTOUT; else reg = HDMI_CORE_RSTOUT; @@ -1550,7 +1556,7 @@ static void hdmi_conf_init(struct hdmi_context *hdata) HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS); } - if (hdata->is_v13) { + if (hdata->type == HDMI_TYPE13) { /* choose bluescreen (fecal) color */ hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12); hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34); @@ -1832,7 +1838,7 @@ static void hdmi_v14_timing_apply(struct hdmi_context *hdata) static void hdmi_timing_apply(struct hdmi_context *hdata) { - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) hdmi_v13_timing_apply(hdata); else hdmi_v14_timing_apply(hdata); @@ -1854,7 +1860,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) if (hdata->hdmiphy_port) i2c_master_send(hdata->hdmiphy_port, buffer, 2); - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) reg = HDMI_V13_PHY_RSTOUT; else reg = HDMI_PHY_RSTOUT; @@ -1881,7 +1887,7 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) } /* pixel clock */ - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) hdmiphy_data = hdmi_v13_confs[hdata->cur_conf].hdmiphy_data; else hdmiphy_data = hdmi_confs[hdata->cur_conf].hdmiphy_data; @@ -1949,7 +1955,7 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, drm_mode_set_crtcinfo(adjusted_mode, 0); - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) index = hdmi_v13_conf_index(adjusted_mode); else index = hdmi_v14_conf_index(adjusted_mode); @@ -1963,7 +1969,7 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, * to adjusted_mode. */ list_for_each_entry(m, &connector->modes, head) { - if (hdata->is_v13) + if (hdata->type == HDMI_TYPE13) index = hdmi_v13_conf_index(m); else index = hdmi_v14_conf_index(m); @@ -2244,11 +2250,6 @@ void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy) hdmi_hdmiphy = hdmiphy; } -enum hdmi_type { - HDMI_TYPE13, - HDMI_TYPE14, -}; - static struct platform_device_id hdmi_driver_types[] = { { .name = "s5pv210-hdmi", @@ -2272,7 +2273,6 @@ static int __devinit hdmi_probe(struct platform_device *pdev) struct s5p_hdmi_platform_data *pdata; struct resource *res; int ret; - enum hdmi_type hdmi_type; DRM_DEBUG_KMS("[%d]\n", __LINE__); @@ -2303,8 +2303,8 @@ static int __devinit hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drm_hdmi_ctx); - hdmi_type = platform_get_device_id(pdev)->driver_data; - hdata->is_v13 = (hdmi_type == HDMI_TYPE13); + hdata->type = (enum hdmi_type)platform_get_device_id + (pdev)->driver_data; hdata->hpd_gpio = pdata->hpd_gpio; hdata->dev = dev; -- cgit v1.2.3 From 22c4f428979521f3ba3398a1eb5c0be07396f357 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Thu, 4 Oct 2012 20:48:55 +0530 Subject: drm: exynos: hdmi: add support for exynos5 hdmi This patch adds support for exynos5 hdmi with device tree enabled. Signed-off-by: Rahul Sharma Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 83 ++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 89e798b47ded..5caf49f366e3 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include #include @@ -2250,6 +2253,41 @@ void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy) hdmi_hdmiphy = hdmiphy; } +#ifdef CONFIG_OF +static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata + (struct device *dev) +{ + struct device_node *np = dev->of_node; + struct s5p_hdmi_platform_data *pd; + enum of_gpio_flags flags; + u32 value; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) { + DRM_ERROR("memory allocation for pdata failed\n"); + goto err_data; + } + + if (!of_find_property(np, "hpd-gpio", &value)) { + DRM_ERROR("no hpd gpio property found\n"); + goto err_data; + } + + pd->hpd_gpio = of_get_named_gpio_flags(np, "hpd-gpio", 0, &flags); + + return pd; + +err_data: + return NULL; +} +#else +static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata + (struct device *dev) +{ + return NULL; +} +#endif + static struct platform_device_id hdmi_driver_types[] = { { .name = "s5pv210-hdmi", @@ -2259,7 +2297,19 @@ static struct platform_device_id hdmi_driver_types[] = { .driver_data = HDMI_TYPE13, }, { .name = "exynos4-hdmi14", - .driver_data = HDMI_TYPE14, + .driver_data = HDMI_TYPE14, + }, { + .name = "exynos5-hdmi", + .driver_data = HDMI_TYPE14, + }, { + /* end node */ + } +}; + +static struct of_device_id hdmi_match_types[] = { + { + .compatible = "samsung,exynos5-hdmi", + .data = (void *)HDMI_TYPE14, }, { /* end node */ } @@ -2276,7 +2326,16 @@ static int __devinit hdmi_probe(struct platform_device *pdev) DRM_DEBUG_KMS("[%d]\n", __LINE__); - pdata = pdev->dev.platform_data; + if (pdev->dev.of_node) { + pdata = drm_hdmi_dt_parse_pdata(dev); + if (IS_ERR(pdata)) { + DRM_ERROR("failed to parse dt\n"); + return PTR_ERR(pdata); + } + } else { + pdata = pdev->dev.platform_data; + } + if (!pdata) { DRM_ERROR("no platform data specified\n"); return -EINVAL; @@ -2303,18 +2362,33 @@ static int __devinit hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drm_hdmi_ctx); - hdata->type = (enum hdmi_type)platform_get_device_id + if (dev->of_node) { + const struct of_device_id *match; + match = of_match_node(of_match_ptr(hdmi_match_types), + pdev->dev.of_node); + hdata->type = (enum hdmi_type)match->data; + } else { + hdata->type = (enum hdmi_type)platform_get_device_id (pdev)->driver_data; + } + hdata->hpd_gpio = pdata->hpd_gpio; hdata->dev = dev; ret = hdmi_resources_init(hdata); + if (ret) { ret = -EINVAL; + DRM_ERROR("hdmi_resources_init failed\n"); goto err_data; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + DRM_ERROR("failed to find registers\n"); + ret = -ENOENT; + goto err_resource; + } hdata->regs = devm_request_and_ioremap(&pdev->dev, res); if (!hdata->regs) { @@ -2462,8 +2536,9 @@ struct platform_driver hdmi_driver = { .remove = __devexit_p(hdmi_remove), .id_table = hdmi_driver_types, .driver = { - .name = "exynos4-hdmi", + .name = "exynos-hdmi", .owner = THIS_MODULE, .pm = &hdmi_pm_ops, + .of_match_table = hdmi_match_types, }, }; -- cgit v1.2.3 From 768c3059d87876ce124dafc40078718dc85cec65 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Thu, 4 Oct 2012 20:48:56 +0530 Subject: drm: exynos: hdmi: remove drm common hdmi platform data struct exynos-drm-hdmi need context pointers from hdmi and mixer. These pointers were expected from the plf data. Cleaned this dependency by exporting i/f which are called by hdmi, mixer driver probes for setting their context. Signed-off-by: Rahul Sharma Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 51 ++++++++++++++++---------------- drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 2 ++ drivers/gpu/drm/exynos/exynos_hdmi.c | 3 ++ drivers/gpu/drm/exynos/exynos_mixer.c | 3 ++ include/drm/exynos_drm.h | 14 --------- 5 files changed, 34 insertions(+), 39 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index 0584132dc608..85304c46a8cd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -29,6 +29,11 @@ #define get_ctx_from_subdrv(subdrv) container_of(subdrv,\ struct drm_hdmi_context, subdrv); +/* Common hdmi subdrv needs to access the hdmi and mixer though context. +* These should be initialied by the repective drivers */ +static struct exynos_drm_hdmi_context *hdmi_ctx; +static struct exynos_drm_hdmi_context *mixer_ctx; + /* these callback points shoud be set by specific drivers. */ static struct exynos_hdmi_ops *hdmi_ops; static struct exynos_mixer_ops *mixer_ops; @@ -41,6 +46,18 @@ struct drm_hdmi_context { bool enabled[MIXER_WIN_NR]; }; +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) { DRM_DEBUG_KMS("%s\n", __FILE__); @@ -303,46 +320,30 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev, { struct exynos_drm_subdrv *subdrv = to_subdrv(dev); struct drm_hdmi_context *ctx; - struct platform_device *pdev = to_platform_device(dev); - struct exynos_drm_common_hdmi_pd *pd; DRM_DEBUG_KMS("%s\n", __FILE__); - pd = pdev->dev.platform_data; - - if (!pd) { - DRM_DEBUG_KMS("platform data is null.\n"); + if (!hdmi_ctx) { + DRM_ERROR("hdmi context not initialized.\n"); return -EFAULT; } - if (!pd->hdmi_dev) { - DRM_DEBUG_KMS("hdmi device is null.\n"); - return -EFAULT; - } - - if (!pd->mixer_dev) { - DRM_DEBUG_KMS("mixer device is null.\n"); + if (!mixer_ctx) { + DRM_ERROR("mixer context not initialized.\n"); return -EFAULT; } ctx = get_ctx_from_subdrv(subdrv); - ctx->hdmi_ctx = (struct exynos_drm_hdmi_context *) - to_context(pd->hdmi_dev); - if (!ctx->hdmi_ctx) { - DRM_DEBUG_KMS("hdmi context is null.\n"); + if (!ctx) { + DRM_ERROR("no drm hdmi context.\n"); return -EFAULT; } - ctx->hdmi_ctx->drm_dev = drm_dev; - - ctx->mixer_ctx = (struct exynos_drm_hdmi_context *) - to_context(pd->mixer_dev); - if (!ctx->mixer_ctx) { - DRM_DEBUG_KMS("mixer context is null.\n"); - return -EFAULT; - } + ctx->hdmi_ctx = hdmi_ctx; + ctx->mixer_ctx = mixer_ctx; + ctx->hdmi_ctx->drm_dev = drm_dev; ctx->mixer_ctx->drm_dev = drm_dev; return 0; diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h index d9f9e9fcc2b6..2da5ffd3a059 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h @@ -73,6 +73,8 @@ struct exynos_mixer_ops { void (*win_disable)(void *ctx, int zpos); }; +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 5caf49f366e3..e6b784d1527d 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2454,6 +2454,9 @@ static int __devinit hdmi_probe(struct platform_device *pdev) goto err_free_irq; } + /* 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); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 39d2b95087ae..1a319e4431d8 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1171,6 +1171,9 @@ static int __devinit mixer_probe(struct platform_device *pdev) } } + /* 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); diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h index 8bdd49a0abd0..8ac4079e6458 100644 --- a/include/drm/exynos_drm.h +++ b/include/drm/exynos_drm.h @@ -240,19 +240,5 @@ struct exynos_drm_fimd_pdata { unsigned int bpp; }; -/** - * Platform Specific Structure for DRM based HDMI. - * - * @hdmi_dev: device point to specific hdmi driver. - * @mixer_dev: device point to specific mixer driver. - * - * this structure is used for common hdmi driver and each device object - * would be used to access specific device driver(hdmi or mixer driver) - */ -struct exynos_drm_common_hdmi_pd { - struct device *hdmi_dev; - struct device *mixer_dev; -}; - #endif /* __KERNEL__ */ #endif /* _EXYNOS_DRM_H_ */ -- cgit v1.2.3