xref: /linux/drivers/gpu/drm/drm_simple_kms_helper.c (revision 59abba48c4299481053411f6a4de5df67b2c998f)
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>
12*59abba48SPhilipp 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  *
59*59abba48SPhilipp Zabel  * Note: consider using drmm_simple_encoder_alloc() instead of
60*59abba48SPhilipp Zabel  * drm_simple_encoder_init() to let the DRM managed resource infrastructure
61*59abba48SPhilipp 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 
76*59abba48SPhilipp Zabel void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
77*59abba48SPhilipp Zabel 				  size_t offset, int encoder_type)
78*59abba48SPhilipp Zabel {
79*59abba48SPhilipp Zabel 	return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type,
80*59abba48SPhilipp Zabel 				    NULL);
81*59abba48SPhilipp Zabel }
82*59abba48SPhilipp Zabel EXPORT_SYMBOL(__drmm_simple_encoder_alloc);
83*59abba48SPhilipp 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,
1805b809074SNoralf Trønnes 					struct drm_plane_state *plane_state)
1815b809074SNoralf Trønnes {
1825b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1835b809074SNoralf Trønnes 	struct drm_crtc_state *crtc_state;
1845b809074SNoralf Trønnes 	int ret;
1855b809074SNoralf Trønnes 
1865b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
187b4d93679SMaarten Lankhorst 	crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
1885b809074SNoralf Trønnes 						   &pipe->crtc);
1894be12cc2SVille Syrjälä 
190a01cb8baSVille Syrjälä 	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
1915b809074SNoralf Trønnes 						  DRM_PLANE_HELPER_NO_SCALING,
1925b809074SNoralf Trønnes 						  DRM_PLANE_HELPER_NO_SCALING,
1934be12cc2SVille Syrjälä 						  false, true);
1945b809074SNoralf Trønnes 	if (ret)
1955b809074SNoralf Trønnes 		return ret;
1965b809074SNoralf Trønnes 
1974be12cc2SVille Syrjälä 	if (!plane_state->visible)
1984751cf73SOleksandr Andrushchenko 		return 0;
1994751cf73SOleksandr Andrushchenko 
2005b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->check)
2015b809074SNoralf Trønnes 		return 0;
2025b809074SNoralf Trønnes 
2035b809074SNoralf Trønnes 	return pipe->funcs->check(pipe, plane_state, crtc_state);
2045b809074SNoralf Trønnes }
2055b809074SNoralf Trønnes 
2065b809074SNoralf Trønnes static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
207bcd2ba02SEric Anholt 					struct drm_plane_state *old_pstate)
2085b809074SNoralf Trønnes {
2095b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
2105b809074SNoralf Trønnes 
2115b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2125b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->update)
2135b809074SNoralf Trønnes 		return;
2145b809074SNoralf Trønnes 
215bcd2ba02SEric Anholt 	pipe->funcs->update(pipe, old_pstate);
2165b809074SNoralf Trønnes }
2175b809074SNoralf Trønnes 
2187d83a155SMarek Vasut static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
2197d83a155SMarek Vasut 					   struct drm_plane_state *state)
2207d83a155SMarek Vasut {
2217d83a155SMarek Vasut 	struct drm_simple_display_pipe *pipe;
2227d83a155SMarek Vasut 
2237d83a155SMarek Vasut 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2247d83a155SMarek Vasut 	if (!pipe->funcs || !pipe->funcs->prepare_fb)
2257d83a155SMarek Vasut 		return 0;
2267d83a155SMarek Vasut 
2277d83a155SMarek Vasut 	return pipe->funcs->prepare_fb(pipe, state);
2287d83a155SMarek Vasut }
2297d83a155SMarek Vasut 
2307d83a155SMarek Vasut static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
2317d83a155SMarek Vasut 					    struct drm_plane_state *state)
2327d83a155SMarek Vasut {
2337d83a155SMarek Vasut 	struct drm_simple_display_pipe *pipe;
2347d83a155SMarek Vasut 
2357d83a155SMarek Vasut 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2367d83a155SMarek Vasut 	if (!pipe->funcs || !pipe->funcs->cleanup_fb)
2377d83a155SMarek Vasut 		return;
2387d83a155SMarek Vasut 
2397d83a155SMarek Vasut 	pipe->funcs->cleanup_fb(pipe, state);
2407d83a155SMarek Vasut }
2417d83a155SMarek Vasut 
242dff906c3SEric Anholt static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
243dff906c3SEric Anholt 						uint32_t format,
244dff906c3SEric Anholt 						uint64_t modifier)
245dff906c3SEric Anholt {
246dff906c3SEric Anholt 	return modifier == DRM_FORMAT_MOD_LINEAR;
247dff906c3SEric Anholt }
248dff906c3SEric Anholt 
2495b809074SNoralf Trønnes static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
2507d83a155SMarek Vasut 	.prepare_fb = drm_simple_kms_plane_prepare_fb,
2517d83a155SMarek Vasut 	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
2525b809074SNoralf Trønnes 	.atomic_check = drm_simple_kms_plane_atomic_check,
2535b809074SNoralf Trønnes 	.atomic_update = drm_simple_kms_plane_atomic_update,
2545b809074SNoralf Trønnes };
2555b809074SNoralf Trønnes 
2565b809074SNoralf Trønnes static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
2575b809074SNoralf Trønnes 	.update_plane		= drm_atomic_helper_update_plane,
2585b809074SNoralf Trønnes 	.disable_plane		= drm_atomic_helper_disable_plane,
2595b809074SNoralf Trønnes 	.destroy		= drm_plane_cleanup,
2605b809074SNoralf Trønnes 	.reset			= drm_atomic_helper_plane_reset,
2615b809074SNoralf Trønnes 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
2625b809074SNoralf Trønnes 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
263dff906c3SEric Anholt 	.format_mod_supported   = drm_simple_kms_format_mod_supported,
2645b809074SNoralf Trønnes };
2655b809074SNoralf Trønnes 
2665b809074SNoralf Trønnes /**
267315486c6SAndrea Merello  * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
268315486c6SAndrea Merello  * @pipe: simple display pipe object
269315486c6SAndrea Merello  * @bridge: bridge to attach
270315486c6SAndrea Merello  *
271315486c6SAndrea Merello  * Makes it possible to still use the drm_simple_display_pipe helpers when
272315486c6SAndrea Merello  * a DRM bridge has to be used.
273315486c6SAndrea Merello  *
274315486c6SAndrea Merello  * Note that you probably want to initialize the pipe by passing a NULL
275315486c6SAndrea Merello  * connector to drm_simple_display_pipe_init().
276315486c6SAndrea Merello  *
277315486c6SAndrea Merello  * Returns:
278315486c6SAndrea Merello  * Zero on success, negative error code on failure.
279315486c6SAndrea Merello  */
280315486c6SAndrea Merello int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
281315486c6SAndrea Merello 					  struct drm_bridge *bridge)
282315486c6SAndrea Merello {
283a25b988fSLaurent Pinchart 	return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0);
284315486c6SAndrea Merello }
285315486c6SAndrea Merello EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
286315486c6SAndrea Merello 
287315486c6SAndrea Merello /**
2885b809074SNoralf Trønnes  * drm_simple_display_pipe_init - Initialize a simple display pipeline
2895b809074SNoralf Trønnes  * @dev: DRM device
2905b809074SNoralf Trønnes  * @pipe: simple display pipe object to initialize
2915b809074SNoralf Trønnes  * @funcs: callbacks for the display pipe (optional)
29262cacc79SDaniel Vetter  * @formats: array of supported formats (DRM_FORMAT\_\*)
2935b809074SNoralf Trønnes  * @format_count: number of elements in @formats
294e6fc3b68SBen Widawsky  * @format_modifiers: array of formats modifiers
2954f993973SAndrea Merello  * @connector: connector to attach and register (optional)
2965b809074SNoralf Trønnes  *
2975b809074SNoralf Trønnes  * Sets up a display pipeline which consist of a really simple
2984f993973SAndrea Merello  * plane-crtc-encoder pipe.
2994f993973SAndrea Merello  *
3004f993973SAndrea Merello  * If a connector is supplied, the pipe will be coupled with the provided
3014f993973SAndrea Merello  * connector. You may supply a NULL connector when using drm bridges, that
3024f993973SAndrea Merello  * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
3034f993973SAndrea Merello  *
3045b809074SNoralf Trønnes  * Teardown of a simple display pipe is all handled automatically by the drm
3055b809074SNoralf Trønnes  * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
3065b809074SNoralf Trønnes  * release the memory for the structure themselves.
3075b809074SNoralf Trønnes  *
3085b809074SNoralf Trønnes  * Returns:
3095b809074SNoralf Trønnes  * Zero on success, negative error code on failure.
3105b809074SNoralf Trønnes  */
3115b809074SNoralf Trønnes int drm_simple_display_pipe_init(struct drm_device *dev,
3125b809074SNoralf Trønnes 			struct drm_simple_display_pipe *pipe,
3135b809074SNoralf Trønnes 			const struct drm_simple_display_pipe_funcs *funcs,
3145b809074SNoralf Trønnes 			const uint32_t *formats, unsigned int format_count,
315e6fc3b68SBen Widawsky 			const uint64_t *format_modifiers,
3165b809074SNoralf Trønnes 			struct drm_connector *connector)
3175b809074SNoralf Trønnes {
3185b809074SNoralf Trønnes 	struct drm_encoder *encoder = &pipe->encoder;
3195b809074SNoralf Trønnes 	struct drm_plane *plane = &pipe->plane;
3205b809074SNoralf Trønnes 	struct drm_crtc *crtc = &pipe->crtc;
3215b809074SNoralf Trønnes 	int ret;
3225b809074SNoralf Trønnes 
3235b809074SNoralf Trønnes 	pipe->connector = connector;
3245b809074SNoralf Trønnes 	pipe->funcs = funcs;
3255b809074SNoralf Trønnes 
3265b809074SNoralf Trønnes 	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
3275b809074SNoralf Trønnes 	ret = drm_universal_plane_init(dev, plane, 0,
3285b809074SNoralf Trønnes 				       &drm_simple_kms_plane_funcs,
3295b809074SNoralf Trønnes 				       formats, format_count,
330e6fc3b68SBen Widawsky 				       format_modifiers,
3315b809074SNoralf Trønnes 				       DRM_PLANE_TYPE_PRIMARY, NULL);
3325b809074SNoralf Trønnes 	if (ret)
3335b809074SNoralf Trønnes 		return ret;
3345b809074SNoralf Trønnes 
3355b809074SNoralf Trønnes 	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
3365b809074SNoralf Trønnes 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
3375b809074SNoralf Trønnes 					&drm_simple_kms_crtc_funcs, NULL);
3385b809074SNoralf Trønnes 	if (ret)
3395b809074SNoralf Trønnes 		return ret;
3405b809074SNoralf Trønnes 
3416a52193bSVille Syrjälä 	encoder->possible_crtcs = drm_crtc_mask(crtc);
34263170ac6SThomas Zimmermann 	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
3434f993973SAndrea Merello 	if (ret || !connector)
3445b809074SNoralf Trønnes 		return ret;
3455b809074SNoralf Trønnes 
346cde4c44dSDaniel Vetter 	return drm_connector_attach_encoder(connector, encoder);
3475b809074SNoralf Trønnes }
3485b809074SNoralf Trønnes EXPORT_SYMBOL(drm_simple_display_pipe_init);
3495b809074SNoralf Trønnes 
3505b809074SNoralf Trønnes MODULE_LICENSE("GPL");
351