xref: /linux/drivers/gpu/drm/drm_simple_kms_helper.c (revision 977697e20b3d758786b67edc33941e5c410ffe4d)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
25b809074SNoralf Trønnes /*
35b809074SNoralf Trønnes  * Copyright (C) 2016 Noralf Trønnes
45b809074SNoralf Trønnes  */
55b809074SNoralf Trønnes 
60500c04eSSam Ravnborg #include <linux/module.h>
70500c04eSSam Ravnborg #include <linux/slab.h>
80500c04eSSam Ravnborg 
95b809074SNoralf Trønnes #include <drm/drm_atomic.h>
105b809074SNoralf Trønnes #include <drm/drm_atomic_helper.h>
11ee68c743SBoris Brezillon #include <drm/drm_bridge.h>
1259abba48SPhilipp Zabel #include <drm/drm_managed.h>
135b809074SNoralf Trønnes #include <drm/drm_plane_helper.h>
14fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
155b809074SNoralf Trønnes #include <drm/drm_simple_kms_helper.h>
165b809074SNoralf Trønnes 
175b809074SNoralf Trønnes /**
185b809074SNoralf Trønnes  * DOC: overview
195b809074SNoralf Trønnes  *
205b809074SNoralf Trønnes  * This helper library provides helpers for drivers for simple display
215b809074SNoralf Trønnes  * hardware.
225b809074SNoralf Trønnes  *
235b809074SNoralf Trønnes  * drm_simple_display_pipe_init() initializes a simple display pipeline
245b809074SNoralf Trønnes  * which has only one full-screen scanout buffer feeding one output. The
25ea0dd85aSDaniel Vetter  * pipeline is represented by &struct drm_simple_display_pipe and binds
265b809074SNoralf Trønnes  * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed
275b809074SNoralf Trønnes  * entity. Some flexibility for code reuse is provided through a separately
285b809074SNoralf Trønnes  * allocated &drm_connector object and supporting optional &drm_bridge
295b809074SNoralf Trønnes  * encoder drivers.
3063170ac6SThomas Zimmermann  *
3163170ac6SThomas Zimmermann  * Many drivers require only a very simple encoder that fulfills the minimum
3263170ac6SThomas Zimmermann  * requirements of the display pipeline and does not add additional
3363170ac6SThomas Zimmermann  * functionality. The function drm_simple_encoder_init() provides an
3463170ac6SThomas Zimmermann  * implementation of such an encoder.
355b809074SNoralf Trønnes  */
365b809074SNoralf Trønnes 
3763170ac6SThomas Zimmermann static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
385b809074SNoralf Trønnes 	.destroy = drm_encoder_cleanup,
395b809074SNoralf Trønnes };
405b809074SNoralf Trønnes 
4163170ac6SThomas Zimmermann /**
422cb5974dSThomas Zimmermann  * drm_simple_encoder_init - Initialize a preallocated encoder with
432cb5974dSThomas Zimmermann  *                           basic functionality.
4463170ac6SThomas Zimmermann  * @dev: drm device
452cb5974dSThomas Zimmermann  * @encoder: the encoder to initialize
4663170ac6SThomas Zimmermann  * @encoder_type: user visible type of the encoder
4763170ac6SThomas Zimmermann  *
4863170ac6SThomas Zimmermann  * Initialises a preallocated encoder that has no further functionality.
4963170ac6SThomas Zimmermann  * Settings for possible CRTC and clones are left to their initial values.
5063170ac6SThomas Zimmermann  * The encoder will be cleaned up automatically as part of the mode-setting
5163170ac6SThomas Zimmermann  * cleanup.
5263170ac6SThomas Zimmermann  *
532cb5974dSThomas Zimmermann  * The caller of drm_simple_encoder_init() is responsible for freeing
542cb5974dSThomas Zimmermann  * the encoder's memory after the encoder has been cleaned up. At the
552cb5974dSThomas Zimmermann  * moment this only works reliably if the encoder data structure is
562cb5974dSThomas Zimmermann  * stored in the device structure. Free the encoder's memory as part of
572cb5974dSThomas Zimmermann  * the device release function.
582cb5974dSThomas Zimmermann  *
5959abba48SPhilipp Zabel  * Note: consider using drmm_simple_encoder_alloc() instead of
6059abba48SPhilipp Zabel  * drm_simple_encoder_init() to let the DRM managed resource infrastructure
6159abba48SPhilipp Zabel  * take care of cleanup and deallocation.
622cb5974dSThomas Zimmermann  *
6363170ac6SThomas Zimmermann  * Returns:
6463170ac6SThomas Zimmermann  * Zero on success, error code on failure.
6563170ac6SThomas Zimmermann  */
6663170ac6SThomas Zimmermann int drm_simple_encoder_init(struct drm_device *dev,
6763170ac6SThomas Zimmermann 			    struct drm_encoder *encoder,
6863170ac6SThomas Zimmermann 			    int encoder_type)
6963170ac6SThomas Zimmermann {
7063170ac6SThomas Zimmermann 	return drm_encoder_init(dev, encoder,
7163170ac6SThomas Zimmermann 				&drm_simple_encoder_funcs_cleanup,
7263170ac6SThomas Zimmermann 				encoder_type, NULL);
7363170ac6SThomas Zimmermann }
7463170ac6SThomas Zimmermann EXPORT_SYMBOL(drm_simple_encoder_init);
7563170ac6SThomas Zimmermann 
7659abba48SPhilipp Zabel void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
7759abba48SPhilipp Zabel 				  size_t offset, int encoder_type)
7859abba48SPhilipp Zabel {
7959abba48SPhilipp Zabel 	return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type,
8059abba48SPhilipp Zabel 				    NULL);
8159abba48SPhilipp Zabel }
8259abba48SPhilipp Zabel EXPORT_SYMBOL(__drmm_simple_encoder_alloc);
8359abba48SPhilipp Zabel 
8440275dc4SLinus Walleij static enum drm_mode_status
8540275dc4SLinus Walleij drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
8640275dc4SLinus Walleij 			       const struct drm_display_mode *mode)
8740275dc4SLinus Walleij {
8840275dc4SLinus Walleij 	struct drm_simple_display_pipe *pipe;
8940275dc4SLinus Walleij 
9040275dc4SLinus Walleij 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
9140275dc4SLinus Walleij 	if (!pipe->funcs || !pipe->funcs->mode_valid)
9240275dc4SLinus Walleij 		/* Anything goes */
9340275dc4SLinus Walleij 		return MODE_OK;
9440275dc4SLinus Walleij 
9562db7d1eSDaniel Vetter 	return pipe->funcs->mode_valid(pipe, mode);
9640275dc4SLinus Walleij }
9740275dc4SLinus Walleij 
986dcf0de7SDaniel Vetter static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
9929b77ad7SMaxime Ripard 				     struct drm_atomic_state *state)
1006dcf0de7SDaniel Vetter {
10129b77ad7SMaxime Ripard 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
10229b77ad7SMaxime Ripard 									  crtc);
10329b77ad7SMaxime Ripard 	bool has_primary = crtc_state->plane_mask &
10462f77ad0SVille Syrjälä 			   drm_plane_mask(crtc->primary);
105765831dcSMaarten Lankhorst 
106765831dcSMaarten Lankhorst 	/* We always want to have an active plane with an active CRTC */
10729b77ad7SMaxime Ripard 	if (has_primary != crtc_state->enable)
108765831dcSMaarten Lankhorst 		return -EINVAL;
109765831dcSMaarten Lankhorst 
110d74252bbSMaxime Ripard 	return drm_atomic_add_affected_planes(state, crtc);
1116dcf0de7SDaniel Vetter }
1126dcf0de7SDaniel Vetter 
1130b20a0f8SLaurent Pinchart static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
114351f950dSMaxime Ripard 				       struct drm_atomic_state *state)
1155b809074SNoralf Trønnes {
1160c9c7fd0SVille Syrjälä 	struct drm_plane *plane;
1175b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1185b809074SNoralf Trønnes 
1195b809074SNoralf Trønnes 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
1205b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->enable)
1215b809074SNoralf Trønnes 		return;
1225b809074SNoralf Trønnes 
1230c9c7fd0SVille Syrjälä 	plane = &pipe->plane;
1240c9c7fd0SVille Syrjälä 	pipe->funcs->enable(pipe, crtc->state, plane->state);
1255b809074SNoralf Trønnes }
1265b809074SNoralf Trønnes 
12764581714SLaurent Pinchart static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
128351f950dSMaxime Ripard 					struct drm_atomic_state *state)
1295b809074SNoralf Trønnes {
1305b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1315b809074SNoralf Trønnes 
1325b809074SNoralf Trønnes 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
1335b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->disable)
1345b809074SNoralf Trønnes 		return;
1355b809074SNoralf Trønnes 
1365b809074SNoralf Trønnes 	pipe->funcs->disable(pipe);
1375b809074SNoralf Trønnes }
1385b809074SNoralf Trønnes 
1395b809074SNoralf Trønnes static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
14040275dc4SLinus Walleij 	.mode_valid = drm_simple_kms_crtc_mode_valid,
1416dcf0de7SDaniel Vetter 	.atomic_check = drm_simple_kms_crtc_check,
1420b20a0f8SLaurent Pinchart 	.atomic_enable = drm_simple_kms_crtc_enable,
14364581714SLaurent Pinchart 	.atomic_disable = drm_simple_kms_crtc_disable,
1445b809074SNoralf Trønnes };
1455b809074SNoralf Trønnes 
146ac86cba9SOleksandr Andrushchenko static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
147ac86cba9SOleksandr Andrushchenko {
148ac86cba9SOleksandr Andrushchenko 	struct drm_simple_display_pipe *pipe;
149ac86cba9SOleksandr Andrushchenko 
150ac86cba9SOleksandr Andrushchenko 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
151ac86cba9SOleksandr Andrushchenko 	if (!pipe->funcs || !pipe->funcs->enable_vblank)
152ac86cba9SOleksandr Andrushchenko 		return 0;
153ac86cba9SOleksandr Andrushchenko 
154ac86cba9SOleksandr Andrushchenko 	return pipe->funcs->enable_vblank(pipe);
155ac86cba9SOleksandr Andrushchenko }
156ac86cba9SOleksandr Andrushchenko 
157ac86cba9SOleksandr Andrushchenko static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
158ac86cba9SOleksandr Andrushchenko {
159ac86cba9SOleksandr Andrushchenko 	struct drm_simple_display_pipe *pipe;
160ac86cba9SOleksandr Andrushchenko 
161ac86cba9SOleksandr Andrushchenko 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
162ac86cba9SOleksandr Andrushchenko 	if (!pipe->funcs || !pipe->funcs->disable_vblank)
163ac86cba9SOleksandr Andrushchenko 		return;
164ac86cba9SOleksandr Andrushchenko 
165ac86cba9SOleksandr Andrushchenko 	pipe->funcs->disable_vblank(pipe);
166ac86cba9SOleksandr Andrushchenko }
167ac86cba9SOleksandr Andrushchenko 
1685b809074SNoralf Trønnes static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
1695b809074SNoralf Trønnes 	.reset = drm_atomic_helper_crtc_reset,
1705b809074SNoralf Trønnes 	.destroy = drm_crtc_cleanup,
1715b809074SNoralf Trønnes 	.set_config = drm_atomic_helper_set_config,
1725b809074SNoralf Trønnes 	.page_flip = drm_atomic_helper_page_flip,
1735b809074SNoralf Trønnes 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
1745b809074SNoralf Trønnes 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
175ac86cba9SOleksandr Andrushchenko 	.enable_vblank = drm_simple_kms_crtc_enable_vblank,
176ac86cba9SOleksandr Andrushchenko 	.disable_vblank = drm_simple_kms_crtc_disable_vblank,
1775b809074SNoralf Trønnes };
1785b809074SNoralf Trønnes 
1795b809074SNoralf Trønnes static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
1807c11b99aSMaxime Ripard 					struct drm_atomic_state *state)
1815b809074SNoralf Trønnes {
1827c11b99aSMaxime Ripard 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
1837c11b99aSMaxime Ripard 									     plane);
1845b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1855b809074SNoralf Trønnes 	struct drm_crtc_state *crtc_state;
1865b809074SNoralf Trønnes 	int ret;
1875b809074SNoralf Trønnes 
1885b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
189dec92020SMaxime Ripard 	crtc_state = drm_atomic_get_new_crtc_state(state,
1905b809074SNoralf Trønnes 						   &pipe->crtc);
1914be12cc2SVille Syrjälä 
192a01cb8baSVille Syrjälä 	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
1935b809074SNoralf Trønnes 						  DRM_PLANE_HELPER_NO_SCALING,
1945b809074SNoralf Trønnes 						  DRM_PLANE_HELPER_NO_SCALING,
1954be12cc2SVille Syrjälä 						  false, true);
1965b809074SNoralf Trønnes 	if (ret)
1975b809074SNoralf Trønnes 		return ret;
1985b809074SNoralf Trønnes 
1994be12cc2SVille Syrjälä 	if (!plane_state->visible)
2004751cf73SOleksandr Andrushchenko 		return 0;
2014751cf73SOleksandr Andrushchenko 
2025b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->check)
2035b809074SNoralf Trønnes 		return 0;
2045b809074SNoralf Trønnes 
2055b809074SNoralf Trønnes 	return pipe->funcs->check(pipe, plane_state, crtc_state);
2065b809074SNoralf Trønnes }
2075b809074SNoralf Trønnes 
2085b809074SNoralf Trønnes static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
209*977697e2SMaxime Ripard 					struct drm_atomic_state *state)
2105b809074SNoralf Trønnes {
211*977697e2SMaxime Ripard 	struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
212*977697e2SMaxime Ripard 									    plane);
2135b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
2145b809074SNoralf Trønnes 
2155b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2165b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->update)
2175b809074SNoralf Trønnes 		return;
2185b809074SNoralf Trønnes 
219bcd2ba02SEric Anholt 	pipe->funcs->update(pipe, old_pstate);
2205b809074SNoralf Trønnes }
2215b809074SNoralf Trønnes 
2227d83a155SMarek Vasut static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
2237d83a155SMarek Vasut 					   struct drm_plane_state *state)
2247d83a155SMarek Vasut {
2257d83a155SMarek Vasut 	struct drm_simple_display_pipe *pipe;
2267d83a155SMarek Vasut 
2277d83a155SMarek Vasut 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2287d83a155SMarek Vasut 	if (!pipe->funcs || !pipe->funcs->prepare_fb)
2297d83a155SMarek Vasut 		return 0;
2307d83a155SMarek Vasut 
2317d83a155SMarek Vasut 	return pipe->funcs->prepare_fb(pipe, state);
2327d83a155SMarek Vasut }
2337d83a155SMarek Vasut 
2347d83a155SMarek Vasut static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
2357d83a155SMarek Vasut 					    struct drm_plane_state *state)
2367d83a155SMarek Vasut {
2377d83a155SMarek Vasut 	struct drm_simple_display_pipe *pipe;
2387d83a155SMarek Vasut 
2397d83a155SMarek Vasut 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2407d83a155SMarek Vasut 	if (!pipe->funcs || !pipe->funcs->cleanup_fb)
2417d83a155SMarek Vasut 		return;
2427d83a155SMarek Vasut 
2437d83a155SMarek Vasut 	pipe->funcs->cleanup_fb(pipe, state);
2447d83a155SMarek Vasut }
2457d83a155SMarek Vasut 
246dff906c3SEric Anholt static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
247dff906c3SEric Anholt 						uint32_t format,
248dff906c3SEric Anholt 						uint64_t modifier)
249dff906c3SEric Anholt {
250dff906c3SEric Anholt 	return modifier == DRM_FORMAT_MOD_LINEAR;
251dff906c3SEric Anholt }
252dff906c3SEric Anholt 
2535b809074SNoralf Trønnes static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
2547d83a155SMarek Vasut 	.prepare_fb = drm_simple_kms_plane_prepare_fb,
2557d83a155SMarek Vasut 	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
2565b809074SNoralf Trønnes 	.atomic_check = drm_simple_kms_plane_atomic_check,
2575b809074SNoralf Trønnes 	.atomic_update = drm_simple_kms_plane_atomic_update,
2585b809074SNoralf Trønnes };
2595b809074SNoralf Trønnes 
26040f302adSThomas Zimmermann static void drm_simple_kms_plane_reset(struct drm_plane *plane)
26140f302adSThomas Zimmermann {
26240f302adSThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
26340f302adSThomas Zimmermann 
26440f302adSThomas Zimmermann 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
26540f302adSThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->reset_plane)
26640f302adSThomas Zimmermann 		return drm_atomic_helper_plane_reset(plane);
26740f302adSThomas Zimmermann 
26840f302adSThomas Zimmermann 	return pipe->funcs->reset_plane(pipe);
26940f302adSThomas Zimmermann }
27040f302adSThomas Zimmermann 
27140f302adSThomas Zimmermann static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane)
27240f302adSThomas Zimmermann {
27340f302adSThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
27440f302adSThomas Zimmermann 
27540f302adSThomas Zimmermann 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
27640f302adSThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->duplicate_plane_state)
27740f302adSThomas Zimmermann 		return drm_atomic_helper_plane_duplicate_state(plane);
27840f302adSThomas Zimmermann 
27940f302adSThomas Zimmermann 	return pipe->funcs->duplicate_plane_state(pipe);
28040f302adSThomas Zimmermann }
28140f302adSThomas Zimmermann 
28240f302adSThomas Zimmermann static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane,
28340f302adSThomas Zimmermann 					       struct drm_plane_state *state)
28440f302adSThomas Zimmermann {
28540f302adSThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
28640f302adSThomas Zimmermann 
28740f302adSThomas Zimmermann 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
28840f302adSThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->destroy_plane_state)
28940f302adSThomas Zimmermann 		drm_atomic_helper_plane_destroy_state(plane, state);
29040f302adSThomas Zimmermann 	else
29140f302adSThomas Zimmermann 		pipe->funcs->destroy_plane_state(pipe, state);
29240f302adSThomas Zimmermann }
29340f302adSThomas Zimmermann 
2945b809074SNoralf Trønnes static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
2955b809074SNoralf Trønnes 	.update_plane		= drm_atomic_helper_update_plane,
2965b809074SNoralf Trønnes 	.disable_plane		= drm_atomic_helper_disable_plane,
2975b809074SNoralf Trønnes 	.destroy		= drm_plane_cleanup,
29840f302adSThomas Zimmermann 	.reset			= drm_simple_kms_plane_reset,
29940f302adSThomas Zimmermann 	.atomic_duplicate_state	= drm_simple_kms_plane_duplicate_state,
30040f302adSThomas Zimmermann 	.atomic_destroy_state	= drm_simple_kms_plane_destroy_state,
301dff906c3SEric Anholt 	.format_mod_supported   = drm_simple_kms_format_mod_supported,
3025b809074SNoralf Trønnes };
3035b809074SNoralf Trønnes 
3045b809074SNoralf Trønnes /**
305315486c6SAndrea Merello  * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
306315486c6SAndrea Merello  * @pipe: simple display pipe object
307315486c6SAndrea Merello  * @bridge: bridge to attach
308315486c6SAndrea Merello  *
309315486c6SAndrea Merello  * Makes it possible to still use the drm_simple_display_pipe helpers when
310315486c6SAndrea Merello  * a DRM bridge has to be used.
311315486c6SAndrea Merello  *
312315486c6SAndrea Merello  * Note that you probably want to initialize the pipe by passing a NULL
313315486c6SAndrea Merello  * connector to drm_simple_display_pipe_init().
314315486c6SAndrea Merello  *
315315486c6SAndrea Merello  * Returns:
316315486c6SAndrea Merello  * Zero on success, negative error code on failure.
317315486c6SAndrea Merello  */
318315486c6SAndrea Merello int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
319315486c6SAndrea Merello 					  struct drm_bridge *bridge)
320315486c6SAndrea Merello {
321a25b988fSLaurent Pinchart 	return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0);
322315486c6SAndrea Merello }
323315486c6SAndrea Merello EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
324315486c6SAndrea Merello 
325315486c6SAndrea Merello /**
3265b809074SNoralf Trønnes  * drm_simple_display_pipe_init - Initialize a simple display pipeline
3275b809074SNoralf Trønnes  * @dev: DRM device
3285b809074SNoralf Trønnes  * @pipe: simple display pipe object to initialize
3295b809074SNoralf Trønnes  * @funcs: callbacks for the display pipe (optional)
33062cacc79SDaniel Vetter  * @formats: array of supported formats (DRM_FORMAT\_\*)
3315b809074SNoralf Trønnes  * @format_count: number of elements in @formats
332e6fc3b68SBen Widawsky  * @format_modifiers: array of formats modifiers
3334f993973SAndrea Merello  * @connector: connector to attach and register (optional)
3345b809074SNoralf Trønnes  *
3355b809074SNoralf Trønnes  * Sets up a display pipeline which consist of a really simple
3364f993973SAndrea Merello  * plane-crtc-encoder pipe.
3374f993973SAndrea Merello  *
3384f993973SAndrea Merello  * If a connector is supplied, the pipe will be coupled with the provided
3394f993973SAndrea Merello  * connector. You may supply a NULL connector when using drm bridges, that
3404f993973SAndrea Merello  * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
3414f993973SAndrea Merello  *
3425b809074SNoralf Trønnes  * Teardown of a simple display pipe is all handled automatically by the drm
3435b809074SNoralf Trønnes  * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
3445b809074SNoralf Trønnes  * release the memory for the structure themselves.
3455b809074SNoralf Trønnes  *
3465b809074SNoralf Trønnes  * Returns:
3475b809074SNoralf Trønnes  * Zero on success, negative error code on failure.
3485b809074SNoralf Trønnes  */
3495b809074SNoralf Trønnes int drm_simple_display_pipe_init(struct drm_device *dev,
3505b809074SNoralf Trønnes 			struct drm_simple_display_pipe *pipe,
3515b809074SNoralf Trønnes 			const struct drm_simple_display_pipe_funcs *funcs,
3525b809074SNoralf Trønnes 			const uint32_t *formats, unsigned int format_count,
353e6fc3b68SBen Widawsky 			const uint64_t *format_modifiers,
3545b809074SNoralf Trønnes 			struct drm_connector *connector)
3555b809074SNoralf Trønnes {
3565b809074SNoralf Trønnes 	struct drm_encoder *encoder = &pipe->encoder;
3575b809074SNoralf Trønnes 	struct drm_plane *plane = &pipe->plane;
3585b809074SNoralf Trønnes 	struct drm_crtc *crtc = &pipe->crtc;
3595b809074SNoralf Trønnes 	int ret;
3605b809074SNoralf Trønnes 
3615b809074SNoralf Trønnes 	pipe->connector = connector;
3625b809074SNoralf Trønnes 	pipe->funcs = funcs;
3635b809074SNoralf Trønnes 
3645b809074SNoralf Trønnes 	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
3655b809074SNoralf Trønnes 	ret = drm_universal_plane_init(dev, plane, 0,
3665b809074SNoralf Trønnes 				       &drm_simple_kms_plane_funcs,
3675b809074SNoralf Trønnes 				       formats, format_count,
368e6fc3b68SBen Widawsky 				       format_modifiers,
3695b809074SNoralf Trønnes 				       DRM_PLANE_TYPE_PRIMARY, NULL);
3705b809074SNoralf Trønnes 	if (ret)
3715b809074SNoralf Trønnes 		return ret;
3725b809074SNoralf Trønnes 
3735b809074SNoralf Trønnes 	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
3745b809074SNoralf Trønnes 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
3755b809074SNoralf Trønnes 					&drm_simple_kms_crtc_funcs, NULL);
3765b809074SNoralf Trønnes 	if (ret)
3775b809074SNoralf Trønnes 		return ret;
3785b809074SNoralf Trønnes 
3796a52193bSVille Syrjälä 	encoder->possible_crtcs = drm_crtc_mask(crtc);
38063170ac6SThomas Zimmermann 	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
3814f993973SAndrea Merello 	if (ret || !connector)
3825b809074SNoralf Trønnes 		return ret;
3835b809074SNoralf Trønnes 
384cde4c44dSDaniel Vetter 	return drm_connector_attach_encoder(connector, encoder);
3855b809074SNoralf Trønnes }
3865b809074SNoralf Trønnes EXPORT_SYMBOL(drm_simple_display_pipe_init);
3875b809074SNoralf Trønnes 
3885b809074SNoralf Trønnes MODULE_LICENSE("GPL");
389