Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) STMicroelectronics SA 2014
0004  * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
0005  *          Fabien Dessenne <fabien.dessenne@st.com>
0006  *          for STMicroelectronics.
0007  */
0008 
0009 #include <linux/clk.h>
0010 
0011 #include <drm/drm_atomic.h>
0012 #include <drm/drm_atomic_helper.h>
0013 #include <drm/drm_device.h>
0014 #include <drm/drm_plane_helper.h>
0015 #include <drm/drm_print.h>
0016 #include <drm/drm_probe_helper.h>
0017 #include <drm/drm_vblank.h>
0018 
0019 #include "sti_compositor.h"
0020 #include "sti_crtc.h"
0021 #include "sti_drv.h"
0022 #include "sti_vid.h"
0023 #include "sti_vtg.h"
0024 
0025 static void sti_crtc_atomic_enable(struct drm_crtc *crtc,
0026                    struct drm_atomic_state *state)
0027 {
0028     struct sti_mixer *mixer = to_sti_mixer(crtc);
0029 
0030     DRM_DEBUG_DRIVER("\n");
0031 
0032     mixer->status = STI_MIXER_READY;
0033 
0034     drm_crtc_vblank_on(crtc);
0035 }
0036 
0037 static void sti_crtc_atomic_disable(struct drm_crtc *crtc,
0038                     struct drm_atomic_state *state)
0039 {
0040     struct sti_mixer *mixer = to_sti_mixer(crtc);
0041 
0042     DRM_DEBUG_DRIVER("\n");
0043 
0044     mixer->status = STI_MIXER_DISABLING;
0045 
0046     drm_crtc_wait_one_vblank(crtc);
0047 }
0048 
0049 static int
0050 sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
0051 {
0052     struct sti_mixer *mixer = to_sti_mixer(crtc);
0053     struct device *dev = mixer->dev;
0054     struct sti_compositor *compo = dev_get_drvdata(dev);
0055     struct clk *compo_clk, *pix_clk;
0056     int rate = mode->clock * 1000;
0057 
0058     DRM_DEBUG_KMS("CRTC:%d (%s) mode: (%s)\n",
0059               crtc->base.id, sti_mixer_to_str(mixer), mode->name);
0060 
0061     DRM_DEBUG_KMS(DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
0062 
0063     if (mixer->id == STI_MIXER_MAIN) {
0064         compo_clk = compo->clk_compo_main;
0065         pix_clk = compo->clk_pix_main;
0066     } else {
0067         compo_clk = compo->clk_compo_aux;
0068         pix_clk = compo->clk_pix_aux;
0069     }
0070 
0071     /* Prepare and enable the compo IP clock */
0072     if (clk_prepare_enable(compo_clk)) {
0073         DRM_INFO("Failed to prepare/enable compositor clk\n");
0074         goto compo_error;
0075     }
0076 
0077     /* Set rate and prepare/enable pixel clock */
0078     if (clk_set_rate(pix_clk, rate) < 0) {
0079         DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate);
0080         goto pix_error;
0081     }
0082     if (clk_prepare_enable(pix_clk)) {
0083         DRM_ERROR("Failed to prepare/enable pix clk\n");
0084         goto pix_error;
0085     }
0086 
0087     sti_vtg_set_config(compo->vtg[mixer->id], &crtc->mode);
0088 
0089     if (sti_mixer_active_video_area(mixer, &crtc->mode)) {
0090         DRM_ERROR("Can't set active video area\n");
0091         goto mixer_error;
0092     }
0093 
0094     return 0;
0095 
0096 mixer_error:
0097     clk_disable_unprepare(pix_clk);
0098 pix_error:
0099     clk_disable_unprepare(compo_clk);
0100 compo_error:
0101     return -EINVAL;
0102 }
0103 
0104 static void sti_crtc_disable(struct drm_crtc *crtc)
0105 {
0106     struct sti_mixer *mixer = to_sti_mixer(crtc);
0107     struct device *dev = mixer->dev;
0108     struct sti_compositor *compo = dev_get_drvdata(dev);
0109 
0110     DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
0111 
0112     /* Disable Background */
0113     sti_mixer_set_background_status(mixer, false);
0114 
0115     drm_crtc_vblank_off(crtc);
0116 
0117     /* Disable pixel clock and compo IP clocks */
0118     if (mixer->id == STI_MIXER_MAIN) {
0119         clk_disable_unprepare(compo->clk_pix_main);
0120         clk_disable_unprepare(compo->clk_compo_main);
0121     } else {
0122         clk_disable_unprepare(compo->clk_pix_aux);
0123         clk_disable_unprepare(compo->clk_compo_aux);
0124     }
0125 
0126     mixer->status = STI_MIXER_DISABLED;
0127 }
0128 
0129 static void
0130 sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
0131 {
0132     sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
0133 }
0134 
0135 static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
0136                   struct drm_atomic_state *state)
0137 {
0138     struct drm_device *drm_dev = crtc->dev;
0139     struct sti_mixer *mixer = to_sti_mixer(crtc);
0140     struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
0141     struct drm_plane *p;
0142     struct drm_pending_vblank_event *event;
0143     unsigned long flags;
0144 
0145     DRM_DEBUG_DRIVER("\n");
0146 
0147     /* perform plane actions */
0148     list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
0149         struct sti_plane *plane = to_sti_plane(p);
0150 
0151         switch (plane->status) {
0152         case STI_PLANE_UPDATED:
0153             /* ignore update for other CRTC */
0154             if (p->state->crtc != crtc)
0155                 continue;
0156 
0157             /* update planes tag as updated */
0158             DRM_DEBUG_DRIVER("update plane %s\n",
0159                      sti_plane_to_str(plane));
0160 
0161             if (sti_mixer_set_plane_depth(mixer, plane)) {
0162                 DRM_ERROR("Cannot set plane %s depth\n",
0163                       sti_plane_to_str(plane));
0164                 break;
0165             }
0166 
0167             if (sti_mixer_set_plane_status(mixer, plane, true)) {
0168                 DRM_ERROR("Cannot enable plane %s at mixer\n",
0169                       sti_plane_to_str(plane));
0170                 break;
0171             }
0172 
0173             /* if plane is HQVDP_0 then commit the vid[0] */
0174             if (plane->desc == STI_HQVDP_0)
0175                 sti_vid_commit(compo->vid[0], p->state);
0176 
0177             plane->status = STI_PLANE_READY;
0178 
0179             break;
0180         case STI_PLANE_DISABLING:
0181             /* disabling sequence for planes tag as disabling */
0182             DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
0183                      sti_plane_to_str(plane));
0184 
0185             if (sti_mixer_set_plane_status(mixer, plane, false)) {
0186                 DRM_ERROR("Cannot disable plane %s at mixer\n",
0187                       sti_plane_to_str(plane));
0188                 continue;
0189             }
0190 
0191             if (plane->desc == STI_CURSOR)
0192                 /* tag plane status for disabled */
0193                 plane->status = STI_PLANE_DISABLED;
0194             else
0195                 /* tag plane status for flushing */
0196                 plane->status = STI_PLANE_FLUSHING;
0197 
0198             /* if plane is HQVDP_0 then disable the vid[0] */
0199             if (plane->desc == STI_HQVDP_0)
0200                 sti_vid_disable(compo->vid[0]);
0201 
0202             break;
0203         default:
0204             /* Other status case are not handled */
0205             break;
0206         }
0207     }
0208 
0209     event = crtc->state->event;
0210     if (event) {
0211         crtc->state->event = NULL;
0212 
0213         spin_lock_irqsave(&crtc->dev->event_lock, flags);
0214         if (drm_crtc_vblank_get(crtc) == 0)
0215             drm_crtc_arm_vblank_event(crtc, event);
0216         else
0217             drm_crtc_send_vblank_event(crtc, event);
0218         spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
0219     }
0220 }
0221 
0222 static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
0223     .mode_set_nofb = sti_crtc_mode_set_nofb,
0224     .atomic_flush = sti_crtc_atomic_flush,
0225     .atomic_enable = sti_crtc_atomic_enable,
0226     .atomic_disable = sti_crtc_atomic_disable,
0227 };
0228 
0229 static void sti_crtc_destroy(struct drm_crtc *crtc)
0230 {
0231     DRM_DEBUG_KMS("\n");
0232     drm_crtc_cleanup(crtc);
0233 }
0234 
0235 static int sti_crtc_set_property(struct drm_crtc *crtc,
0236                  struct drm_property *property,
0237                  uint64_t val)
0238 {
0239     DRM_DEBUG_KMS("\n");
0240     return 0;
0241 }
0242 
0243 int sti_crtc_vblank_cb(struct notifier_block *nb,
0244                unsigned long event, void *data)
0245 {
0246     struct sti_compositor *compo;
0247     struct drm_crtc *crtc = data;
0248     struct sti_mixer *mixer;
0249     unsigned int pipe;
0250 
0251     pipe = drm_crtc_index(crtc);
0252     compo = container_of(nb, struct sti_compositor, vtg_vblank_nb[pipe]);
0253     mixer = compo->mixer[pipe];
0254 
0255     if ((event != VTG_TOP_FIELD_EVENT) &&
0256         (event != VTG_BOTTOM_FIELD_EVENT)) {
0257         DRM_ERROR("unknown event: %lu\n", event);
0258         return -EINVAL;
0259     }
0260 
0261     drm_crtc_handle_vblank(crtc);
0262 
0263     if (mixer->status == STI_MIXER_DISABLING) {
0264         struct drm_plane *p;
0265 
0266         /* Disable mixer only if all overlay planes (GDP and VDP)
0267          * are disabled */
0268         list_for_each_entry(p, &crtc->dev->mode_config.plane_list,
0269                     head) {
0270             struct sti_plane *plane = to_sti_plane(p);
0271 
0272             if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
0273                 if (plane->status != STI_PLANE_DISABLED)
0274                     return 0;
0275         }
0276         sti_crtc_disable(crtc);
0277     }
0278 
0279     return 0;
0280 }
0281 
0282 static int sti_crtc_enable_vblank(struct drm_crtc *crtc)
0283 {
0284     struct drm_device *dev = crtc->dev;
0285     unsigned int pipe = crtc->index;
0286     struct sti_private *dev_priv = dev->dev_private;
0287     struct sti_compositor *compo = dev_priv->compo;
0288     struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
0289     struct sti_vtg *vtg = compo->vtg[pipe];
0290 
0291     DRM_DEBUG_DRIVER("\n");
0292 
0293     if (sti_vtg_register_client(vtg, vtg_vblank_nb, crtc)) {
0294         DRM_ERROR("Cannot register VTG notifier\n");
0295         return -EINVAL;
0296     }
0297 
0298     return 0;
0299 }
0300 
0301 static void sti_crtc_disable_vblank(struct drm_crtc *crtc)
0302 {
0303     struct drm_device *drm_dev = crtc->dev;
0304     unsigned int pipe = crtc->index;
0305     struct sti_private *priv = drm_dev->dev_private;
0306     struct sti_compositor *compo = priv->compo;
0307     struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
0308     struct sti_vtg *vtg = compo->vtg[pipe];
0309 
0310     DRM_DEBUG_DRIVER("\n");
0311 
0312     if (sti_vtg_unregister_client(vtg, vtg_vblank_nb))
0313         DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
0314 }
0315 
0316 static int sti_crtc_late_register(struct drm_crtc *crtc)
0317 {
0318     struct sti_mixer *mixer = to_sti_mixer(crtc);
0319     struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
0320 
0321     if (drm_crtc_index(crtc) == 0)
0322         sti_compositor_debugfs_init(compo, crtc->dev->primary);
0323 
0324     return 0;
0325 }
0326 
0327 static const struct drm_crtc_funcs sti_crtc_funcs = {
0328     .set_config = drm_atomic_helper_set_config,
0329     .page_flip = drm_atomic_helper_page_flip,
0330     .destroy = sti_crtc_destroy,
0331     .set_property = sti_crtc_set_property,
0332     .reset = drm_atomic_helper_crtc_reset,
0333     .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
0334     .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
0335     .late_register = sti_crtc_late_register,
0336     .enable_vblank = sti_crtc_enable_vblank,
0337     .disable_vblank = sti_crtc_disable_vblank,
0338 };
0339 
0340 bool sti_crtc_is_main(struct drm_crtc *crtc)
0341 {
0342     struct sti_mixer *mixer = to_sti_mixer(crtc);
0343 
0344     if (mixer->id == STI_MIXER_MAIN)
0345         return true;
0346 
0347     return false;
0348 }
0349 
0350 int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
0351           struct drm_plane *primary, struct drm_plane *cursor)
0352 {
0353     struct drm_crtc *crtc = &mixer->drm_crtc;
0354     int res;
0355 
0356     res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
0357                     &sti_crtc_funcs, NULL);
0358     if (res) {
0359         DRM_ERROR("Can't initialize CRTC\n");
0360         return -EINVAL;
0361     }
0362 
0363     drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs);
0364 
0365     DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n",
0366              crtc->base.id, sti_mixer_to_str(mixer));
0367 
0368     return 0;
0369 }