xref: /linux/drivers/gpu/drm/drm_simple_kms_helper.c (revision 2cb5974dcaaaaa5027defa854e2c4616eb6cb03a)
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>
125b809074SNoralf Trønnes #include <drm/drm_plane_helper.h>
13fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
145b809074SNoralf Trønnes #include <drm/drm_simple_kms_helper.h>
155b809074SNoralf Trønnes 
165b809074SNoralf Trønnes /**
175b809074SNoralf Trønnes  * DOC: overview
185b809074SNoralf Trønnes  *
195b809074SNoralf Trønnes  * This helper library provides helpers for drivers for simple display
205b809074SNoralf Trønnes  * hardware.
215b809074SNoralf Trønnes  *
225b809074SNoralf Trønnes  * drm_simple_display_pipe_init() initializes a simple display pipeline
235b809074SNoralf Trønnes  * which has only one full-screen scanout buffer feeding one output. The
24ea0dd85aSDaniel Vetter  * pipeline is represented by &struct drm_simple_display_pipe and binds
255b809074SNoralf Trønnes  * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed
265b809074SNoralf Trønnes  * entity. Some flexibility for code reuse is provided through a separately
275b809074SNoralf Trønnes  * allocated &drm_connector object and supporting optional &drm_bridge
285b809074SNoralf Trønnes  * encoder drivers.
2963170ac6SThomas Zimmermann  *
3063170ac6SThomas Zimmermann  * Many drivers require only a very simple encoder that fulfills the minimum
3163170ac6SThomas Zimmermann  * requirements of the display pipeline and does not add additional
3263170ac6SThomas Zimmermann  * functionality. The function drm_simple_encoder_init() provides an
3363170ac6SThomas Zimmermann  * implementation of such an encoder.
345b809074SNoralf Trønnes  */
355b809074SNoralf Trønnes 
3663170ac6SThomas Zimmermann static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
375b809074SNoralf Trønnes 	.destroy = drm_encoder_cleanup,
385b809074SNoralf Trønnes };
395b809074SNoralf Trønnes 
4063170ac6SThomas Zimmermann /**
41*2cb5974dSThomas Zimmermann  * drm_simple_encoder_init - Initialize a preallocated encoder with
42*2cb5974dSThomas Zimmermann  *                           basic functionality.
4363170ac6SThomas Zimmermann  * @dev: drm device
44*2cb5974dSThomas Zimmermann  * @encoder: the encoder to initialize
4563170ac6SThomas Zimmermann  * @encoder_type: user visible type of the encoder
4663170ac6SThomas Zimmermann  *
4763170ac6SThomas Zimmermann  * Initialises a preallocated encoder that has no further functionality.
4863170ac6SThomas Zimmermann  * Settings for possible CRTC and clones are left to their initial values.
4963170ac6SThomas Zimmermann  * The encoder will be cleaned up automatically as part of the mode-setting
5063170ac6SThomas Zimmermann  * cleanup.
5163170ac6SThomas Zimmermann  *
52*2cb5974dSThomas Zimmermann  * The caller of drm_simple_encoder_init() is responsible for freeing
53*2cb5974dSThomas Zimmermann  * the encoder's memory after the encoder has been cleaned up. At the
54*2cb5974dSThomas Zimmermann  * moment this only works reliably if the encoder data structure is
55*2cb5974dSThomas Zimmermann  * stored in the device structure. Free the encoder's memory as part of
56*2cb5974dSThomas Zimmermann  * the device release function.
57*2cb5974dSThomas Zimmermann  *
58*2cb5974dSThomas Zimmermann  * FIXME: Later improvements to DRM's resource management may allow for
59*2cb5974dSThomas Zimmermann  *        an automated kfree() of the encoder's memory.
60*2cb5974dSThomas Zimmermann  *
6163170ac6SThomas Zimmermann  * Returns:
6263170ac6SThomas Zimmermann  * Zero on success, error code on failure.
6363170ac6SThomas Zimmermann  */
6463170ac6SThomas Zimmermann int drm_simple_encoder_init(struct drm_device *dev,
6563170ac6SThomas Zimmermann 			    struct drm_encoder *encoder,
6663170ac6SThomas Zimmermann 			    int encoder_type)
6763170ac6SThomas Zimmermann {
6863170ac6SThomas Zimmermann 	return drm_encoder_init(dev, encoder,
6963170ac6SThomas Zimmermann 				&drm_simple_encoder_funcs_cleanup,
7063170ac6SThomas Zimmermann 				encoder_type, NULL);
7163170ac6SThomas Zimmermann }
7263170ac6SThomas Zimmermann EXPORT_SYMBOL(drm_simple_encoder_init);
7363170ac6SThomas Zimmermann 
7440275dc4SLinus Walleij static enum drm_mode_status
7540275dc4SLinus Walleij drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
7640275dc4SLinus Walleij 			       const struct drm_display_mode *mode)
7740275dc4SLinus Walleij {
7840275dc4SLinus Walleij 	struct drm_simple_display_pipe *pipe;
7940275dc4SLinus Walleij 
8040275dc4SLinus Walleij 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
8140275dc4SLinus Walleij 	if (!pipe->funcs || !pipe->funcs->mode_valid)
8240275dc4SLinus Walleij 		/* Anything goes */
8340275dc4SLinus Walleij 		return MODE_OK;
8440275dc4SLinus Walleij 
8562db7d1eSDaniel Vetter 	return pipe->funcs->mode_valid(pipe, mode);
8640275dc4SLinus Walleij }
8740275dc4SLinus Walleij 
886dcf0de7SDaniel Vetter static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
896dcf0de7SDaniel Vetter 				     struct drm_crtc_state *state)
906dcf0de7SDaniel Vetter {
91765831dcSMaarten Lankhorst 	bool has_primary = state->plane_mask &
9262f77ad0SVille Syrjälä 			   drm_plane_mask(crtc->primary);
93765831dcSMaarten Lankhorst 
94765831dcSMaarten Lankhorst 	/* We always want to have an active plane with an active CRTC */
95765831dcSMaarten Lankhorst 	if (has_primary != state->enable)
96765831dcSMaarten Lankhorst 		return -EINVAL;
97765831dcSMaarten Lankhorst 
986dcf0de7SDaniel Vetter 	return drm_atomic_add_affected_planes(state->state, crtc);
996dcf0de7SDaniel Vetter }
1006dcf0de7SDaniel Vetter 
1010b20a0f8SLaurent Pinchart static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
1020b20a0f8SLaurent Pinchart 				       struct drm_crtc_state *old_state)
1035b809074SNoralf Trønnes {
1040c9c7fd0SVille Syrjälä 	struct drm_plane *plane;
1055b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1065b809074SNoralf Trønnes 
1075b809074SNoralf Trønnes 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
1085b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->enable)
1095b809074SNoralf Trønnes 		return;
1105b809074SNoralf Trønnes 
1110c9c7fd0SVille Syrjälä 	plane = &pipe->plane;
1120c9c7fd0SVille Syrjälä 	pipe->funcs->enable(pipe, crtc->state, plane->state);
1135b809074SNoralf Trønnes }
1145b809074SNoralf Trønnes 
11564581714SLaurent Pinchart static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
11664581714SLaurent Pinchart 					struct drm_crtc_state *old_state)
1175b809074SNoralf Trønnes {
1185b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1195b809074SNoralf Trønnes 
1205b809074SNoralf Trønnes 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
1215b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->disable)
1225b809074SNoralf Trønnes 		return;
1235b809074SNoralf Trønnes 
1245b809074SNoralf Trønnes 	pipe->funcs->disable(pipe);
1255b809074SNoralf Trønnes }
1265b809074SNoralf Trønnes 
1275b809074SNoralf Trønnes static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
12840275dc4SLinus Walleij 	.mode_valid = drm_simple_kms_crtc_mode_valid,
1296dcf0de7SDaniel Vetter 	.atomic_check = drm_simple_kms_crtc_check,
1300b20a0f8SLaurent Pinchart 	.atomic_enable = drm_simple_kms_crtc_enable,
13164581714SLaurent Pinchart 	.atomic_disable = drm_simple_kms_crtc_disable,
1325b809074SNoralf Trønnes };
1335b809074SNoralf Trønnes 
134ac86cba9SOleksandr Andrushchenko static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
135ac86cba9SOleksandr Andrushchenko {
136ac86cba9SOleksandr Andrushchenko 	struct drm_simple_display_pipe *pipe;
137ac86cba9SOleksandr Andrushchenko 
138ac86cba9SOleksandr Andrushchenko 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
139ac86cba9SOleksandr Andrushchenko 	if (!pipe->funcs || !pipe->funcs->enable_vblank)
140ac86cba9SOleksandr Andrushchenko 		return 0;
141ac86cba9SOleksandr Andrushchenko 
142ac86cba9SOleksandr Andrushchenko 	return pipe->funcs->enable_vblank(pipe);
143ac86cba9SOleksandr Andrushchenko }
144ac86cba9SOleksandr Andrushchenko 
145ac86cba9SOleksandr Andrushchenko static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
146ac86cba9SOleksandr Andrushchenko {
147ac86cba9SOleksandr Andrushchenko 	struct drm_simple_display_pipe *pipe;
148ac86cba9SOleksandr Andrushchenko 
149ac86cba9SOleksandr Andrushchenko 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
150ac86cba9SOleksandr Andrushchenko 	if (!pipe->funcs || !pipe->funcs->disable_vblank)
151ac86cba9SOleksandr Andrushchenko 		return;
152ac86cba9SOleksandr Andrushchenko 
153ac86cba9SOleksandr Andrushchenko 	pipe->funcs->disable_vblank(pipe);
154ac86cba9SOleksandr Andrushchenko }
155ac86cba9SOleksandr Andrushchenko 
1565b809074SNoralf Trønnes static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
1575b809074SNoralf Trønnes 	.reset = drm_atomic_helper_crtc_reset,
1585b809074SNoralf Trønnes 	.destroy = drm_crtc_cleanup,
1595b809074SNoralf Trønnes 	.set_config = drm_atomic_helper_set_config,
1605b809074SNoralf Trønnes 	.page_flip = drm_atomic_helper_page_flip,
1615b809074SNoralf Trønnes 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
1625b809074SNoralf Trønnes 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
163ac86cba9SOleksandr Andrushchenko 	.enable_vblank = drm_simple_kms_crtc_enable_vblank,
164ac86cba9SOleksandr Andrushchenko 	.disable_vblank = drm_simple_kms_crtc_disable_vblank,
1655b809074SNoralf Trønnes };
1665b809074SNoralf Trønnes 
1675b809074SNoralf Trønnes static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
1685b809074SNoralf Trønnes 					struct drm_plane_state *plane_state)
1695b809074SNoralf Trønnes {
1705b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1715b809074SNoralf Trønnes 	struct drm_crtc_state *crtc_state;
1725b809074SNoralf Trønnes 	int ret;
1735b809074SNoralf Trønnes 
1745b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
175b4d93679SMaarten Lankhorst 	crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
1765b809074SNoralf Trønnes 						   &pipe->crtc);
1774be12cc2SVille Syrjälä 
178a01cb8baSVille Syrjälä 	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
1795b809074SNoralf Trønnes 						  DRM_PLANE_HELPER_NO_SCALING,
1805b809074SNoralf Trønnes 						  DRM_PLANE_HELPER_NO_SCALING,
1814be12cc2SVille Syrjälä 						  false, true);
1825b809074SNoralf Trønnes 	if (ret)
1835b809074SNoralf Trønnes 		return ret;
1845b809074SNoralf Trønnes 
1854be12cc2SVille Syrjälä 	if (!plane_state->visible)
1864751cf73SOleksandr Andrushchenko 		return 0;
1874751cf73SOleksandr Andrushchenko 
1885b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->check)
1895b809074SNoralf Trønnes 		return 0;
1905b809074SNoralf Trønnes 
1915b809074SNoralf Trønnes 	return pipe->funcs->check(pipe, plane_state, crtc_state);
1925b809074SNoralf Trønnes }
1935b809074SNoralf Trønnes 
1945b809074SNoralf Trønnes static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
195bcd2ba02SEric Anholt 					struct drm_plane_state *old_pstate)
1965b809074SNoralf Trønnes {
1975b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1985b809074SNoralf Trønnes 
1995b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2005b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->update)
2015b809074SNoralf Trønnes 		return;
2025b809074SNoralf Trønnes 
203bcd2ba02SEric Anholt 	pipe->funcs->update(pipe, old_pstate);
2045b809074SNoralf Trønnes }
2055b809074SNoralf Trønnes 
2067d83a155SMarek Vasut static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
2077d83a155SMarek Vasut 					   struct drm_plane_state *state)
2087d83a155SMarek Vasut {
2097d83a155SMarek Vasut 	struct drm_simple_display_pipe *pipe;
2107d83a155SMarek Vasut 
2117d83a155SMarek Vasut 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2127d83a155SMarek Vasut 	if (!pipe->funcs || !pipe->funcs->prepare_fb)
2137d83a155SMarek Vasut 		return 0;
2147d83a155SMarek Vasut 
2157d83a155SMarek Vasut 	return pipe->funcs->prepare_fb(pipe, state);
2167d83a155SMarek Vasut }
2177d83a155SMarek Vasut 
2187d83a155SMarek Vasut static void drm_simple_kms_plane_cleanup_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->cleanup_fb)
2257d83a155SMarek Vasut 		return;
2267d83a155SMarek Vasut 
2277d83a155SMarek Vasut 	pipe->funcs->cleanup_fb(pipe, state);
2287d83a155SMarek Vasut }
2297d83a155SMarek Vasut 
230dff906c3SEric Anholt static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
231dff906c3SEric Anholt 						uint32_t format,
232dff906c3SEric Anholt 						uint64_t modifier)
233dff906c3SEric Anholt {
234dff906c3SEric Anholt 	return modifier == DRM_FORMAT_MOD_LINEAR;
235dff906c3SEric Anholt }
236dff906c3SEric Anholt 
2375b809074SNoralf Trønnes static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
2387d83a155SMarek Vasut 	.prepare_fb = drm_simple_kms_plane_prepare_fb,
2397d83a155SMarek Vasut 	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
2405b809074SNoralf Trønnes 	.atomic_check = drm_simple_kms_plane_atomic_check,
2415b809074SNoralf Trønnes 	.atomic_update = drm_simple_kms_plane_atomic_update,
2425b809074SNoralf Trønnes };
2435b809074SNoralf Trønnes 
2445b809074SNoralf Trønnes static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
2455b809074SNoralf Trønnes 	.update_plane		= drm_atomic_helper_update_plane,
2465b809074SNoralf Trønnes 	.disable_plane		= drm_atomic_helper_disable_plane,
2475b809074SNoralf Trønnes 	.destroy		= drm_plane_cleanup,
2485b809074SNoralf Trønnes 	.reset			= drm_atomic_helper_plane_reset,
2495b809074SNoralf Trønnes 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
2505b809074SNoralf Trønnes 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
251dff906c3SEric Anholt 	.format_mod_supported   = drm_simple_kms_format_mod_supported,
2525b809074SNoralf Trønnes };
2535b809074SNoralf Trønnes 
2545b809074SNoralf Trønnes /**
255315486c6SAndrea Merello  * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
256315486c6SAndrea Merello  * @pipe: simple display pipe object
257315486c6SAndrea Merello  * @bridge: bridge to attach
258315486c6SAndrea Merello  *
259315486c6SAndrea Merello  * Makes it possible to still use the drm_simple_display_pipe helpers when
260315486c6SAndrea Merello  * a DRM bridge has to be used.
261315486c6SAndrea Merello  *
262315486c6SAndrea Merello  * Note that you probably want to initialize the pipe by passing a NULL
263315486c6SAndrea Merello  * connector to drm_simple_display_pipe_init().
264315486c6SAndrea Merello  *
265315486c6SAndrea Merello  * Returns:
266315486c6SAndrea Merello  * Zero on success, negative error code on failure.
267315486c6SAndrea Merello  */
268315486c6SAndrea Merello int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
269315486c6SAndrea Merello 					  struct drm_bridge *bridge)
270315486c6SAndrea Merello {
271a25b988fSLaurent Pinchart 	return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0);
272315486c6SAndrea Merello }
273315486c6SAndrea Merello EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
274315486c6SAndrea Merello 
275315486c6SAndrea Merello /**
2765b809074SNoralf Trønnes  * drm_simple_display_pipe_init - Initialize a simple display pipeline
2775b809074SNoralf Trønnes  * @dev: DRM device
2785b809074SNoralf Trønnes  * @pipe: simple display pipe object to initialize
2795b809074SNoralf Trønnes  * @funcs: callbacks for the display pipe (optional)
28062cacc79SDaniel Vetter  * @formats: array of supported formats (DRM_FORMAT\_\*)
2815b809074SNoralf Trønnes  * @format_count: number of elements in @formats
282e6fc3b68SBen Widawsky  * @format_modifiers: array of formats modifiers
2834f993973SAndrea Merello  * @connector: connector to attach and register (optional)
2845b809074SNoralf Trønnes  *
2855b809074SNoralf Trønnes  * Sets up a display pipeline which consist of a really simple
2864f993973SAndrea Merello  * plane-crtc-encoder pipe.
2874f993973SAndrea Merello  *
2884f993973SAndrea Merello  * If a connector is supplied, the pipe will be coupled with the provided
2894f993973SAndrea Merello  * connector. You may supply a NULL connector when using drm bridges, that
2904f993973SAndrea Merello  * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
2914f993973SAndrea Merello  *
2925b809074SNoralf Trønnes  * Teardown of a simple display pipe is all handled automatically by the drm
2935b809074SNoralf Trønnes  * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
2945b809074SNoralf Trønnes  * release the memory for the structure themselves.
2955b809074SNoralf Trønnes  *
2965b809074SNoralf Trønnes  * Returns:
2975b809074SNoralf Trønnes  * Zero on success, negative error code on failure.
2985b809074SNoralf Trønnes  */
2995b809074SNoralf Trønnes int drm_simple_display_pipe_init(struct drm_device *dev,
3005b809074SNoralf Trønnes 			struct drm_simple_display_pipe *pipe,
3015b809074SNoralf Trønnes 			const struct drm_simple_display_pipe_funcs *funcs,
3025b809074SNoralf Trønnes 			const uint32_t *formats, unsigned int format_count,
303e6fc3b68SBen Widawsky 			const uint64_t *format_modifiers,
3045b809074SNoralf Trønnes 			struct drm_connector *connector)
3055b809074SNoralf Trønnes {
3065b809074SNoralf Trønnes 	struct drm_encoder *encoder = &pipe->encoder;
3075b809074SNoralf Trønnes 	struct drm_plane *plane = &pipe->plane;
3085b809074SNoralf Trønnes 	struct drm_crtc *crtc = &pipe->crtc;
3095b809074SNoralf Trønnes 	int ret;
3105b809074SNoralf Trønnes 
3115b809074SNoralf Trønnes 	pipe->connector = connector;
3125b809074SNoralf Trønnes 	pipe->funcs = funcs;
3135b809074SNoralf Trønnes 
3145b809074SNoralf Trønnes 	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
3155b809074SNoralf Trønnes 	ret = drm_universal_plane_init(dev, plane, 0,
3165b809074SNoralf Trønnes 				       &drm_simple_kms_plane_funcs,
3175b809074SNoralf Trønnes 				       formats, format_count,
318e6fc3b68SBen Widawsky 				       format_modifiers,
3195b809074SNoralf Trønnes 				       DRM_PLANE_TYPE_PRIMARY, NULL);
3205b809074SNoralf Trønnes 	if (ret)
3215b809074SNoralf Trønnes 		return ret;
3225b809074SNoralf Trønnes 
3235b809074SNoralf Trønnes 	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
3245b809074SNoralf Trønnes 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
3255b809074SNoralf Trønnes 					&drm_simple_kms_crtc_funcs, NULL);
3265b809074SNoralf Trønnes 	if (ret)
3275b809074SNoralf Trønnes 		return ret;
3285b809074SNoralf Trønnes 
3296a52193bSVille Syrjälä 	encoder->possible_crtcs = drm_crtc_mask(crtc);
33063170ac6SThomas Zimmermann 	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
3314f993973SAndrea Merello 	if (ret || !connector)
3325b809074SNoralf Trønnes 		return ret;
3335b809074SNoralf Trønnes 
334cde4c44dSDaniel Vetter 	return drm_connector_attach_encoder(connector, encoder);
3355b809074SNoralf Trønnes }
3365b809074SNoralf Trønnes EXPORT_SYMBOL(drm_simple_display_pipe_init);
3375b809074SNoralf Trønnes 
3385b809074SNoralf Trønnes MODULE_LICENSE("GPL");
339