From: Dave Airlie Date: Fri, 14 Aug 2015 00:14:23 +0000 (+1000) Subject: Merge branch 'drm-sti-next-atomic-2015-08-11' of http://git.linaro.org/people/benjami... X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=e1474e7bdf6b16db41cc12b8e7b3fefd8668f3cf;p=openwrt%2Fstaging%2Fblogic.git Merge branch 'drm-sti-next-atomic-2015-08-11' of git.linaro.org/people/benjamin.gaignard/kernel into drm-next This serie of patches fix minor bugs around how driver sub-components are bind and planes z-ordering. The main part is about atomic support: using more atomic helpers allow us to simplify the code (~300 lines removed) and to ahve a better match between drm concepts (planes and crtc) and hardware split. [airlied: fixed up conflict in atomic code] * 'drm-sti-next-atomic-2015-08-11' of http://git.linaro.org/people/benjamin.gaignard/kernel: drm/sti: atomic crtc/plane update drm/sti: rename files and functions drm/sti: code clean up drm/sti: fix dynamic z-ordering drm: sti: fix sub-components bind --- e1474e7bdf6b16db41cc12b8e7b3fefd8668f3cf diff --cc drivers/gpu/drm/sti/sti_crtc.c index 000000000000,23fc2db50d17..018ffc970e96 mode 000000,100644..100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@@ -1,0 -1,379 +1,381 @@@ + /* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Benjamin Gaignard + * Fabien Dessenne + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + + #include + + #include + #include + #include + #include + #include + + #include "sti_compositor.h" + #include "sti_crtc.h" + #include "sti_drv.h" + #include "sti_vid.h" + #include "sti_vtg.h" + + 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); + + DRM_DEBUG_DRIVER("\n"); + + mixer->status = STI_MIXER_READY; + + /* Prepare and enable the compo IP clock */ + if (mixer->id == STI_MIXER_MAIN) { + if (clk_prepare_enable(compo->clk_compo_main)) + DRM_INFO("Failed to prepare/enable compo_main clk\n"); + } else { + if (clk_prepare_enable(compo->clk_compo_aux)) + DRM_INFO("Failed to prepare/enable compo_aux clk\n"); + } + + drm_crtc_vblank_on(crtc); + } + + static void sti_crtc_disabling(struct drm_crtc *crtc) + { + struct sti_mixer *mixer = to_sti_mixer(crtc); + + DRM_DEBUG_DRIVER("\n"); + + mixer->status = STI_MIXER_DISABLING; + } + + static bool sti_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) + { + /* accept the provided drm_display_mode, do not fix it up */ + return true; + } + + static int + sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) + { + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct device *dev = mixer->dev; + struct sti_compositor *compo = dev_get_drvdata(dev); + struct clk *clk; + int rate = mode->clock * 1000; + int res; + + DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", + crtc->base.id, sti_mixer_to_str(mixer), + mode->base.id, mode->name); + + DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", + mode->vrefresh, mode->clock, + mode->hdisplay, + mode->hsync_start, mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, mode->vsync_end, + mode->vtotal, mode->type, mode->flags); + + /* Set rate and prepare/enable pixel clock */ + if (mixer->id == STI_MIXER_MAIN) + clk = compo->clk_pix_main; + else + clk = compo->clk_pix_aux; + + res = clk_set_rate(clk, rate); + if (res < 0) { + DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); + return -EINVAL; + } + if (clk_prepare_enable(clk)) { + DRM_ERROR("Failed to prepare/enable pix clk\n"); + return -EINVAL; + } + + sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, &crtc->mode); + + res = sti_mixer_active_video_area(mixer, &crtc->mode); + if (res) { + DRM_ERROR("Can't set active video area\n"); + return -EINVAL; + } + + return res; + } + + static void sti_crtc_disable(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); + + DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); + + /* Disable Background */ + sti_mixer_set_background_status(mixer, false); + + drm_crtc_vblank_off(crtc); + + /* Disable pixel clock and compo IP clocks */ + if (mixer->id == STI_MIXER_MAIN) { + clk_disable_unprepare(compo->clk_pix_main); + clk_disable_unprepare(compo->clk_compo_main); + } else { + clk_disable_unprepare(compo->clk_pix_aux); + clk_disable_unprepare(compo->clk_compo_aux); + } + + mixer->status = STI_MIXER_DISABLED; + } + + static void + sti_crtc_mode_set_nofb(struct drm_crtc *crtc) + { + sti_crtc_enable(crtc); + sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); + } + -static void sti_crtc_atomic_begin(struct drm_crtc *crtc) ++static void sti_crtc_atomic_begin(struct drm_crtc *crtc, ++ struct drm_crtc_state *old_crtc_state) + { + struct sti_mixer *mixer = to_sti_mixer(crtc); + + if (crtc->state->event) { + crtc->state->event->pipe = drm_crtc_index(crtc); + + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + mixer->pending_event = crtc->state->event; + crtc->state->event = NULL; + } + } + -static void sti_crtc_atomic_flush(struct drm_crtc *crtc) ++static void sti_crtc_atomic_flush(struct drm_crtc *crtc, ++ struct drm_crtc_state *old_crtc_state) + { + 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 = { + .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, + .atomic_begin = sti_crtc_atomic_begin, + .atomic_flush = sti_crtc_atomic_flush, + }; + + static void sti_crtc_destroy(struct drm_crtc *crtc) + { + DRM_DEBUG_KMS("\n"); + drm_crtc_cleanup(crtc); + } + + static int sti_crtc_set_property(struct drm_crtc *crtc, + struct drm_property *property, + uint64_t val) + { + DRM_DEBUG_KMS("\n"); + return 0; + } + + int sti_crtc_vblank_cb(struct notifier_block *nb, + unsigned long event, void *data) + { + struct drm_device *drm_dev; + struct sti_compositor *compo = + container_of(nb, struct sti_compositor, vtg_vblank_nb); + int *crtc = data; + unsigned long flags; + struct sti_private *priv; + + drm_dev = compo->mixer[*crtc]->drm_crtc.dev; + priv = drm_dev->dev_private; + + if ((event != VTG_TOP_FIELD_EVENT) && + (event != VTG_BOTTOM_FIELD_EVENT)) { + DRM_ERROR("unknown event: %lu\n", event); + return -EINVAL; + } + + drm_handle_vblank(drm_dev, *crtc); + + spin_lock_irqsave(&drm_dev->event_lock, flags); + if (compo->mixer[*crtc]->pending_event) { + drm_send_vblank_event(drm_dev, -1, + compo->mixer[*crtc]->pending_event); + drm_vblank_put(drm_dev, *crtc); + compo->mixer[*crtc]->pending_event = NULL; + } + 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; + } + + int sti_crtc_enable_vblank(struct drm_device *dev, int crtc) + { + struct sti_private *dev_priv = dev->dev_private; + struct sti_compositor *compo = dev_priv->compo; + struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; + + DRM_DEBUG_DRIVER("\n"); + + if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, + vtg_vblank_nb, crtc)) { + DRM_ERROR("Cannot register VTG notifier\n"); + return -EINVAL; + } + + return 0; + } + EXPORT_SYMBOL(sti_crtc_enable_vblank); + + void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc) + { + struct sti_private *priv = drm_dev->dev_private; + struct sti_compositor *compo = priv->compo; + struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; + + DRM_DEBUG_DRIVER("\n"); + + if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, vtg_vblank_nb)) + DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); + + /* free the resources of the pending requests */ + if (compo->mixer[crtc]->pending_event) { + drm_vblank_put(drm_dev, crtc); + compo->mixer[crtc]->pending_event = NULL; + } + } + EXPORT_SYMBOL(sti_crtc_disable_vblank); + + static struct drm_crtc_funcs sti_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .destroy = sti_crtc_destroy, + .set_property = sti_crtc_set_property, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + }; + + bool sti_crtc_is_main(struct drm_crtc *crtc) + { + struct sti_mixer *mixer = to_sti_mixer(crtc); + + if (mixer->id == STI_MIXER_MAIN) + return true; + + return false; + } + EXPORT_SYMBOL(sti_crtc_is_main); + + int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, + struct drm_plane *primary, struct drm_plane *cursor) + { + struct drm_crtc *crtc = &mixer->drm_crtc; + int res; + + res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, + &sti_crtc_funcs); + if (res) { + DRM_ERROR("Can't initialze CRTC\n"); + return -EINVAL; + } + + drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs); + + DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n", + crtc->base.id, sti_mixer_to_str(mixer)); + + return 0; + }