diff options
Diffstat (limited to 'drivers/gpu/drm/sti/sti_crtc.c')
-rw-r--r-- | drivers/gpu/drm/sti/sti_crtc.c | 133 |
1 files changed, 95 insertions, 38 deletions
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index 27b3ef207617..23fc2db50d17 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -17,20 +17,18 @@ #include "sti_compositor.h" #include "sti_crtc.h" #include "sti_drv.h" +#include "sti_vid.h" #include "sti_vtg.h" -static void sti_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - DRM_DEBUG_KMS("\n"); -} - -static void sti_crtc_prepare(struct drm_crtc *crtc) +static void sti_crtc_enable(struct drm_crtc *crtc) { struct sti_mixer *mixer = to_sti_mixer(crtc); struct device *dev = mixer->dev; struct sti_compositor *compo = dev_get_drvdata(dev); - mixer->enabled = true; + DRM_DEBUG_DRIVER("\n"); + + mixer->status = STI_MIXER_READY; /* Prepare and enable the compo IP clock */ if (mixer->id == STI_MIXER_MAIN) { @@ -41,31 +39,16 @@ static void sti_crtc_prepare(struct drm_crtc *crtc) DRM_INFO("Failed to prepare/enable compo_aux clk\n"); } - sti_mixer_clear_all_planes(mixer); + drm_crtc_vblank_on(crtc); } -static void sti_crtc_commit(struct drm_crtc *crtc) +static void sti_crtc_disabling(struct drm_crtc *crtc) { struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - struct sti_plane *plane; - - if ((!mixer || !compo)) { - DRM_ERROR("Can't find mixer or compositor)\n"); - return; - } - - /* get GDP which is reserved to the CRTC FB */ - plane = to_sti_plane(crtc->primary); - if (!plane) - DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n"); - /* Enable plane on mixer */ - if (sti_mixer_set_plane_status(mixer, plane, true)) - DRM_ERROR("Cannot enable plane at mixer\n"); + DRM_DEBUG_DRIVER("\n"); - drm_crtc_vblank_on(crtc); + mixer->status = STI_MIXER_DISABLING; } static bool sti_crtc_mode_fixup(struct drm_crtc *crtc, @@ -133,9 +116,6 @@ static void sti_crtc_disable(struct drm_crtc *crtc) struct device *dev = mixer->dev; struct sti_compositor *compo = dev_get_drvdata(dev); - if (!mixer->enabled) - return; - DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); /* Disable Background */ @@ -152,13 +132,13 @@ static void sti_crtc_disable(struct drm_crtc *crtc) clk_disable_unprepare(compo->clk_compo_aux); } - mixer->enabled = false; + mixer->status = STI_MIXER_DISABLED; } static void sti_crtc_mode_set_nofb(struct drm_crtc *crtc) { - sti_crtc_prepare(crtc); + sti_crtc_enable(crtc); sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); } @@ -178,17 +158,79 @@ static void sti_crtc_atomic_begin(struct drm_crtc *crtc) static void sti_crtc_atomic_flush(struct drm_crtc *crtc) { + struct drm_device *drm_dev = crtc->dev; + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct sti_compositor *compo = dev_get_drvdata(mixer->dev); + struct drm_plane *p; + + DRM_DEBUG_DRIVER("\n"); + + /* perform plane actions */ + list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { + struct sti_plane *plane = to_sti_plane(p); + + switch (plane->status) { + case STI_PLANE_UPDATED: + /* update planes tag as updated */ + DRM_DEBUG_DRIVER("update plane %s\n", + sti_plane_to_str(plane)); + + if (sti_mixer_set_plane_depth(mixer, plane)) { + DRM_ERROR("Cannot set plane %s depth\n", + sti_plane_to_str(plane)); + break; + } + + if (sti_mixer_set_plane_status(mixer, plane, true)) { + DRM_ERROR("Cannot enable plane %s at mixer\n", + sti_plane_to_str(plane)); + break; + } + + /* if plane is HQVDP_0 then commit the vid[0] */ + if (plane->desc == STI_HQVDP_0) + sti_vid_commit(compo->vid[0], p->state); + + plane->status = STI_PLANE_READY; + + break; + case STI_PLANE_DISABLING: + /* disabling sequence for planes tag as disabling */ + DRM_DEBUG_DRIVER("disable plane %s from mixer\n", + sti_plane_to_str(plane)); + + if (sti_mixer_set_plane_status(mixer, plane, false)) { + DRM_ERROR("Cannot disable plane %s at mixer\n", + sti_plane_to_str(plane)); + continue; + } + + if (plane->desc == STI_CURSOR) + /* tag plane status for disabled */ + plane->status = STI_PLANE_DISABLED; + else + /* tag plane status for flushing */ + plane->status = STI_PLANE_FLUSHING; + + /* if plane is HQVDP_0 then disable the vid[0] */ + if (plane->desc == STI_HQVDP_0) + sti_vid_disable(compo->vid[0]); + + break; + default: + /* Other status case are not handled */ + break; + } + } } static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { - .dpms = sti_crtc_dpms, - .prepare = sti_crtc_prepare, - .commit = sti_crtc_commit, + .enable = sti_crtc_enable, + .disable = sti_crtc_disabling, .mode_fixup = sti_crtc_mode_fixup, .mode_set = drm_helper_crtc_mode_set, .mode_set_nofb = sti_crtc_mode_set_nofb, .mode_set_base = drm_helper_crtc_mode_set_base, - .disable = sti_crtc_disable, .atomic_begin = sti_crtc_atomic_begin, .atomic_flush = sti_crtc_atomic_flush, }; @@ -237,6 +279,21 @@ int sti_crtc_vblank_cb(struct notifier_block *nb, } spin_unlock_irqrestore(&drm_dev->event_lock, flags); + if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) { + struct drm_plane *p; + + /* Disable mixer only if all overlay planes (GDP and VDP) + * are disabled */ + list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { + struct sti_plane *plane = to_sti_plane(p); + + if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP) + if (plane->status != STI_PLANE_DISABLED) + return 0; + } + sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc); + } + return 0; } @@ -259,9 +316,9 @@ int sti_crtc_enable_vblank(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(sti_crtc_enable_vblank); -void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) +void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc) { - struct sti_private *priv = dev->dev_private; + struct sti_private *priv = drm_dev->dev_private; struct sti_compositor *compo = priv->compo; struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; @@ -273,7 +330,7 @@ void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) /* free the resources of the pending requests */ if (compo->mixer[crtc]->pending_event) { - drm_vblank_put(dev, crtc); + drm_vblank_put(drm_dev, crtc); compo->mixer[crtc]->pending_event = NULL; } } |