162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) STMicroelectronics SA 2014
462306a36Sopenharmony_ci * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
562306a36Sopenharmony_ci *          Fabien Dessenne <fabien.dessenne@st.com>
662306a36Sopenharmony_ci *          for STMicroelectronics.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <drm/drm_atomic.h>
1262306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h>
1362306a36Sopenharmony_ci#include <drm/drm_device.h>
1462306a36Sopenharmony_ci#include <drm/drm_print.h>
1562306a36Sopenharmony_ci#include <drm/drm_probe_helper.h>
1662306a36Sopenharmony_ci#include <drm/drm_vblank.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "sti_compositor.h"
1962306a36Sopenharmony_ci#include "sti_crtc.h"
2062306a36Sopenharmony_ci#include "sti_drv.h"
2162306a36Sopenharmony_ci#include "sti_vid.h"
2262306a36Sopenharmony_ci#include "sti_vtg.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic void sti_crtc_atomic_enable(struct drm_crtc *crtc,
2562306a36Sopenharmony_ci				   struct drm_atomic_state *state)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct sti_mixer *mixer = to_sti_mixer(crtc);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	mixer->status = STI_MIXER_READY;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	drm_crtc_vblank_on(crtc);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic void sti_crtc_atomic_disable(struct drm_crtc *crtc,
3762306a36Sopenharmony_ci				    struct drm_atomic_state *state)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	struct sti_mixer *mixer = to_sti_mixer(crtc);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	mixer->status = STI_MIXER_DISABLING;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	drm_crtc_wait_one_vblank(crtc);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic int
4962306a36Sopenharmony_cisti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct sti_mixer *mixer = to_sti_mixer(crtc);
5262306a36Sopenharmony_ci	struct device *dev = mixer->dev;
5362306a36Sopenharmony_ci	struct sti_compositor *compo = dev_get_drvdata(dev);
5462306a36Sopenharmony_ci	struct clk *compo_clk, *pix_clk;
5562306a36Sopenharmony_ci	int rate = mode->clock * 1000;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	DRM_DEBUG_KMS("CRTC:%d (%s) mode: (%s)\n",
5862306a36Sopenharmony_ci		      crtc->base.id, sti_mixer_to_str(mixer), mode->name);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	DRM_DEBUG_KMS(DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (mixer->id == STI_MIXER_MAIN) {
6362306a36Sopenharmony_ci		compo_clk = compo->clk_compo_main;
6462306a36Sopenharmony_ci		pix_clk = compo->clk_pix_main;
6562306a36Sopenharmony_ci	} else {
6662306a36Sopenharmony_ci		compo_clk = compo->clk_compo_aux;
6762306a36Sopenharmony_ci		pix_clk = compo->clk_pix_aux;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* Prepare and enable the compo IP clock */
7162306a36Sopenharmony_ci	if (clk_prepare_enable(compo_clk)) {
7262306a36Sopenharmony_ci		DRM_INFO("Failed to prepare/enable compositor clk\n");
7362306a36Sopenharmony_ci		goto compo_error;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* Set rate and prepare/enable pixel clock */
7762306a36Sopenharmony_ci	if (clk_set_rate(pix_clk, rate) < 0) {
7862306a36Sopenharmony_ci		DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate);
7962306a36Sopenharmony_ci		goto pix_error;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci	if (clk_prepare_enable(pix_clk)) {
8262306a36Sopenharmony_ci		DRM_ERROR("Failed to prepare/enable pix clk\n");
8362306a36Sopenharmony_ci		goto pix_error;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	sti_vtg_set_config(compo->vtg[mixer->id], &crtc->mode);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (sti_mixer_active_video_area(mixer, &crtc->mode)) {
8962306a36Sopenharmony_ci		DRM_ERROR("Can't set active video area\n");
9062306a36Sopenharmony_ci		goto mixer_error;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return 0;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cimixer_error:
9662306a36Sopenharmony_ci	clk_disable_unprepare(pix_clk);
9762306a36Sopenharmony_cipix_error:
9862306a36Sopenharmony_ci	clk_disable_unprepare(compo_clk);
9962306a36Sopenharmony_cicompo_error:
10062306a36Sopenharmony_ci	return -EINVAL;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic void sti_crtc_disable(struct drm_crtc *crtc)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct sti_mixer *mixer = to_sti_mixer(crtc);
10662306a36Sopenharmony_ci	struct device *dev = mixer->dev;
10762306a36Sopenharmony_ci	struct sti_compositor *compo = dev_get_drvdata(dev);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* Disable Background */
11262306a36Sopenharmony_ci	sti_mixer_set_background_status(mixer, false);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	drm_crtc_vblank_off(crtc);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Disable pixel clock and compo IP clocks */
11762306a36Sopenharmony_ci	if (mixer->id == STI_MIXER_MAIN) {
11862306a36Sopenharmony_ci		clk_disable_unprepare(compo->clk_pix_main);
11962306a36Sopenharmony_ci		clk_disable_unprepare(compo->clk_compo_main);
12062306a36Sopenharmony_ci	} else {
12162306a36Sopenharmony_ci		clk_disable_unprepare(compo->clk_pix_aux);
12262306a36Sopenharmony_ci		clk_disable_unprepare(compo->clk_compo_aux);
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	mixer->status = STI_MIXER_DISABLED;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic void
12962306a36Sopenharmony_cisti_crtc_mode_set_nofb(struct drm_crtc *crtc)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void sti_crtc_atomic_flush(struct drm_crtc *crtc,
13562306a36Sopenharmony_ci				  struct drm_atomic_state *state)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct drm_device *drm_dev = crtc->dev;
13862306a36Sopenharmony_ci	struct sti_mixer *mixer = to_sti_mixer(crtc);
13962306a36Sopenharmony_ci	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
14062306a36Sopenharmony_ci	struct drm_plane *p;
14162306a36Sopenharmony_ci	struct drm_pending_vblank_event *event;
14262306a36Sopenharmony_ci	unsigned long flags;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* perform plane actions */
14762306a36Sopenharmony_ci	list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
14862306a36Sopenharmony_ci		struct sti_plane *plane = to_sti_plane(p);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci		switch (plane->status) {
15162306a36Sopenharmony_ci		case STI_PLANE_UPDATED:
15262306a36Sopenharmony_ci			/* ignore update for other CRTC */
15362306a36Sopenharmony_ci			if (p->state->crtc != crtc)
15462306a36Sopenharmony_ci				continue;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci			/* update planes tag as updated */
15762306a36Sopenharmony_ci			DRM_DEBUG_DRIVER("update plane %s\n",
15862306a36Sopenharmony_ci					 sti_plane_to_str(plane));
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci			if (sti_mixer_set_plane_depth(mixer, plane)) {
16162306a36Sopenharmony_ci				DRM_ERROR("Cannot set plane %s depth\n",
16262306a36Sopenharmony_ci					  sti_plane_to_str(plane));
16362306a36Sopenharmony_ci				break;
16462306a36Sopenharmony_ci			}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci			if (sti_mixer_set_plane_status(mixer, plane, true)) {
16762306a36Sopenharmony_ci				DRM_ERROR("Cannot enable plane %s at mixer\n",
16862306a36Sopenharmony_ci					  sti_plane_to_str(plane));
16962306a36Sopenharmony_ci				break;
17062306a36Sopenharmony_ci			}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci			/* if plane is HQVDP_0 then commit the vid[0] */
17362306a36Sopenharmony_ci			if (plane->desc == STI_HQVDP_0)
17462306a36Sopenharmony_ci				sti_vid_commit(compo->vid[0], p->state);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci			plane->status = STI_PLANE_READY;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci			break;
17962306a36Sopenharmony_ci		case STI_PLANE_DISABLING:
18062306a36Sopenharmony_ci			/* disabling sequence for planes tag as disabling */
18162306a36Sopenharmony_ci			DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
18262306a36Sopenharmony_ci					 sti_plane_to_str(plane));
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci			if (sti_mixer_set_plane_status(mixer, plane, false)) {
18562306a36Sopenharmony_ci				DRM_ERROR("Cannot disable plane %s at mixer\n",
18662306a36Sopenharmony_ci					  sti_plane_to_str(plane));
18762306a36Sopenharmony_ci				continue;
18862306a36Sopenharmony_ci			}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci			if (plane->desc == STI_CURSOR)
19162306a36Sopenharmony_ci				/* tag plane status for disabled */
19262306a36Sopenharmony_ci				plane->status = STI_PLANE_DISABLED;
19362306a36Sopenharmony_ci			else
19462306a36Sopenharmony_ci				/* tag plane status for flushing */
19562306a36Sopenharmony_ci				plane->status = STI_PLANE_FLUSHING;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci			/* if plane is HQVDP_0 then disable the vid[0] */
19862306a36Sopenharmony_ci			if (plane->desc == STI_HQVDP_0)
19962306a36Sopenharmony_ci				sti_vid_disable(compo->vid[0]);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci			break;
20262306a36Sopenharmony_ci		default:
20362306a36Sopenharmony_ci			/* Other status case are not handled */
20462306a36Sopenharmony_ci			break;
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	event = crtc->state->event;
20962306a36Sopenharmony_ci	if (event) {
21062306a36Sopenharmony_ci		crtc->state->event = NULL;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		spin_lock_irqsave(&crtc->dev->event_lock, flags);
21362306a36Sopenharmony_ci		if (drm_crtc_vblank_get(crtc) == 0)
21462306a36Sopenharmony_ci			drm_crtc_arm_vblank_event(crtc, event);
21562306a36Sopenharmony_ci		else
21662306a36Sopenharmony_ci			drm_crtc_send_vblank_event(crtc, event);
21762306a36Sopenharmony_ci		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
22262306a36Sopenharmony_ci	.mode_set_nofb = sti_crtc_mode_set_nofb,
22362306a36Sopenharmony_ci	.atomic_flush = sti_crtc_atomic_flush,
22462306a36Sopenharmony_ci	.atomic_enable = sti_crtc_atomic_enable,
22562306a36Sopenharmony_ci	.atomic_disable = sti_crtc_atomic_disable,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic void sti_crtc_destroy(struct drm_crtc *crtc)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	DRM_DEBUG_KMS("\n");
23162306a36Sopenharmony_ci	drm_crtc_cleanup(crtc);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic int sti_crtc_set_property(struct drm_crtc *crtc,
23562306a36Sopenharmony_ci				 struct drm_property *property,
23662306a36Sopenharmony_ci				 uint64_t val)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	DRM_DEBUG_KMS("\n");
23962306a36Sopenharmony_ci	return 0;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ciint sti_crtc_vblank_cb(struct notifier_block *nb,
24362306a36Sopenharmony_ci		       unsigned long event, void *data)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	struct sti_compositor *compo;
24662306a36Sopenharmony_ci	struct drm_crtc *crtc = data;
24762306a36Sopenharmony_ci	struct sti_mixer *mixer;
24862306a36Sopenharmony_ci	unsigned int pipe;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	pipe = drm_crtc_index(crtc);
25162306a36Sopenharmony_ci	compo = container_of(nb, struct sti_compositor, vtg_vblank_nb[pipe]);
25262306a36Sopenharmony_ci	mixer = compo->mixer[pipe];
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if ((event != VTG_TOP_FIELD_EVENT) &&
25562306a36Sopenharmony_ci	    (event != VTG_BOTTOM_FIELD_EVENT)) {
25662306a36Sopenharmony_ci		DRM_ERROR("unknown event: %lu\n", event);
25762306a36Sopenharmony_ci		return -EINVAL;
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	drm_crtc_handle_vblank(crtc);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (mixer->status == STI_MIXER_DISABLING) {
26362306a36Sopenharmony_ci		struct drm_plane *p;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		/* Disable mixer only if all overlay planes (GDP and VDP)
26662306a36Sopenharmony_ci		 * are disabled */
26762306a36Sopenharmony_ci		list_for_each_entry(p, &crtc->dev->mode_config.plane_list,
26862306a36Sopenharmony_ci				    head) {
26962306a36Sopenharmony_ci			struct sti_plane *plane = to_sti_plane(p);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci			if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
27262306a36Sopenharmony_ci				if (plane->status != STI_PLANE_DISABLED)
27362306a36Sopenharmony_ci					return 0;
27462306a36Sopenharmony_ci		}
27562306a36Sopenharmony_ci		sti_crtc_disable(crtc);
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic int sti_crtc_enable_vblank(struct drm_crtc *crtc)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
28462306a36Sopenharmony_ci	unsigned int pipe = crtc->index;
28562306a36Sopenharmony_ci	struct sti_private *dev_priv = dev->dev_private;
28662306a36Sopenharmony_ci	struct sti_compositor *compo = dev_priv->compo;
28762306a36Sopenharmony_ci	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
28862306a36Sopenharmony_ci	struct sti_vtg *vtg = compo->vtg[pipe];
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (sti_vtg_register_client(vtg, vtg_vblank_nb, crtc)) {
29362306a36Sopenharmony_ci		DRM_ERROR("Cannot register VTG notifier\n");
29462306a36Sopenharmony_ci		return -EINVAL;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic void sti_crtc_disable_vblank(struct drm_crtc *crtc)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct drm_device *drm_dev = crtc->dev;
30362306a36Sopenharmony_ci	unsigned int pipe = crtc->index;
30462306a36Sopenharmony_ci	struct sti_private *priv = drm_dev->dev_private;
30562306a36Sopenharmony_ci	struct sti_compositor *compo = priv->compo;
30662306a36Sopenharmony_ci	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
30762306a36Sopenharmony_ci	struct sti_vtg *vtg = compo->vtg[pipe];
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (sti_vtg_unregister_client(vtg, vtg_vblank_nb))
31262306a36Sopenharmony_ci		DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int sti_crtc_late_register(struct drm_crtc *crtc)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct sti_mixer *mixer = to_sti_mixer(crtc);
31862306a36Sopenharmony_ci	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (drm_crtc_index(crtc) == 0)
32162306a36Sopenharmony_ci		sti_compositor_debugfs_init(compo, crtc->dev->primary);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return 0;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic const struct drm_crtc_funcs sti_crtc_funcs = {
32762306a36Sopenharmony_ci	.set_config = drm_atomic_helper_set_config,
32862306a36Sopenharmony_ci	.page_flip = drm_atomic_helper_page_flip,
32962306a36Sopenharmony_ci	.destroy = sti_crtc_destroy,
33062306a36Sopenharmony_ci	.set_property = sti_crtc_set_property,
33162306a36Sopenharmony_ci	.reset = drm_atomic_helper_crtc_reset,
33262306a36Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
33362306a36Sopenharmony_ci	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
33462306a36Sopenharmony_ci	.late_register = sti_crtc_late_register,
33562306a36Sopenharmony_ci	.enable_vblank = sti_crtc_enable_vblank,
33662306a36Sopenharmony_ci	.disable_vblank = sti_crtc_disable_vblank,
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cibool sti_crtc_is_main(struct drm_crtc *crtc)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct sti_mixer *mixer = to_sti_mixer(crtc);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (mixer->id == STI_MIXER_MAIN)
34462306a36Sopenharmony_ci		return true;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return false;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ciint sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
35062306a36Sopenharmony_ci		  struct drm_plane *primary, struct drm_plane *cursor)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct drm_crtc *crtc = &mixer->drm_crtc;
35362306a36Sopenharmony_ci	int res;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
35662306a36Sopenharmony_ci					&sti_crtc_funcs, NULL);
35762306a36Sopenharmony_ci	if (res) {
35862306a36Sopenharmony_ci		DRM_ERROR("Can't initialize CRTC\n");
35962306a36Sopenharmony_ci		return -EINVAL;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n",
36562306a36Sopenharmony_ci			 crtc->base.id, sti_mixer_to_str(mixer));
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return 0;
36862306a36Sopenharmony_ci}
369