summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/exynos/exynos_mixer.c
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
commite5fd91f1ef340da553f7a79da9540c3db711c937 (patch)
treeb11842027dc6641da63f4bcc524f8678263304a3 /drivers/gpu/drm/exynos/exynos_mixer.c
parent2a9b0348e685a63d97486f6749622b61e9e3292f (diff)
Linux-libre 4.2-gnu
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_mixer.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c139
1 files changed, 57 insertions, 82 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 8874c1fcb..4706b5690 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -718,6 +718,10 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
/* handling VSYNC */
if (val & MXR_INT_STATUS_VSYNC) {
+ /* vsync interrupt use different bit for read and clear */
+ val |= MXR_INT_CLEAR_VSYNC;
+ val &= ~MXR_INT_STATUS_VSYNC;
+
/* interlace scan need to check shadow register */
if (ctx->interlace) {
base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
@@ -743,11 +747,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
out:
/* clear interrupts */
- if (~val & MXR_INT_EN_VSYNC) {
- /* vsync interrupt use different bit for read and clear */
- val &= ~MXR_INT_EN_VSYNC;
- val |= MXR_INT_CLEAR_VSYNC;
- }
mixer_reg_write(res, MXR_INT_STATUS, val);
spin_unlock(&res->reg_slock);
@@ -882,10 +881,12 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
}
}
- if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
- return 0;
+ ret = drm_iommu_attach_device_if_possible(mixer_ctx->crtc, drm_dev,
+ mixer_ctx->dev);
+ if (ret)
+ priv->pipe--;
- return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
+ return ret;
}
static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
@@ -905,8 +906,8 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
}
/* enable vsync interrupt */
- mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
- MXR_INT_EN_VSYNC);
+ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
+ mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
return 0;
}
@@ -916,7 +917,13 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
struct mixer_context *mixer_ctx = crtc->ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res;
+ if (!mixer_ctx->powered) {
+ mixer_ctx->int_en &= MXR_INT_EN_VSYNC;
+ return;
+ }
+
/* disable vsync interrupt */
+ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
}
@@ -937,8 +944,6 @@ static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
vp_video_buffer(mixer_ctx, win);
else
mixer_graph_buffer(mixer_ctx, win);
-
- mixer_ctx->planes[win].enabled = true;
}
static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
@@ -952,7 +957,6 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
mutex_lock(&mixer_ctx->mixer_mutex);
if (!mixer_ctx->powered) {
mutex_unlock(&mixer_ctx->mixer_mutex);
- mixer_ctx->planes[win].resume = false;
return;
}
mutex_unlock(&mixer_ctx->mixer_mutex);
@@ -964,8 +968,6 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
mixer_vsync_set_update(mixer_ctx, true);
spin_unlock_irqrestore(&res->reg_slock, flags);
-
- mixer_ctx->planes[win].enabled = false;
}
static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
@@ -1000,36 +1002,11 @@ static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
}
-static void mixer_window_suspend(struct mixer_context *ctx)
-{
- struct exynos_drm_plane *plane;
- int i;
-
- for (i = 0; i < MIXER_WIN_NR; i++) {
- plane = &ctx->planes[i];
- plane->resume = plane->enabled;
- mixer_win_disable(ctx->crtc, i);
- }
- mixer_wait_for_vblank(ctx->crtc);
-}
-
-static void mixer_window_resume(struct mixer_context *ctx)
-{
- struct exynos_drm_plane *plane;
- int i;
-
- for (i = 0; i < MIXER_WIN_NR; i++) {
- plane = &ctx->planes[i];
- plane->enabled = plane->resume;
- plane->resume = false;
- if (plane->enabled)
- mixer_win_commit(ctx->crtc, i);
- }
-}
-
-static void mixer_poweron(struct mixer_context *ctx)
+static void mixer_enable(struct exynos_drm_crtc *crtc)
{
+ struct mixer_context *ctx = crtc->ctx;
struct mixer_resources *res = &ctx->mixer_res;
+ int ret;
mutex_lock(&ctx->mixer_mutex);
if (ctx->powered) {
@@ -1041,12 +1018,32 @@ static void mixer_poweron(struct mixer_context *ctx)
pm_runtime_get_sync(ctx->dev);
- clk_prepare_enable(res->mixer);
- clk_prepare_enable(res->hdmi);
+ ret = clk_prepare_enable(res->mixer);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
+ return;
+ }
+ ret = clk_prepare_enable(res->hdmi);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
+ return;
+ }
if (ctx->vp_enabled) {
- clk_prepare_enable(res->vp);
- if (ctx->has_sclk)
- clk_prepare_enable(res->sclk_mixer);
+ ret = clk_prepare_enable(res->vp);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
+ ret);
+ return;
+ }
+ if (ctx->has_sclk) {
+ ret = clk_prepare_enable(res->sclk_mixer);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the " \
+ "sclk_mixer clk [%d]\n",
+ ret);
+ return;
+ }
+ }
}
mutex_lock(&ctx->mixer_mutex);
@@ -1055,15 +1052,17 @@ static void mixer_poweron(struct mixer_context *ctx)
mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
+ if (ctx->int_en & MXR_INT_EN_VSYNC)
+ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
mixer_win_reset(ctx);
-
- mixer_window_resume(ctx);
}
-static void mixer_poweroff(struct mixer_context *ctx)
+static void mixer_disable(struct exynos_drm_crtc *crtc)
{
+ struct mixer_context *ctx = crtc->ctx;
struct mixer_resources *res = &ctx->mixer_res;
+ int i;
mutex_lock(&ctx->mixer_mutex);
if (!ctx->powered) {
@@ -1074,7 +1073,9 @@ static void mixer_poweroff(struct mixer_context *ctx)
mixer_stop(ctx);
mixer_regs_dump(ctx);
- mixer_window_suspend(ctx);
+
+ for (i = 0; i < MIXER_WIN_NR; i++)
+ mixer_win_disable(crtc, i);
ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
@@ -1093,23 +1094,6 @@ static void mixer_poweroff(struct mixer_context *ctx)
pm_runtime_put_sync(ctx->dev);
}
-static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
-{
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- mixer_poweron(crtc->ctx);
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
- mixer_poweroff(crtc->ctx);
- break;
- default:
- DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
- break;
- }
-}
-
/* Only valid for Mixer version 16.0.33.0 */
int mixer_check_mode(struct drm_display_mode *mode)
{
@@ -1131,7 +1115,8 @@ int mixer_check_mode(struct drm_display_mode *mode)
}
static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
- .dpms = mixer_dpms,
+ .enable = mixer_enable,
+ .disable = mixer_disable,
.enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank,
.wait_for_vblank = mixer_wait_for_vblank,
@@ -1280,18 +1265,9 @@ static int mixer_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
- ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
- EXYNOS_DISPLAY_TYPE_HDMI);
- if (ret)
- return ret;
-
ret = component_add(&pdev->dev, &mixer_component_ops);
- if (ret) {
- exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
- return ret;
- }
-
- pm_runtime_enable(dev);
+ if (!ret)
+ pm_runtime_enable(dev);
return ret;
}
@@ -1301,7 +1277,6 @@ static int mixer_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
component_del(&pdev->dev, &mixer_component_ops);
- exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
return 0;
}