xref: /openbmc/linux/drivers/gpu/drm/sti/sti_crtc.c (revision f6ebe9f9)
1e2842570SBenjamin Gaignard // SPDX-License-Identifier: GPL-2.0
29e1f05b2SVincent Abriou /*
39e1f05b2SVincent Abriou  * Copyright (C) STMicroelectronics SA 2014
49e1f05b2SVincent Abriou  * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
59e1f05b2SVincent Abriou  *          Fabien Dessenne <fabien.dessenne@st.com>
69e1f05b2SVincent Abriou  *          for STMicroelectronics.
79e1f05b2SVincent Abriou  */
89e1f05b2SVincent Abriou 
99e1f05b2SVincent Abriou #include <linux/clk.h>
109e1f05b2SVincent Abriou 
119e1f05b2SVincent Abriou #include <drm/drm_atomic.h>
129e1f05b2SVincent Abriou #include <drm/drm_atomic_helper.h>
135e2f97a9SSam Ravnborg #include <drm/drm_device.h>
149e1f05b2SVincent Abriou #include <drm/drm_plane_helper.h>
155e2f97a9SSam Ravnborg #include <drm/drm_print.h>
16fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
175e2f97a9SSam Ravnborg #include <drm/drm_vblank.h>
189e1f05b2SVincent Abriou 
199e1f05b2SVincent Abriou #include "sti_compositor.h"
209e1f05b2SVincent Abriou #include "sti_crtc.h"
219e1f05b2SVincent Abriou #include "sti_drv.h"
2229d1dc62SVincent Abriou #include "sti_vid.h"
239e1f05b2SVincent Abriou #include "sti_vtg.h"
249e1f05b2SVincent Abriou 
250b20a0f8SLaurent Pinchart static void sti_crtc_atomic_enable(struct drm_crtc *crtc,
26351f950dSMaxime Ripard 				   struct drm_atomic_state *state)
279e1f05b2SVincent Abriou {
289e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
299e1f05b2SVincent Abriou 
3029d1dc62SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
3129d1dc62SVincent Abriou 
3229d1dc62SVincent Abriou 	mixer->status = STI_MIXER_READY;
339e1f05b2SVincent Abriou 
3429d1dc62SVincent Abriou 	drm_crtc_vblank_on(crtc);
359e1f05b2SVincent Abriou }
369e1f05b2SVincent Abriou 
3764581714SLaurent Pinchart static void sti_crtc_atomic_disable(struct drm_crtc *crtc,
38351f950dSMaxime Ripard 				    struct drm_atomic_state *state)
399e1f05b2SVincent Abriou {
409e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
419e1f05b2SVincent Abriou 
4229d1dc62SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
439e1f05b2SVincent Abriou 
4429d1dc62SVincent Abriou 	mixer->status = STI_MIXER_DISABLING;
45885054f9SBenjamin Gaignard 
46885054f9SBenjamin Gaignard 	drm_crtc_wait_one_vblank(crtc);
479e1f05b2SVincent Abriou }
489e1f05b2SVincent Abriou 
499e1f05b2SVincent Abriou static int
509e1f05b2SVincent Abriou sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
519e1f05b2SVincent Abriou {
529e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
539e1f05b2SVincent Abriou 	struct device *dev = mixer->dev;
549e1f05b2SVincent Abriou 	struct sti_compositor *compo = dev_get_drvdata(dev);
5532e14592SBenjamin Gaignard 	struct clk *compo_clk, *pix_clk;
569e1f05b2SVincent Abriou 	int rate = mode->clock * 1000;
579e1f05b2SVincent Abriou 
585e8345a0SShayenne Moura 	DRM_DEBUG_KMS("CRTC:%d (%s) mode: (%s)\n",
595e8345a0SShayenne Moura 		      crtc->base.id, sti_mixer_to_str(mixer), mode->name);
609e1f05b2SVincent Abriou 
615e8345a0SShayenne Moura 	DRM_DEBUG_KMS(DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
629e1f05b2SVincent Abriou 
6332e14592SBenjamin Gaignard 	if (mixer->id == STI_MIXER_MAIN) {
6432e14592SBenjamin Gaignard 		compo_clk = compo->clk_compo_main;
6532e14592SBenjamin Gaignard 		pix_clk = compo->clk_pix_main;
6632e14592SBenjamin Gaignard 	} else {
6732e14592SBenjamin Gaignard 		compo_clk = compo->clk_compo_aux;
6832e14592SBenjamin Gaignard 		pix_clk = compo->clk_pix_aux;
699e1f05b2SVincent Abriou 	}
7032e14592SBenjamin Gaignard 
7132e14592SBenjamin Gaignard 	/* Prepare and enable the compo IP clock */
7232e14592SBenjamin Gaignard 	if (clk_prepare_enable(compo_clk)) {
7332e14592SBenjamin Gaignard 		DRM_INFO("Failed to prepare/enable compositor clk\n");
7432e14592SBenjamin Gaignard 		goto compo_error;
7532e14592SBenjamin Gaignard 	}
7632e14592SBenjamin Gaignard 
7732e14592SBenjamin Gaignard 	/* Set rate and prepare/enable pixel clock */
7832e14592SBenjamin Gaignard 	if (clk_set_rate(pix_clk, rate) < 0) {
7932e14592SBenjamin Gaignard 		DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate);
8032e14592SBenjamin Gaignard 		goto pix_error;
8132e14592SBenjamin Gaignard 	}
8232e14592SBenjamin Gaignard 	if (clk_prepare_enable(pix_clk)) {
839e1f05b2SVincent Abriou 		DRM_ERROR("Failed to prepare/enable pix clk\n");
8432e14592SBenjamin Gaignard 		goto pix_error;
859e1f05b2SVincent Abriou 	}
869e1f05b2SVincent Abriou 
87ffdbb82cSFabien Dessenne 	sti_vtg_set_config(compo->vtg[mixer->id], &crtc->mode);
889e1f05b2SVincent Abriou 
8932e14592SBenjamin Gaignard 	if (sti_mixer_active_video_area(mixer, &crtc->mode)) {
909e1f05b2SVincent Abriou 		DRM_ERROR("Can't set active video area\n");
9132e14592SBenjamin Gaignard 		goto mixer_error;
929e1f05b2SVincent Abriou 	}
939e1f05b2SVincent Abriou 
9432e14592SBenjamin Gaignard 	return 0;
9532e14592SBenjamin Gaignard 
9632e14592SBenjamin Gaignard mixer_error:
9732e14592SBenjamin Gaignard 	clk_disable_unprepare(pix_clk);
9832e14592SBenjamin Gaignard pix_error:
9932e14592SBenjamin Gaignard 	clk_disable_unprepare(compo_clk);
10032e14592SBenjamin Gaignard compo_error:
10132e14592SBenjamin Gaignard 	return -EINVAL;
1029e1f05b2SVincent Abriou }
1039e1f05b2SVincent Abriou 
1049e1f05b2SVincent Abriou static void sti_crtc_disable(struct drm_crtc *crtc)
1059e1f05b2SVincent Abriou {
1069e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
1079e1f05b2SVincent Abriou 	struct device *dev = mixer->dev;
1089e1f05b2SVincent Abriou 	struct sti_compositor *compo = dev_get_drvdata(dev);
1099e1f05b2SVincent Abriou 
1109e1f05b2SVincent Abriou 	DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
1119e1f05b2SVincent Abriou 
1129e1f05b2SVincent Abriou 	/* Disable Background */
1139e1f05b2SVincent Abriou 	sti_mixer_set_background_status(mixer, false);
1149e1f05b2SVincent Abriou 
1159e1f05b2SVincent Abriou 	drm_crtc_vblank_off(crtc);
1169e1f05b2SVincent Abriou 
1179e1f05b2SVincent Abriou 	/* Disable pixel clock and compo IP clocks */
1189e1f05b2SVincent Abriou 	if (mixer->id == STI_MIXER_MAIN) {
1199e1f05b2SVincent Abriou 		clk_disable_unprepare(compo->clk_pix_main);
1209e1f05b2SVincent Abriou 		clk_disable_unprepare(compo->clk_compo_main);
1219e1f05b2SVincent Abriou 	} else {
1229e1f05b2SVincent Abriou 		clk_disable_unprepare(compo->clk_pix_aux);
1239e1f05b2SVincent Abriou 		clk_disable_unprepare(compo->clk_compo_aux);
1249e1f05b2SVincent Abriou 	}
1259e1f05b2SVincent Abriou 
12629d1dc62SVincent Abriou 	mixer->status = STI_MIXER_DISABLED;
1279e1f05b2SVincent Abriou }
1289e1f05b2SVincent Abriou 
1299e1f05b2SVincent Abriou static void
1309e1f05b2SVincent Abriou sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
1319e1f05b2SVincent Abriou {
1329e1f05b2SVincent Abriou 	sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
1339e1f05b2SVincent Abriou }
1349e1f05b2SVincent Abriou 
135e1474e7bSDave Airlie static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
136*f6ebe9f9SMaxime Ripard 				  struct drm_atomic_state *state)
1379e1f05b2SVincent Abriou {
13829d1dc62SVincent Abriou 	struct drm_device *drm_dev = crtc->dev;
13929d1dc62SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
14029d1dc62SVincent Abriou 	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
14129d1dc62SVincent Abriou 	struct drm_plane *p;
142c62052d1SFabien DESSENNE 	struct drm_pending_vblank_event *event;
143c62052d1SFabien DESSENNE 	unsigned long flags;
14429d1dc62SVincent Abriou 
14529d1dc62SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
14629d1dc62SVincent Abriou 
14729d1dc62SVincent Abriou 	/* perform plane actions */
14829d1dc62SVincent Abriou 	list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
14929d1dc62SVincent Abriou 		struct sti_plane *plane = to_sti_plane(p);
15029d1dc62SVincent Abriou 
15129d1dc62SVincent Abriou 		switch (plane->status) {
15229d1dc62SVincent Abriou 		case STI_PLANE_UPDATED:
1533bc6b01dSFabien Dessenne 			/* ignore update for other CRTC */
1543bc6b01dSFabien Dessenne 			if (p->state->crtc != crtc)
1553bc6b01dSFabien Dessenne 				continue;
1563bc6b01dSFabien Dessenne 
15729d1dc62SVincent Abriou 			/* update planes tag as updated */
15829d1dc62SVincent Abriou 			DRM_DEBUG_DRIVER("update plane %s\n",
15929d1dc62SVincent Abriou 					 sti_plane_to_str(plane));
16029d1dc62SVincent Abriou 
16129d1dc62SVincent Abriou 			if (sti_mixer_set_plane_depth(mixer, plane)) {
16229d1dc62SVincent Abriou 				DRM_ERROR("Cannot set plane %s depth\n",
16329d1dc62SVincent Abriou 					  sti_plane_to_str(plane));
16429d1dc62SVincent Abriou 				break;
16529d1dc62SVincent Abriou 			}
16629d1dc62SVincent Abriou 
16729d1dc62SVincent Abriou 			if (sti_mixer_set_plane_status(mixer, plane, true)) {
16829d1dc62SVincent Abriou 				DRM_ERROR("Cannot enable plane %s at mixer\n",
16929d1dc62SVincent Abriou 					  sti_plane_to_str(plane));
17029d1dc62SVincent Abriou 				break;
17129d1dc62SVincent Abriou 			}
17229d1dc62SVincent Abriou 
17329d1dc62SVincent Abriou 			/* if plane is HQVDP_0 then commit the vid[0] */
17429d1dc62SVincent Abriou 			if (plane->desc == STI_HQVDP_0)
17529d1dc62SVincent Abriou 				sti_vid_commit(compo->vid[0], p->state);
17629d1dc62SVincent Abriou 
17729d1dc62SVincent Abriou 			plane->status = STI_PLANE_READY;
17829d1dc62SVincent Abriou 
17929d1dc62SVincent Abriou 			break;
18029d1dc62SVincent Abriou 		case STI_PLANE_DISABLING:
18129d1dc62SVincent Abriou 			/* disabling sequence for planes tag as disabling */
18229d1dc62SVincent Abriou 			DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
18329d1dc62SVincent Abriou 					 sti_plane_to_str(plane));
18429d1dc62SVincent Abriou 
18529d1dc62SVincent Abriou 			if (sti_mixer_set_plane_status(mixer, plane, false)) {
18629d1dc62SVincent Abriou 				DRM_ERROR("Cannot disable plane %s at mixer\n",
18729d1dc62SVincent Abriou 					  sti_plane_to_str(plane));
18829d1dc62SVincent Abriou 				continue;
18929d1dc62SVincent Abriou 			}
19029d1dc62SVincent Abriou 
19129d1dc62SVincent Abriou 			if (plane->desc == STI_CURSOR)
19229d1dc62SVincent Abriou 				/* tag plane status for disabled */
19329d1dc62SVincent Abriou 				plane->status = STI_PLANE_DISABLED;
19429d1dc62SVincent Abriou 			else
19529d1dc62SVincent Abriou 				/* tag plane status for flushing */
19629d1dc62SVincent Abriou 				plane->status = STI_PLANE_FLUSHING;
19729d1dc62SVincent Abriou 
19829d1dc62SVincent Abriou 			/* if plane is HQVDP_0 then disable the vid[0] */
19929d1dc62SVincent Abriou 			if (plane->desc == STI_HQVDP_0)
20029d1dc62SVincent Abriou 				sti_vid_disable(compo->vid[0]);
20129d1dc62SVincent Abriou 
20229d1dc62SVincent Abriou 			break;
20329d1dc62SVincent Abriou 		default:
20429d1dc62SVincent Abriou 			/* Other status case are not handled */
20529d1dc62SVincent Abriou 			break;
20629d1dc62SVincent Abriou 		}
20729d1dc62SVincent Abriou 	}
208c62052d1SFabien DESSENNE 
209c62052d1SFabien DESSENNE 	event = crtc->state->event;
210c62052d1SFabien DESSENNE 	if (event) {
211c62052d1SFabien DESSENNE 		crtc->state->event = NULL;
212c62052d1SFabien DESSENNE 
213c62052d1SFabien DESSENNE 		spin_lock_irqsave(&crtc->dev->event_lock, flags);
214c62052d1SFabien DESSENNE 		if (drm_crtc_vblank_get(crtc) == 0)
215c62052d1SFabien DESSENNE 			drm_crtc_arm_vblank_event(crtc, event);
216c62052d1SFabien DESSENNE 		else
217c62052d1SFabien DESSENNE 			drm_crtc_send_vblank_event(crtc, event);
218c62052d1SFabien DESSENNE 		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
219c62052d1SFabien DESSENNE 	}
2209e1f05b2SVincent Abriou }
2219e1f05b2SVincent Abriou 
222c5de4853SVille Syrjälä static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
2239e1f05b2SVincent Abriou 	.mode_set_nofb = sti_crtc_mode_set_nofb,
2249e1f05b2SVincent Abriou 	.atomic_flush = sti_crtc_atomic_flush,
2250b20a0f8SLaurent Pinchart 	.atomic_enable = sti_crtc_atomic_enable,
22664581714SLaurent Pinchart 	.atomic_disable = sti_crtc_atomic_disable,
2279e1f05b2SVincent Abriou };
2289e1f05b2SVincent Abriou 
2299e1f05b2SVincent Abriou static void sti_crtc_destroy(struct drm_crtc *crtc)
2309e1f05b2SVincent Abriou {
2319e1f05b2SVincent Abriou 	DRM_DEBUG_KMS("\n");
2329e1f05b2SVincent Abriou 	drm_crtc_cleanup(crtc);
2339e1f05b2SVincent Abriou }
2349e1f05b2SVincent Abriou 
2359e1f05b2SVincent Abriou static int sti_crtc_set_property(struct drm_crtc *crtc,
2369e1f05b2SVincent Abriou 				 struct drm_property *property,
2379e1f05b2SVincent Abriou 				 uint64_t val)
2389e1f05b2SVincent Abriou {
2399e1f05b2SVincent Abriou 	DRM_DEBUG_KMS("\n");
2409e1f05b2SVincent Abriou 	return 0;
2419e1f05b2SVincent Abriou }
2429e1f05b2SVincent Abriou 
2439e1f05b2SVincent Abriou int sti_crtc_vblank_cb(struct notifier_block *nb,
2449e1f05b2SVincent Abriou 		       unsigned long event, void *data)
2459e1f05b2SVincent Abriou {
246ae217850SFabien Dessenne 	struct sti_compositor *compo;
2472388693eSThierry Reding 	struct drm_crtc *crtc = data;
2482388693eSThierry Reding 	struct sti_mixer *mixer;
2492388693eSThierry Reding 	unsigned int pipe;
2509e1f05b2SVincent Abriou 
2512388693eSThierry Reding 	pipe = drm_crtc_index(crtc);
252ae217850SFabien Dessenne 	compo = container_of(nb, struct sti_compositor, vtg_vblank_nb[pipe]);
2532388693eSThierry Reding 	mixer = compo->mixer[pipe];
2549e1f05b2SVincent Abriou 
2559e1f05b2SVincent Abriou 	if ((event != VTG_TOP_FIELD_EVENT) &&
2569e1f05b2SVincent Abriou 	    (event != VTG_BOTTOM_FIELD_EVENT)) {
2579e1f05b2SVincent Abriou 		DRM_ERROR("unknown event: %lu\n", event);
2589e1f05b2SVincent Abriou 		return -EINVAL;
2599e1f05b2SVincent Abriou 	}
2609e1f05b2SVincent Abriou 
2612388693eSThierry Reding 	drm_crtc_handle_vblank(crtc);
2629e1f05b2SVincent Abriou 
2632388693eSThierry Reding 	if (mixer->status == STI_MIXER_DISABLING) {
26429d1dc62SVincent Abriou 		struct drm_plane *p;
26529d1dc62SVincent Abriou 
26629d1dc62SVincent Abriou 		/* Disable mixer only if all overlay planes (GDP and VDP)
26729d1dc62SVincent Abriou 		 * are disabled */
2682388693eSThierry Reding 		list_for_each_entry(p, &crtc->dev->mode_config.plane_list,
2692388693eSThierry Reding 				    head) {
27029d1dc62SVincent Abriou 			struct sti_plane *plane = to_sti_plane(p);
27129d1dc62SVincent Abriou 
27229d1dc62SVincent Abriou 			if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
27329d1dc62SVincent Abriou 				if (plane->status != STI_PLANE_DISABLED)
27429d1dc62SVincent Abriou 					return 0;
27529d1dc62SVincent Abriou 		}
2762388693eSThierry Reding 		sti_crtc_disable(crtc);
27729d1dc62SVincent Abriou 	}
27829d1dc62SVincent Abriou 
2799e1f05b2SVincent Abriou 	return 0;
2809e1f05b2SVincent Abriou }
2819e1f05b2SVincent Abriou 
28287b09c62SThomas Zimmermann static int sti_crtc_enable_vblank(struct drm_crtc *crtc)
2839e1f05b2SVincent Abriou {
28487b09c62SThomas Zimmermann 	struct drm_device *dev = crtc->dev;
28587b09c62SThomas Zimmermann 	unsigned int pipe = crtc->index;
2869e1f05b2SVincent Abriou 	struct sti_private *dev_priv = dev->dev_private;
2879e1f05b2SVincent Abriou 	struct sti_compositor *compo = dev_priv->compo;
288ae217850SFabien Dessenne 	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
289ffdbb82cSFabien Dessenne 	struct sti_vtg *vtg = compo->vtg[pipe];
2909e1f05b2SVincent Abriou 
2919e1f05b2SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
2929e1f05b2SVincent Abriou 
293ffdbb82cSFabien Dessenne 	if (sti_vtg_register_client(vtg, vtg_vblank_nb, crtc)) {
2949e1f05b2SVincent Abriou 		DRM_ERROR("Cannot register VTG notifier\n");
2959e1f05b2SVincent Abriou 		return -EINVAL;
2969e1f05b2SVincent Abriou 	}
2979e1f05b2SVincent Abriou 
2989e1f05b2SVincent Abriou 	return 0;
2999e1f05b2SVincent Abriou }
3009e1f05b2SVincent Abriou 
30187b09c62SThomas Zimmermann static void sti_crtc_disable_vblank(struct drm_crtc *crtc)
3029e1f05b2SVincent Abriou {
30387b09c62SThomas Zimmermann 	struct drm_device *drm_dev = crtc->dev;
30487b09c62SThomas Zimmermann 	unsigned int pipe = crtc->index;
30529d1dc62SVincent Abriou 	struct sti_private *priv = drm_dev->dev_private;
3069e1f05b2SVincent Abriou 	struct sti_compositor *compo = priv->compo;
307ae217850SFabien Dessenne 	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
308ffdbb82cSFabien Dessenne 	struct sti_vtg *vtg = compo->vtg[pipe];
3099e1f05b2SVincent Abriou 
3109e1f05b2SVincent Abriou 	DRM_DEBUG_DRIVER("\n");
3119e1f05b2SVincent Abriou 
312ffdbb82cSFabien Dessenne 	if (sti_vtg_unregister_client(vtg, vtg_vblank_nb))
3139e1f05b2SVincent Abriou 		DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
3149e1f05b2SVincent Abriou }
3159e1f05b2SVincent Abriou 
31683af0a48SBenjamin Gaignard static int sti_crtc_late_register(struct drm_crtc *crtc)
31783af0a48SBenjamin Gaignard {
31883af0a48SBenjamin Gaignard 	struct sti_mixer *mixer = to_sti_mixer(crtc);
31983af0a48SBenjamin Gaignard 	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
32083af0a48SBenjamin Gaignard 
32183af0a48SBenjamin Gaignard 	if (drm_crtc_index(crtc) == 0)
32254ac836bSWambui Karuga 		sti_compositor_debugfs_init(compo, crtc->dev->primary);
32383af0a48SBenjamin Gaignard 
32483af0a48SBenjamin Gaignard 	return 0;
32583af0a48SBenjamin Gaignard }
32683af0a48SBenjamin Gaignard 
327c5de4853SVille Syrjälä static const struct drm_crtc_funcs sti_crtc_funcs = {
3289e1f05b2SVincent Abriou 	.set_config = drm_atomic_helper_set_config,
3299e1f05b2SVincent Abriou 	.page_flip = drm_atomic_helper_page_flip,
3309e1f05b2SVincent Abriou 	.destroy = sti_crtc_destroy,
3319e1f05b2SVincent Abriou 	.set_property = sti_crtc_set_property,
3329e1f05b2SVincent Abriou 	.reset = drm_atomic_helper_crtc_reset,
3339e1f05b2SVincent Abriou 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
3349e1f05b2SVincent Abriou 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
33583af0a48SBenjamin Gaignard 	.late_register = sti_crtc_late_register,
33687b09c62SThomas Zimmermann 	.enable_vblank = sti_crtc_enable_vblank,
33787b09c62SThomas Zimmermann 	.disable_vblank = sti_crtc_disable_vblank,
3389e1f05b2SVincent Abriou };
3399e1f05b2SVincent Abriou 
3409e1f05b2SVincent Abriou bool sti_crtc_is_main(struct drm_crtc *crtc)
3419e1f05b2SVincent Abriou {
3429e1f05b2SVincent Abriou 	struct sti_mixer *mixer = to_sti_mixer(crtc);
3439e1f05b2SVincent Abriou 
3449e1f05b2SVincent Abriou 	if (mixer->id == STI_MIXER_MAIN)
3459e1f05b2SVincent Abriou 		return true;
3469e1f05b2SVincent Abriou 
3479e1f05b2SVincent Abriou 	return false;
3489e1f05b2SVincent Abriou }
3499e1f05b2SVincent Abriou 
3509e1f05b2SVincent Abriou int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
3519e1f05b2SVincent Abriou 		  struct drm_plane *primary, struct drm_plane *cursor)
3529e1f05b2SVincent Abriou {
3539e1f05b2SVincent Abriou 	struct drm_crtc *crtc = &mixer->drm_crtc;
3549e1f05b2SVincent Abriou 	int res;
3559e1f05b2SVincent Abriou 
3569e1f05b2SVincent Abriou 	res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
357f9882876SVille Syrjälä 					&sti_crtc_funcs, NULL);
3589e1f05b2SVincent Abriou 	if (res) {
359304f72e5SColin Ian King 		DRM_ERROR("Can't initialize CRTC\n");
3609e1f05b2SVincent Abriou 		return -EINVAL;
3619e1f05b2SVincent Abriou 	}
3629e1f05b2SVincent Abriou 
3639e1f05b2SVincent Abriou 	drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs);
3649e1f05b2SVincent Abriou 
3659e1f05b2SVincent Abriou 	DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n",
3669e1f05b2SVincent Abriou 			 crtc->base.id, sti_mixer_to_str(mixer));
3679e1f05b2SVincent Abriou 
3689e1f05b2SVincent Abriou 	return 0;
3699e1f05b2SVincent Abriou }
370