xref: /openbmc/linux/drivers/gpu/drm/sti/sti_crtc.c (revision 3bc6b01d)
19e1f05b2SVincent Abriou /*
29e1f05b2SVincent Abriou  * Copyright (C) STMicroelectronics SA 2014
39e1f05b2SVincent Abriou  * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
49e1f05b2SVincent Abriou  *          Fabien Dessenne <fabien.dessenne@st.com>
59e1f05b2SVincent Abriou  *          for STMicroelectronics.
69e1f05b2SVincent Abriou  * License terms:  GNU General Public License (GPL), version 2
79e1f05b2SVincent Abriou  */
89e1f05b2SVincent Abriou 
99e1f05b2SVincent Abriou #include <linux/clk.h>
109e1f05b2SVincent Abriou 
119e1f05b2SVincent Abriou #include <drm/drmP.h>
129e1f05b2SVincent Abriou #include <drm/drm_atomic.h>
139e1f05b2SVincent Abriou #include <drm/drm_atomic_helper.h>
149e1f05b2SVincent Abriou #include <drm/drm_crtc_helper.h>
159e1f05b2SVincent Abriou #include <drm/drm_plane_helper.h>
169e1f05b2SVincent Abriou 
179e1f05b2SVincent Abriou #include "sti_compositor.h"
189e1f05b2SVincent Abriou #include "sti_crtc.h"
199e1f05b2SVincent Abriou #include "sti_drv.h"
2029d1dc62SVincent Abriou #include "sti_vid.h"
219e1f05b2SVincent Abriou #include "sti_vtg.h"
229e1f05b2SVincent Abriou 
2329d1dc62SVincent Abriou static void sti_crtc_enable(struct drm_crtc *crtc)
249e1f05b2SVincent Abriou {
259e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
269e1f05b2SVincent Abriou 
2729d1dc62SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
2829d1dc62SVincent Abriou 
2929d1dc62SVincent Abriou 	mixer->status = STI_MIXER_READY;
309e1f05b2SVincent Abriou 
3129d1dc62SVincent Abriou 	drm_crtc_vblank_on(crtc);
329e1f05b2SVincent Abriou }
339e1f05b2SVincent Abriou 
3429d1dc62SVincent Abriou static void sti_crtc_disabling(struct drm_crtc *crtc)
359e1f05b2SVincent Abriou {
369e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
379e1f05b2SVincent Abriou 
3829d1dc62SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
399e1f05b2SVincent Abriou 
4029d1dc62SVincent Abriou 	mixer->status = STI_MIXER_DISABLING;
419e1f05b2SVincent Abriou }
429e1f05b2SVincent Abriou 
439e1f05b2SVincent Abriou static int
449e1f05b2SVincent Abriou sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
459e1f05b2SVincent Abriou {
469e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
479e1f05b2SVincent Abriou 	struct device *dev = mixer->dev;
489e1f05b2SVincent Abriou 	struct sti_compositor *compo = dev_get_drvdata(dev);
4932e14592SBenjamin Gaignard 	struct clk *compo_clk, *pix_clk;
509e1f05b2SVincent Abriou 	int rate = mode->clock * 1000;
519e1f05b2SVincent Abriou 
529e1f05b2SVincent Abriou 	DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n",
539e1f05b2SVincent Abriou 		      crtc->base.id, sti_mixer_to_str(mixer),
549e1f05b2SVincent Abriou 		      mode->base.id, mode->name);
559e1f05b2SVincent Abriou 
569e1f05b2SVincent Abriou 	DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
579e1f05b2SVincent Abriou 		      mode->vrefresh, mode->clock,
589e1f05b2SVincent Abriou 		      mode->hdisplay,
599e1f05b2SVincent Abriou 		      mode->hsync_start, mode->hsync_end,
609e1f05b2SVincent Abriou 		      mode->htotal,
619e1f05b2SVincent Abriou 		      mode->vdisplay,
629e1f05b2SVincent Abriou 		      mode->vsync_start, mode->vsync_end,
639e1f05b2SVincent Abriou 		      mode->vtotal, mode->type, mode->flags);
649e1f05b2SVincent Abriou 
6532e14592SBenjamin Gaignard 	if (mixer->id == STI_MIXER_MAIN) {
6632e14592SBenjamin Gaignard 		compo_clk = compo->clk_compo_main;
6732e14592SBenjamin Gaignard 		pix_clk = compo->clk_pix_main;
6832e14592SBenjamin Gaignard 	} else {
6932e14592SBenjamin Gaignard 		compo_clk = compo->clk_compo_aux;
7032e14592SBenjamin Gaignard 		pix_clk = compo->clk_pix_aux;
719e1f05b2SVincent Abriou 	}
7232e14592SBenjamin Gaignard 
7332e14592SBenjamin Gaignard 	/* Prepare and enable the compo IP clock */
7432e14592SBenjamin Gaignard 	if (clk_prepare_enable(compo_clk)) {
7532e14592SBenjamin Gaignard 		DRM_INFO("Failed to prepare/enable compositor clk\n");
7632e14592SBenjamin Gaignard 		goto compo_error;
7732e14592SBenjamin Gaignard 	}
7832e14592SBenjamin Gaignard 
7932e14592SBenjamin Gaignard 	/* Set rate and prepare/enable pixel clock */
8032e14592SBenjamin Gaignard 	if (clk_set_rate(pix_clk, rate) < 0) {
8132e14592SBenjamin Gaignard 		DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate);
8232e14592SBenjamin Gaignard 		goto pix_error;
8332e14592SBenjamin Gaignard 	}
8432e14592SBenjamin Gaignard 	if (clk_prepare_enable(pix_clk)) {
859e1f05b2SVincent Abriou 		DRM_ERROR("Failed to prepare/enable pix clk\n");
8632e14592SBenjamin Gaignard 		goto pix_error;
879e1f05b2SVincent Abriou 	}
889e1f05b2SVincent Abriou 
89ffdbb82cSFabien Dessenne 	sti_vtg_set_config(compo->vtg[mixer->id], &crtc->mode);
909e1f05b2SVincent Abriou 
9132e14592SBenjamin Gaignard 	if (sti_mixer_active_video_area(mixer, &crtc->mode)) {
929e1f05b2SVincent Abriou 		DRM_ERROR("Can't set active video area\n");
9332e14592SBenjamin Gaignard 		goto mixer_error;
949e1f05b2SVincent Abriou 	}
959e1f05b2SVincent Abriou 
9632e14592SBenjamin Gaignard 	return 0;
9732e14592SBenjamin Gaignard 
9832e14592SBenjamin Gaignard mixer_error:
9932e14592SBenjamin Gaignard 	clk_disable_unprepare(pix_clk);
10032e14592SBenjamin Gaignard pix_error:
10132e14592SBenjamin Gaignard 	clk_disable_unprepare(compo_clk);
10232e14592SBenjamin Gaignard compo_error:
10332e14592SBenjamin Gaignard 	return -EINVAL;
1049e1f05b2SVincent Abriou }
1059e1f05b2SVincent Abriou 
1069e1f05b2SVincent Abriou static void sti_crtc_disable(struct drm_crtc *crtc)
1079e1f05b2SVincent Abriou {
1089e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
1099e1f05b2SVincent Abriou 	struct device *dev = mixer->dev;
1109e1f05b2SVincent Abriou 	struct sti_compositor *compo = dev_get_drvdata(dev);
1119e1f05b2SVincent Abriou 
1129e1f05b2SVincent Abriou 	DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
1139e1f05b2SVincent Abriou 
1149e1f05b2SVincent Abriou 	/* Disable Background */
1159e1f05b2SVincent Abriou 	sti_mixer_set_background_status(mixer, false);
1169e1f05b2SVincent Abriou 
1179e1f05b2SVincent Abriou 	drm_crtc_vblank_off(crtc);
1189e1f05b2SVincent Abriou 
1199e1f05b2SVincent Abriou 	/* Disable pixel clock and compo IP clocks */
1209e1f05b2SVincent Abriou 	if (mixer->id == STI_MIXER_MAIN) {
1219e1f05b2SVincent Abriou 		clk_disable_unprepare(compo->clk_pix_main);
1229e1f05b2SVincent Abriou 		clk_disable_unprepare(compo->clk_compo_main);
1239e1f05b2SVincent Abriou 	} else {
1249e1f05b2SVincent Abriou 		clk_disable_unprepare(compo->clk_pix_aux);
1259e1f05b2SVincent Abriou 		clk_disable_unprepare(compo->clk_compo_aux);
1269e1f05b2SVincent Abriou 	}
1279e1f05b2SVincent Abriou 
12829d1dc62SVincent Abriou 	mixer->status = STI_MIXER_DISABLED;
1299e1f05b2SVincent Abriou }
1309e1f05b2SVincent Abriou 
1319e1f05b2SVincent Abriou static void
1329e1f05b2SVincent Abriou sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
1339e1f05b2SVincent Abriou {
1349e1f05b2SVincent Abriou 	sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
1359e1f05b2SVincent Abriou }
1369e1f05b2SVincent Abriou 
137e1474e7bSDave Airlie static void sti_crtc_atomic_begin(struct drm_crtc *crtc,
138e1474e7bSDave Airlie 				  struct drm_crtc_state *old_crtc_state)
1399e1f05b2SVincent Abriou {
1409e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
1419e1f05b2SVincent Abriou 
1429e1f05b2SVincent Abriou 	if (crtc->state->event) {
1439e1f05b2SVincent Abriou 		crtc->state->event->pipe = drm_crtc_index(crtc);
1449e1f05b2SVincent Abriou 
1459e1f05b2SVincent Abriou 		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
1469e1f05b2SVincent Abriou 
1479e1f05b2SVincent Abriou 		mixer->pending_event = crtc->state->event;
1489e1f05b2SVincent Abriou 		crtc->state->event = NULL;
1499e1f05b2SVincent Abriou 	}
1509e1f05b2SVincent Abriou }
1519e1f05b2SVincent Abriou 
152e1474e7bSDave Airlie static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
153e1474e7bSDave Airlie 				  struct drm_crtc_state *old_crtc_state)
1549e1f05b2SVincent Abriou {
15529d1dc62SVincent Abriou 	struct drm_device *drm_dev = crtc->dev;
15629d1dc62SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
15729d1dc62SVincent Abriou 	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
15829d1dc62SVincent Abriou 	struct drm_plane *p;
15929d1dc62SVincent Abriou 
16029d1dc62SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
16129d1dc62SVincent Abriou 
16229d1dc62SVincent Abriou 	/* perform plane actions */
16329d1dc62SVincent Abriou 	list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
16429d1dc62SVincent Abriou 		struct sti_plane *plane = to_sti_plane(p);
16529d1dc62SVincent Abriou 
16629d1dc62SVincent Abriou 		switch (plane->status) {
16729d1dc62SVincent Abriou 		case STI_PLANE_UPDATED:
1683bc6b01dSFabien Dessenne 			/* ignore update for other CRTC */
1693bc6b01dSFabien Dessenne 			if (p->state->crtc != crtc)
1703bc6b01dSFabien Dessenne 				continue;
1713bc6b01dSFabien Dessenne 
17229d1dc62SVincent Abriou 			/* update planes tag as updated */
17329d1dc62SVincent Abriou 			DRM_DEBUG_DRIVER("update plane %s\n",
17429d1dc62SVincent Abriou 					 sti_plane_to_str(plane));
17529d1dc62SVincent Abriou 
17629d1dc62SVincent Abriou 			if (sti_mixer_set_plane_depth(mixer, plane)) {
17729d1dc62SVincent Abriou 				DRM_ERROR("Cannot set plane %s depth\n",
17829d1dc62SVincent Abriou 					  sti_plane_to_str(plane));
17929d1dc62SVincent Abriou 				break;
18029d1dc62SVincent Abriou 			}
18129d1dc62SVincent Abriou 
18229d1dc62SVincent Abriou 			if (sti_mixer_set_plane_status(mixer, plane, true)) {
18329d1dc62SVincent Abriou 				DRM_ERROR("Cannot enable plane %s at mixer\n",
18429d1dc62SVincent Abriou 					  sti_plane_to_str(plane));
18529d1dc62SVincent Abriou 				break;
18629d1dc62SVincent Abriou 			}
18729d1dc62SVincent Abriou 
18829d1dc62SVincent Abriou 			/* if plane is HQVDP_0 then commit the vid[0] */
18929d1dc62SVincent Abriou 			if (plane->desc == STI_HQVDP_0)
19029d1dc62SVincent Abriou 				sti_vid_commit(compo->vid[0], p->state);
19129d1dc62SVincent Abriou 
19229d1dc62SVincent Abriou 			plane->status = STI_PLANE_READY;
19329d1dc62SVincent Abriou 
19429d1dc62SVincent Abriou 			break;
19529d1dc62SVincent Abriou 		case STI_PLANE_DISABLING:
19629d1dc62SVincent Abriou 			/* disabling sequence for planes tag as disabling */
19729d1dc62SVincent Abriou 			DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
19829d1dc62SVincent Abriou 					 sti_plane_to_str(plane));
19929d1dc62SVincent Abriou 
20029d1dc62SVincent Abriou 			if (sti_mixer_set_plane_status(mixer, plane, false)) {
20129d1dc62SVincent Abriou 				DRM_ERROR("Cannot disable plane %s at mixer\n",
20229d1dc62SVincent Abriou 					  sti_plane_to_str(plane));
20329d1dc62SVincent Abriou 				continue;
20429d1dc62SVincent Abriou 			}
20529d1dc62SVincent Abriou 
20629d1dc62SVincent Abriou 			if (plane->desc == STI_CURSOR)
20729d1dc62SVincent Abriou 				/* tag plane status for disabled */
20829d1dc62SVincent Abriou 				plane->status = STI_PLANE_DISABLED;
20929d1dc62SVincent Abriou 			else
21029d1dc62SVincent Abriou 				/* tag plane status for flushing */
21129d1dc62SVincent Abriou 				plane->status = STI_PLANE_FLUSHING;
21229d1dc62SVincent Abriou 
21329d1dc62SVincent Abriou 			/* if plane is HQVDP_0 then disable the vid[0] */
21429d1dc62SVincent Abriou 			if (plane->desc == STI_HQVDP_0)
21529d1dc62SVincent Abriou 				sti_vid_disable(compo->vid[0]);
21629d1dc62SVincent Abriou 
21729d1dc62SVincent Abriou 			break;
21829d1dc62SVincent Abriou 		default:
21929d1dc62SVincent Abriou 			/* Other status case are not handled */
22029d1dc62SVincent Abriou 			break;
22129d1dc62SVincent Abriou 		}
22229d1dc62SVincent Abriou 	}
2239e1f05b2SVincent Abriou }
2249e1f05b2SVincent Abriou 
225c5de4853SVille Syrjälä static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
22629d1dc62SVincent Abriou 	.enable = sti_crtc_enable,
22729d1dc62SVincent Abriou 	.disable = sti_crtc_disabling,
2289e1f05b2SVincent Abriou 	.mode_set_nofb = sti_crtc_mode_set_nofb,
2299e1f05b2SVincent Abriou 	.atomic_begin = sti_crtc_atomic_begin,
2309e1f05b2SVincent Abriou 	.atomic_flush = sti_crtc_atomic_flush,
2319e1f05b2SVincent Abriou };
2329e1f05b2SVincent Abriou 
2339e1f05b2SVincent Abriou static void sti_crtc_destroy(struct drm_crtc *crtc)
2349e1f05b2SVincent Abriou {
2359e1f05b2SVincent Abriou 	DRM_DEBUG_KMS("\n");
2369e1f05b2SVincent Abriou 	drm_crtc_cleanup(crtc);
2379e1f05b2SVincent Abriou }
2389e1f05b2SVincent Abriou 
2399e1f05b2SVincent Abriou static int sti_crtc_set_property(struct drm_crtc *crtc,
2409e1f05b2SVincent Abriou 				 struct drm_property *property,
2419e1f05b2SVincent Abriou 				 uint64_t val)
2429e1f05b2SVincent Abriou {
2439e1f05b2SVincent Abriou 	DRM_DEBUG_KMS("\n");
2449e1f05b2SVincent Abriou 	return 0;
2459e1f05b2SVincent Abriou }
2469e1f05b2SVincent Abriou 
2479e1f05b2SVincent Abriou int sti_crtc_vblank_cb(struct notifier_block *nb,
2489e1f05b2SVincent Abriou 		       unsigned long event, void *data)
2499e1f05b2SVincent Abriou {
250ae217850SFabien Dessenne 	struct sti_compositor *compo;
2512388693eSThierry Reding 	struct drm_crtc *crtc = data;
2522388693eSThierry Reding 	struct sti_mixer *mixer;
2539e1f05b2SVincent Abriou 	unsigned long flags;
2549e1f05b2SVincent Abriou 	struct sti_private *priv;
2552388693eSThierry Reding 	unsigned int pipe;
2569e1f05b2SVincent Abriou 
2572388693eSThierry Reding 	priv = crtc->dev->dev_private;
2582388693eSThierry Reding 	pipe = drm_crtc_index(crtc);
259ae217850SFabien Dessenne 	compo = container_of(nb, struct sti_compositor, vtg_vblank_nb[pipe]);
2602388693eSThierry Reding 	mixer = compo->mixer[pipe];
2619e1f05b2SVincent Abriou 
2629e1f05b2SVincent Abriou 	if ((event != VTG_TOP_FIELD_EVENT) &&
2639e1f05b2SVincent Abriou 	    (event != VTG_BOTTOM_FIELD_EVENT)) {
2649e1f05b2SVincent Abriou 		DRM_ERROR("unknown event: %lu\n", event);
2659e1f05b2SVincent Abriou 		return -EINVAL;
2669e1f05b2SVincent Abriou 	}
2679e1f05b2SVincent Abriou 
2682388693eSThierry Reding 	drm_crtc_handle_vblank(crtc);
2699e1f05b2SVincent Abriou 
2702388693eSThierry Reding 	spin_lock_irqsave(&crtc->dev->event_lock, flags);
2712388693eSThierry Reding 	if (mixer->pending_event) {
2722388693eSThierry Reding 		drm_crtc_send_vblank_event(crtc, mixer->pending_event);
2732388693eSThierry Reding 		drm_crtc_vblank_put(crtc);
2742388693eSThierry Reding 		mixer->pending_event = NULL;
2759e1f05b2SVincent Abriou 	}
2762388693eSThierry Reding 	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
2779e1f05b2SVincent Abriou 
2782388693eSThierry Reding 	if (mixer->status == STI_MIXER_DISABLING) {
27929d1dc62SVincent Abriou 		struct drm_plane *p;
28029d1dc62SVincent Abriou 
28129d1dc62SVincent Abriou 		/* Disable mixer only if all overlay planes (GDP and VDP)
28229d1dc62SVincent Abriou 		 * are disabled */
2832388693eSThierry Reding 		list_for_each_entry(p, &crtc->dev->mode_config.plane_list,
2842388693eSThierry Reding 				    head) {
28529d1dc62SVincent Abriou 			struct sti_plane *plane = to_sti_plane(p);
28629d1dc62SVincent Abriou 
28729d1dc62SVincent Abriou 			if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
28829d1dc62SVincent Abriou 				if (plane->status != STI_PLANE_DISABLED)
28929d1dc62SVincent Abriou 					return 0;
29029d1dc62SVincent Abriou 		}
2912388693eSThierry Reding 		sti_crtc_disable(crtc);
29229d1dc62SVincent Abriou 	}
29329d1dc62SVincent Abriou 
2949e1f05b2SVincent Abriou 	return 0;
2959e1f05b2SVincent Abriou }
2969e1f05b2SVincent Abriou 
29788e72717SThierry Reding int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
2989e1f05b2SVincent Abriou {
2999e1f05b2SVincent Abriou 	struct sti_private *dev_priv = dev->dev_private;
3009e1f05b2SVincent Abriou 	struct sti_compositor *compo = dev_priv->compo;
301ae217850SFabien Dessenne 	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
3022388693eSThierry Reding 	struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
303ffdbb82cSFabien Dessenne 	struct sti_vtg *vtg = compo->vtg[pipe];
3049e1f05b2SVincent Abriou 
3059e1f05b2SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
3069e1f05b2SVincent Abriou 
307ffdbb82cSFabien Dessenne 	if (sti_vtg_register_client(vtg, vtg_vblank_nb, crtc)) {
3089e1f05b2SVincent Abriou 		DRM_ERROR("Cannot register VTG notifier\n");
3099e1f05b2SVincent Abriou 		return -EINVAL;
3109e1f05b2SVincent Abriou 	}
3119e1f05b2SVincent Abriou 
3129e1f05b2SVincent Abriou 	return 0;
3139e1f05b2SVincent Abriou }
3149e1f05b2SVincent Abriou 
31588e72717SThierry Reding void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
3169e1f05b2SVincent Abriou {
31729d1dc62SVincent Abriou 	struct sti_private *priv = drm_dev->dev_private;
3189e1f05b2SVincent Abriou 	struct sti_compositor *compo = priv->compo;
319ae217850SFabien Dessenne 	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
3202388693eSThierry Reding 	struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
321ffdbb82cSFabien Dessenne 	struct sti_vtg *vtg = compo->vtg[pipe];
3229e1f05b2SVincent Abriou 
3239e1f05b2SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
3249e1f05b2SVincent Abriou 
325ffdbb82cSFabien Dessenne 	if (sti_vtg_unregister_client(vtg, vtg_vblank_nb))
3269e1f05b2SVincent Abriou 		DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
3279e1f05b2SVincent Abriou 
3289e1f05b2SVincent Abriou 	/* free the resources of the pending requests */
32988e72717SThierry Reding 	if (compo->mixer[pipe]->pending_event) {
3302388693eSThierry Reding 		drm_crtc_vblank_put(crtc);
33188e72717SThierry Reding 		compo->mixer[pipe]->pending_event = NULL;
3329e1f05b2SVincent Abriou 	}
3339e1f05b2SVincent Abriou }
3349e1f05b2SVincent Abriou 
33583af0a48SBenjamin Gaignard static int sti_crtc_late_register(struct drm_crtc *crtc)
33683af0a48SBenjamin Gaignard {
33783af0a48SBenjamin Gaignard 	struct sti_mixer *mixer = to_sti_mixer(crtc);
33883af0a48SBenjamin Gaignard 	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
33983af0a48SBenjamin Gaignard 
34083af0a48SBenjamin Gaignard 	if (drm_crtc_index(crtc) == 0)
34183af0a48SBenjamin Gaignard 		return sti_compositor_debufs_init(compo, crtc->dev->primary);
34283af0a48SBenjamin Gaignard 
34383af0a48SBenjamin Gaignard 	return 0;
34483af0a48SBenjamin Gaignard }
34583af0a48SBenjamin Gaignard 
346c5de4853SVille Syrjälä static const struct drm_crtc_funcs sti_crtc_funcs = {
3479e1f05b2SVincent Abriou 	.set_config = drm_atomic_helper_set_config,
3489e1f05b2SVincent Abriou 	.page_flip = drm_atomic_helper_page_flip,
3499e1f05b2SVincent Abriou 	.destroy = sti_crtc_destroy,
3509e1f05b2SVincent Abriou 	.set_property = sti_crtc_set_property,
3519e1f05b2SVincent Abriou 	.reset = drm_atomic_helper_crtc_reset,
3529e1f05b2SVincent Abriou 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
3539e1f05b2SVincent Abriou 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
35483af0a48SBenjamin Gaignard 	.late_register = sti_crtc_late_register,
3559e1f05b2SVincent Abriou };
3569e1f05b2SVincent Abriou 
3579e1f05b2SVincent Abriou bool sti_crtc_is_main(struct drm_crtc *crtc)
3589e1f05b2SVincent Abriou {
3599e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
3609e1f05b2SVincent Abriou 
3619e1f05b2SVincent Abriou 	if (mixer->id == STI_MIXER_MAIN)
3629e1f05b2SVincent Abriou 		return true;
3639e1f05b2SVincent Abriou 
3649e1f05b2SVincent Abriou 	return false;
3659e1f05b2SVincent Abriou }
3669e1f05b2SVincent Abriou 
3679e1f05b2SVincent Abriou int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
3689e1f05b2SVincent Abriou 		  struct drm_plane *primary, struct drm_plane *cursor)
3699e1f05b2SVincent Abriou {
3709e1f05b2SVincent Abriou 	struct drm_crtc *crtc = &mixer->drm_crtc;
3719e1f05b2SVincent Abriou 	int res;
3729e1f05b2SVincent Abriou 
3739e1f05b2SVincent Abriou 	res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
374f9882876SVille Syrjälä 					&sti_crtc_funcs, NULL);
3759e1f05b2SVincent Abriou 	if (res) {
3769e1f05b2SVincent Abriou 		DRM_ERROR("Can't initialze CRTC\n");
3779e1f05b2SVincent Abriou 		return -EINVAL;
3789e1f05b2SVincent Abriou 	}
3799e1f05b2SVincent Abriou 
3809e1f05b2SVincent Abriou 	drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs);
3819e1f05b2SVincent Abriou 
3829e1f05b2SVincent Abriou 	DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n",
3839e1f05b2SVincent Abriou 			 crtc->base.id, sti_mixer_to_str(mixer));
3849e1f05b2SVincent Abriou 
3859e1f05b2SVincent Abriou 	return 0;
3869e1f05b2SVincent Abriou }
387