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>
1240cfc7fcSDaniel Vetter #include <drm/drm_drv.h>
1340cfc7fcSDaniel Vetter #include <drm/drm_gem_atomic_helper.h>
1459abba48SPhilipp Zabel #include <drm/drm_managed.h>
15fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
165b809074SNoralf Trønnes #include <drm/drm_simple_kms_helper.h>
175b809074SNoralf Trønnes 
185b809074SNoralf Trønnes /**
195b809074SNoralf Trønnes  * DOC: overview
205b809074SNoralf Trønnes  *
215b809074SNoralf Trønnes  * This helper library provides helpers for drivers for simple display
225b809074SNoralf Trønnes  * hardware.
235b809074SNoralf Trønnes  *
245b809074SNoralf Trønnes  * drm_simple_display_pipe_init() initializes a simple display pipeline
255b809074SNoralf Trønnes  * which has only one full-screen scanout buffer feeding one output. The
26ea0dd85aSDaniel Vetter  * pipeline is represented by &struct drm_simple_display_pipe and binds
275b809074SNoralf Trønnes  * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed
285b809074SNoralf Trønnes  * entity. Some flexibility for code reuse is provided through a separately
295b809074SNoralf Trønnes  * allocated &drm_connector object and supporting optional &drm_bridge
305b809074SNoralf Trønnes  * encoder drivers.
3163170ac6SThomas Zimmermann  *
3263170ac6SThomas Zimmermann  * Many drivers require only a very simple encoder that fulfills the minimum
3363170ac6SThomas Zimmermann  * requirements of the display pipeline and does not add additional
3463170ac6SThomas Zimmermann  * functionality. The function drm_simple_encoder_init() provides an
3563170ac6SThomas Zimmermann  * implementation of such an encoder.
365b809074SNoralf Trønnes  */
375b809074SNoralf Trønnes 
3863170ac6SThomas Zimmermann static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
395b809074SNoralf Trønnes 	.destroy = drm_encoder_cleanup,
405b809074SNoralf Trønnes };
415b809074SNoralf Trønnes 
4263170ac6SThomas Zimmermann /**
432cb5974dSThomas Zimmermann  * drm_simple_encoder_init - Initialize a preallocated encoder with
442cb5974dSThomas Zimmermann  *                           basic functionality.
4563170ac6SThomas Zimmermann  * @dev: drm device
462cb5974dSThomas Zimmermann  * @encoder: the encoder to initialize
4763170ac6SThomas Zimmermann  * @encoder_type: user visible type of the encoder
4863170ac6SThomas Zimmermann  *
4963170ac6SThomas Zimmermann  * Initialises a preallocated encoder that has no further functionality.
5063170ac6SThomas Zimmermann  * Settings for possible CRTC and clones are left to their initial values.
5163170ac6SThomas Zimmermann  * The encoder will be cleaned up automatically as part of the mode-setting
5263170ac6SThomas Zimmermann  * cleanup.
5363170ac6SThomas Zimmermann  *
542cb5974dSThomas Zimmermann  * The caller of drm_simple_encoder_init() is responsible for freeing
552cb5974dSThomas Zimmermann  * the encoder's memory after the encoder has been cleaned up. At the
562cb5974dSThomas Zimmermann  * moment this only works reliably if the encoder data structure is
572cb5974dSThomas Zimmermann  * stored in the device structure. Free the encoder's memory as part of
582cb5974dSThomas Zimmermann  * the device release function.
592cb5974dSThomas Zimmermann  *
6059abba48SPhilipp Zabel  * Note: consider using drmm_simple_encoder_alloc() instead of
6159abba48SPhilipp Zabel  * drm_simple_encoder_init() to let the DRM managed resource infrastructure
6259abba48SPhilipp Zabel  * take care of cleanup and deallocation.
632cb5974dSThomas Zimmermann  *
6463170ac6SThomas Zimmermann  * Returns:
6563170ac6SThomas Zimmermann  * Zero on success, error code on failure.
6663170ac6SThomas Zimmermann  */
drm_simple_encoder_init(struct drm_device * dev,struct drm_encoder * encoder,int encoder_type)6763170ac6SThomas Zimmermann int drm_simple_encoder_init(struct drm_device *dev,
6863170ac6SThomas Zimmermann 			    struct drm_encoder *encoder,
6963170ac6SThomas Zimmermann 			    int encoder_type)
7063170ac6SThomas Zimmermann {
7163170ac6SThomas Zimmermann 	return drm_encoder_init(dev, encoder,
7263170ac6SThomas Zimmermann 				&drm_simple_encoder_funcs_cleanup,
7363170ac6SThomas Zimmermann 				encoder_type, NULL);
7463170ac6SThomas Zimmermann }
7563170ac6SThomas Zimmermann EXPORT_SYMBOL(drm_simple_encoder_init);
7663170ac6SThomas Zimmermann 
__drmm_simple_encoder_alloc(struct drm_device * dev,size_t size,size_t offset,int encoder_type)7759abba48SPhilipp Zabel void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
7859abba48SPhilipp Zabel 				  size_t offset, int encoder_type)
7959abba48SPhilipp Zabel {
8059abba48SPhilipp Zabel 	return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type,
8159abba48SPhilipp Zabel 				    NULL);
8259abba48SPhilipp Zabel }
8359abba48SPhilipp Zabel EXPORT_SYMBOL(__drmm_simple_encoder_alloc);
8459abba48SPhilipp Zabel 
8540275dc4SLinus Walleij static enum drm_mode_status
drm_simple_kms_crtc_mode_valid(struct drm_crtc * crtc,const struct drm_display_mode * mode)8640275dc4SLinus Walleij drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
8740275dc4SLinus Walleij 			       const struct drm_display_mode *mode)
8840275dc4SLinus Walleij {
8940275dc4SLinus Walleij 	struct drm_simple_display_pipe *pipe;
9040275dc4SLinus Walleij 
9140275dc4SLinus Walleij 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
9240275dc4SLinus Walleij 	if (!pipe->funcs || !pipe->funcs->mode_valid)
9340275dc4SLinus Walleij 		/* Anything goes */
9440275dc4SLinus Walleij 		return MODE_OK;
9540275dc4SLinus Walleij 
9662db7d1eSDaniel Vetter 	return pipe->funcs->mode_valid(pipe, mode);
9740275dc4SLinus Walleij }
9840275dc4SLinus Walleij 
drm_simple_kms_crtc_check(struct drm_crtc * crtc,struct drm_atomic_state * state)996dcf0de7SDaniel Vetter static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
10029b77ad7SMaxime Ripard 				     struct drm_atomic_state *state)
1016dcf0de7SDaniel Vetter {
102dc2cdd17SThomas Zimmermann 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
103dc2cdd17SThomas Zimmermann 	int ret;
104765831dcSMaarten Lankhorst 
1058f2fd57dSThomas Zimmermann 	if (!crtc_state->enable)
1068f2fd57dSThomas Zimmermann 		goto out;
1078f2fd57dSThomas Zimmermann 
1088f2fd57dSThomas Zimmermann 	ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
109dc2cdd17SThomas Zimmermann 	if (ret)
110dc2cdd17SThomas Zimmermann 		return ret;
111765831dcSMaarten Lankhorst 
1128f2fd57dSThomas Zimmermann out:
113d74252bbSMaxime Ripard 	return drm_atomic_add_affected_planes(state, crtc);
1146dcf0de7SDaniel Vetter }
1156dcf0de7SDaniel Vetter 
drm_simple_kms_crtc_enable(struct drm_crtc * crtc,struct drm_atomic_state * state)1160b20a0f8SLaurent Pinchart static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
117351f950dSMaxime Ripard 				       struct drm_atomic_state *state)
1185b809074SNoralf Trønnes {
1190c9c7fd0SVille Syrjälä 	struct drm_plane *plane;
1205b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1215b809074SNoralf Trønnes 
1225b809074SNoralf Trønnes 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
1235b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->enable)
1245b809074SNoralf Trønnes 		return;
1255b809074SNoralf Trønnes 
1260c9c7fd0SVille Syrjälä 	plane = &pipe->plane;
1270c9c7fd0SVille Syrjälä 	pipe->funcs->enable(pipe, crtc->state, plane->state);
1285b809074SNoralf Trønnes }
1295b809074SNoralf Trønnes 
drm_simple_kms_crtc_disable(struct drm_crtc * crtc,struct drm_atomic_state * state)13064581714SLaurent Pinchart static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
131351f950dSMaxime Ripard 					struct drm_atomic_state *state)
1325b809074SNoralf Trønnes {
1335b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1345b809074SNoralf Trønnes 
1355b809074SNoralf Trønnes 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
1365b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->disable)
1375b809074SNoralf Trønnes 		return;
1385b809074SNoralf Trønnes 
1395b809074SNoralf Trønnes 	pipe->funcs->disable(pipe);
1405b809074SNoralf Trønnes }
1415b809074SNoralf Trønnes 
1425b809074SNoralf Trønnes static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
14340275dc4SLinus Walleij 	.mode_valid = drm_simple_kms_crtc_mode_valid,
1446dcf0de7SDaniel Vetter 	.atomic_check = drm_simple_kms_crtc_check,
1450b20a0f8SLaurent Pinchart 	.atomic_enable = drm_simple_kms_crtc_enable,
14664581714SLaurent Pinchart 	.atomic_disable = drm_simple_kms_crtc_disable,
1475b809074SNoralf Trønnes };
1485b809074SNoralf Trønnes 
drm_simple_kms_crtc_reset(struct drm_crtc * crtc)14938c5af44SThomas Zimmermann static void drm_simple_kms_crtc_reset(struct drm_crtc *crtc)
15038c5af44SThomas Zimmermann {
15138c5af44SThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
15238c5af44SThomas Zimmermann 
15338c5af44SThomas Zimmermann 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
15438c5af44SThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->reset_crtc)
15538c5af44SThomas Zimmermann 		return drm_atomic_helper_crtc_reset(crtc);
15638c5af44SThomas Zimmermann 
15738c5af44SThomas Zimmermann 	return pipe->funcs->reset_crtc(pipe);
15838c5af44SThomas Zimmermann }
15938c5af44SThomas Zimmermann 
drm_simple_kms_crtc_duplicate_state(struct drm_crtc * crtc)16038c5af44SThomas Zimmermann static struct drm_crtc_state *drm_simple_kms_crtc_duplicate_state(struct drm_crtc *crtc)
16138c5af44SThomas Zimmermann {
16238c5af44SThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
16338c5af44SThomas Zimmermann 
16438c5af44SThomas Zimmermann 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
16538c5af44SThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->duplicate_crtc_state)
16638c5af44SThomas Zimmermann 		return drm_atomic_helper_crtc_duplicate_state(crtc);
16738c5af44SThomas Zimmermann 
16838c5af44SThomas Zimmermann 	return pipe->funcs->duplicate_crtc_state(pipe);
16938c5af44SThomas Zimmermann }
17038c5af44SThomas Zimmermann 
drm_simple_kms_crtc_destroy_state(struct drm_crtc * crtc,struct drm_crtc_state * state)17138c5af44SThomas Zimmermann static void drm_simple_kms_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state)
17238c5af44SThomas Zimmermann {
17338c5af44SThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
17438c5af44SThomas Zimmermann 
17538c5af44SThomas Zimmermann 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
17638c5af44SThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->destroy_crtc_state)
17738c5af44SThomas Zimmermann 		drm_atomic_helper_crtc_destroy_state(crtc, state);
17838c5af44SThomas Zimmermann 	else
17938c5af44SThomas Zimmermann 		pipe->funcs->destroy_crtc_state(pipe, state);
18038c5af44SThomas Zimmermann }
18138c5af44SThomas Zimmermann 
drm_simple_kms_crtc_enable_vblank(struct drm_crtc * crtc)182ac86cba9SOleksandr Andrushchenko static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
183ac86cba9SOleksandr Andrushchenko {
184ac86cba9SOleksandr Andrushchenko 	struct drm_simple_display_pipe *pipe;
185ac86cba9SOleksandr Andrushchenko 
186ac86cba9SOleksandr Andrushchenko 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
187ac86cba9SOleksandr Andrushchenko 	if (!pipe->funcs || !pipe->funcs->enable_vblank)
188ac86cba9SOleksandr Andrushchenko 		return 0;
189ac86cba9SOleksandr Andrushchenko 
190ac86cba9SOleksandr Andrushchenko 	return pipe->funcs->enable_vblank(pipe);
191ac86cba9SOleksandr Andrushchenko }
192ac86cba9SOleksandr Andrushchenko 
drm_simple_kms_crtc_disable_vblank(struct drm_crtc * crtc)193ac86cba9SOleksandr Andrushchenko static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
194ac86cba9SOleksandr Andrushchenko {
195ac86cba9SOleksandr Andrushchenko 	struct drm_simple_display_pipe *pipe;
196ac86cba9SOleksandr Andrushchenko 
197ac86cba9SOleksandr Andrushchenko 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
198ac86cba9SOleksandr Andrushchenko 	if (!pipe->funcs || !pipe->funcs->disable_vblank)
199ac86cba9SOleksandr Andrushchenko 		return;
200ac86cba9SOleksandr Andrushchenko 
201ac86cba9SOleksandr Andrushchenko 	pipe->funcs->disable_vblank(pipe);
202ac86cba9SOleksandr Andrushchenko }
203ac86cba9SOleksandr Andrushchenko 
2045b809074SNoralf Trønnes static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
20538c5af44SThomas Zimmermann 	.reset = drm_simple_kms_crtc_reset,
2065b809074SNoralf Trønnes 	.destroy = drm_crtc_cleanup,
2075b809074SNoralf Trønnes 	.set_config = drm_atomic_helper_set_config,
2085b809074SNoralf Trønnes 	.page_flip = drm_atomic_helper_page_flip,
20938c5af44SThomas Zimmermann 	.atomic_duplicate_state = drm_simple_kms_crtc_duplicate_state,
21038c5af44SThomas Zimmermann 	.atomic_destroy_state = drm_simple_kms_crtc_destroy_state,
211ac86cba9SOleksandr Andrushchenko 	.enable_vblank = drm_simple_kms_crtc_enable_vblank,
212ac86cba9SOleksandr Andrushchenko 	.disable_vblank = drm_simple_kms_crtc_disable_vblank,
2135b809074SNoralf Trønnes };
2145b809074SNoralf Trønnes 
drm_simple_kms_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)2155b809074SNoralf Trønnes static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
2167c11b99aSMaxime Ripard 					struct drm_atomic_state *state)
2175b809074SNoralf Trønnes {
2187c11b99aSMaxime Ripard 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
2197c11b99aSMaxime Ripard 									     plane);
2205b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
2215b809074SNoralf Trønnes 	struct drm_crtc_state *crtc_state;
2225b809074SNoralf Trønnes 	int ret;
2235b809074SNoralf Trønnes 
2245b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
225dec92020SMaxime Ripard 	crtc_state = drm_atomic_get_new_crtc_state(state,
2265b809074SNoralf Trønnes 						   &pipe->crtc);
2274be12cc2SVille Syrjälä 
228a01cb8baSVille Syrjälä 	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
229cce32e4eSThomas Zimmermann 						  DRM_PLANE_NO_SCALING,
230cce32e4eSThomas Zimmermann 						  DRM_PLANE_NO_SCALING,
231dc2cdd17SThomas Zimmermann 						  false, false);
2325b809074SNoralf Trønnes 	if (ret)
2335b809074SNoralf Trønnes 		return ret;
2345b809074SNoralf Trønnes 
2354be12cc2SVille Syrjälä 	if (!plane_state->visible)
2364751cf73SOleksandr Andrushchenko 		return 0;
2374751cf73SOleksandr Andrushchenko 
2385b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->check)
2395b809074SNoralf Trønnes 		return 0;
2405b809074SNoralf Trønnes 
2415b809074SNoralf Trønnes 	return pipe->funcs->check(pipe, plane_state, crtc_state);
2425b809074SNoralf Trønnes }
2435b809074SNoralf Trønnes 
drm_simple_kms_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)2445b809074SNoralf Trønnes static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
245977697e2SMaxime Ripard 					struct drm_atomic_state *state)
2465b809074SNoralf Trønnes {
247977697e2SMaxime Ripard 	struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
248977697e2SMaxime Ripard 									    plane);
2495b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
2505b809074SNoralf Trønnes 
2515b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2525b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->update)
2535b809074SNoralf Trønnes 		return;
2545b809074SNoralf Trønnes 
255bcd2ba02SEric Anholt 	pipe->funcs->update(pipe, old_pstate);
2565b809074SNoralf Trønnes }
2575b809074SNoralf Trønnes 
drm_simple_kms_plane_prepare_fb(struct drm_plane * plane,struct drm_plane_state * state)2587d83a155SMarek Vasut static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
2597d83a155SMarek Vasut 					   struct drm_plane_state *state)
2607d83a155SMarek Vasut {
2617d83a155SMarek Vasut 	struct drm_simple_display_pipe *pipe;
2627d83a155SMarek Vasut 
2637d83a155SMarek Vasut 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
26440cfc7fcSDaniel Vetter 	if (!pipe->funcs || !pipe->funcs->prepare_fb) {
26540cfc7fcSDaniel Vetter 		if (WARN_ON_ONCE(!drm_core_check_feature(plane->dev, DRIVER_GEM)))
2667d83a155SMarek Vasut 			return 0;
2677d83a155SMarek Vasut 
26840cfc7fcSDaniel Vetter 		WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb);
26940cfc7fcSDaniel Vetter 
270*00b5497dSThomas Zimmermann 		return drm_gem_plane_helper_prepare_fb(plane, state);
27140cfc7fcSDaniel Vetter 	}
27240cfc7fcSDaniel Vetter 
2737d83a155SMarek Vasut 	return pipe->funcs->prepare_fb(pipe, state);
2747d83a155SMarek Vasut }
2757d83a155SMarek Vasut 
drm_simple_kms_plane_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * state)2767d83a155SMarek Vasut static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
2777d83a155SMarek Vasut 					    struct drm_plane_state *state)
2787d83a155SMarek Vasut {
2797d83a155SMarek Vasut 	struct drm_simple_display_pipe *pipe;
2807d83a155SMarek Vasut 
2817d83a155SMarek Vasut 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
2827d83a155SMarek Vasut 	if (!pipe->funcs || !pipe->funcs->cleanup_fb)
2837d83a155SMarek Vasut 		return;
2847d83a155SMarek Vasut 
2857d83a155SMarek Vasut 	pipe->funcs->cleanup_fb(pipe, state);
2867d83a155SMarek Vasut }
2877d83a155SMarek Vasut 
drm_simple_kms_plane_begin_fb_access(struct drm_plane * plane,struct drm_plane_state * new_plane_state)28894d879eaSThomas Zimmermann static int drm_simple_kms_plane_begin_fb_access(struct drm_plane *plane,
28994d879eaSThomas Zimmermann 						struct drm_plane_state *new_plane_state)
29094d879eaSThomas Zimmermann {
29194d879eaSThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
29294d879eaSThomas Zimmermann 
29394d879eaSThomas Zimmermann 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
29494d879eaSThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->begin_fb_access)
29594d879eaSThomas Zimmermann 		return 0;
29694d879eaSThomas Zimmermann 
29794d879eaSThomas Zimmermann 	return pipe->funcs->begin_fb_access(pipe, new_plane_state);
29894d879eaSThomas Zimmermann }
29994d879eaSThomas Zimmermann 
drm_simple_kms_plane_end_fb_access(struct drm_plane * plane,struct drm_plane_state * new_plane_state)30094d879eaSThomas Zimmermann static void drm_simple_kms_plane_end_fb_access(struct drm_plane *plane,
30194d879eaSThomas Zimmermann 					       struct drm_plane_state *new_plane_state)
30294d879eaSThomas Zimmermann {
30394d879eaSThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
30494d879eaSThomas Zimmermann 
30594d879eaSThomas Zimmermann 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
30694d879eaSThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->end_fb_access)
30794d879eaSThomas Zimmermann 		return;
30894d879eaSThomas Zimmermann 
30994d879eaSThomas Zimmermann 	pipe->funcs->end_fb_access(pipe, new_plane_state);
31094d879eaSThomas Zimmermann }
31194d879eaSThomas Zimmermann 
drm_simple_kms_format_mod_supported(struct drm_plane * plane,uint32_t format,uint64_t modifier)312dff906c3SEric Anholt static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
313dff906c3SEric Anholt 						uint32_t format,
314dff906c3SEric Anholt 						uint64_t modifier)
315dff906c3SEric Anholt {
316dff906c3SEric Anholt 	return modifier == DRM_FORMAT_MOD_LINEAR;
317dff906c3SEric Anholt }
318dff906c3SEric Anholt 
3195b809074SNoralf Trønnes static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
3207d83a155SMarek Vasut 	.prepare_fb = drm_simple_kms_plane_prepare_fb,
3217d83a155SMarek Vasut 	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
32294d879eaSThomas Zimmermann 	.begin_fb_access = drm_simple_kms_plane_begin_fb_access,
32394d879eaSThomas Zimmermann 	.end_fb_access = drm_simple_kms_plane_end_fb_access,
3245b809074SNoralf Trønnes 	.atomic_check = drm_simple_kms_plane_atomic_check,
3255b809074SNoralf Trønnes 	.atomic_update = drm_simple_kms_plane_atomic_update,
3265b809074SNoralf Trønnes };
3275b809074SNoralf Trønnes 
drm_simple_kms_plane_reset(struct drm_plane * plane)32840f302adSThomas Zimmermann static void drm_simple_kms_plane_reset(struct drm_plane *plane)
32940f302adSThomas Zimmermann {
33040f302adSThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
33140f302adSThomas Zimmermann 
33240f302adSThomas Zimmermann 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
33340f302adSThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->reset_plane)
33440f302adSThomas Zimmermann 		return drm_atomic_helper_plane_reset(plane);
33540f302adSThomas Zimmermann 
33640f302adSThomas Zimmermann 	return pipe->funcs->reset_plane(pipe);
33740f302adSThomas Zimmermann }
33840f302adSThomas Zimmermann 
drm_simple_kms_plane_duplicate_state(struct drm_plane * plane)33940f302adSThomas Zimmermann static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane)
34040f302adSThomas Zimmermann {
34140f302adSThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
34240f302adSThomas Zimmermann 
34340f302adSThomas Zimmermann 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
34440f302adSThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->duplicate_plane_state)
34540f302adSThomas Zimmermann 		return drm_atomic_helper_plane_duplicate_state(plane);
34640f302adSThomas Zimmermann 
34740f302adSThomas Zimmermann 	return pipe->funcs->duplicate_plane_state(pipe);
34840f302adSThomas Zimmermann }
34940f302adSThomas Zimmermann 
drm_simple_kms_plane_destroy_state(struct drm_plane * plane,struct drm_plane_state * state)35040f302adSThomas Zimmermann static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane,
35140f302adSThomas Zimmermann 					       struct drm_plane_state *state)
35240f302adSThomas Zimmermann {
35340f302adSThomas Zimmermann 	struct drm_simple_display_pipe *pipe;
35440f302adSThomas Zimmermann 
35540f302adSThomas Zimmermann 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
35640f302adSThomas Zimmermann 	if (!pipe->funcs || !pipe->funcs->destroy_plane_state)
35740f302adSThomas Zimmermann 		drm_atomic_helper_plane_destroy_state(plane, state);
35840f302adSThomas Zimmermann 	else
35940f302adSThomas Zimmermann 		pipe->funcs->destroy_plane_state(pipe, state);
36040f302adSThomas Zimmermann }
36140f302adSThomas Zimmermann 
3625b809074SNoralf Trønnes static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
3635b809074SNoralf Trønnes 	.update_plane		= drm_atomic_helper_update_plane,
3645b809074SNoralf Trønnes 	.disable_plane		= drm_atomic_helper_disable_plane,
3655b809074SNoralf Trønnes 	.destroy		= drm_plane_cleanup,
36640f302adSThomas Zimmermann 	.reset			= drm_simple_kms_plane_reset,
36740f302adSThomas Zimmermann 	.atomic_duplicate_state	= drm_simple_kms_plane_duplicate_state,
36840f302adSThomas Zimmermann 	.atomic_destroy_state	= drm_simple_kms_plane_destroy_state,
369dff906c3SEric Anholt 	.format_mod_supported   = drm_simple_kms_format_mod_supported,
3705b809074SNoralf Trønnes };
3715b809074SNoralf Trønnes 
3725b809074SNoralf Trønnes /**
373315486c6SAndrea Merello  * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
374315486c6SAndrea Merello  * @pipe: simple display pipe object
375315486c6SAndrea Merello  * @bridge: bridge to attach
376315486c6SAndrea Merello  *
377315486c6SAndrea Merello  * Makes it possible to still use the drm_simple_display_pipe helpers when
378315486c6SAndrea Merello  * a DRM bridge has to be used.
379315486c6SAndrea Merello  *
380315486c6SAndrea Merello  * Note that you probably want to initialize the pipe by passing a NULL
381315486c6SAndrea Merello  * connector to drm_simple_display_pipe_init().
382315486c6SAndrea Merello  *
383315486c6SAndrea Merello  * Returns:
384315486c6SAndrea Merello  * Zero on success, negative error code on failure.
385315486c6SAndrea Merello  */
drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe * pipe,struct drm_bridge * bridge)386315486c6SAndrea Merello int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
387315486c6SAndrea Merello 					  struct drm_bridge *bridge)
388315486c6SAndrea Merello {
389a25b988fSLaurent Pinchart 	return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0);
390315486c6SAndrea Merello }
391315486c6SAndrea Merello EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
392315486c6SAndrea Merello 
393315486c6SAndrea Merello /**
3945b809074SNoralf Trønnes  * drm_simple_display_pipe_init - Initialize a simple display pipeline
3955b809074SNoralf Trønnes  * @dev: DRM device
3965b809074SNoralf Trønnes  * @pipe: simple display pipe object to initialize
3975b809074SNoralf Trønnes  * @funcs: callbacks for the display pipe (optional)
39862cacc79SDaniel Vetter  * @formats: array of supported formats (DRM_FORMAT\_\*)
3995b809074SNoralf Trønnes  * @format_count: number of elements in @formats
400e6fc3b68SBen Widawsky  * @format_modifiers: array of formats modifiers
4014f993973SAndrea Merello  * @connector: connector to attach and register (optional)
4025b809074SNoralf Trønnes  *
4035b809074SNoralf Trønnes  * Sets up a display pipeline which consist of a really simple
4044f993973SAndrea Merello  * plane-crtc-encoder pipe.
4054f993973SAndrea Merello  *
4064f993973SAndrea Merello  * If a connector is supplied, the pipe will be coupled with the provided
4074f993973SAndrea Merello  * connector. You may supply a NULL connector when using drm bridges, that
4084f993973SAndrea Merello  * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
4094f993973SAndrea Merello  *
4105b809074SNoralf Trønnes  * Teardown of a simple display pipe is all handled automatically by the drm
4115b809074SNoralf Trønnes  * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
4125b809074SNoralf Trønnes  * release the memory for the structure themselves.
4135b809074SNoralf Trønnes  *
4145b809074SNoralf Trønnes  * Returns:
4155b809074SNoralf Trønnes  * Zero on success, negative error code on failure.
4165b809074SNoralf Trønnes  */
drm_simple_display_pipe_init(struct drm_device * dev,struct drm_simple_display_pipe * pipe,const struct drm_simple_display_pipe_funcs * funcs,const uint32_t * formats,unsigned int format_count,const uint64_t * format_modifiers,struct drm_connector * connector)4175b809074SNoralf Trønnes int drm_simple_display_pipe_init(struct drm_device *dev,
4185b809074SNoralf Trønnes 			struct drm_simple_display_pipe *pipe,
4195b809074SNoralf Trønnes 			const struct drm_simple_display_pipe_funcs *funcs,
4205b809074SNoralf Trønnes 			const uint32_t *formats, unsigned int format_count,
421e6fc3b68SBen Widawsky 			const uint64_t *format_modifiers,
4225b809074SNoralf Trønnes 			struct drm_connector *connector)
4235b809074SNoralf Trønnes {
4245b809074SNoralf Trønnes 	struct drm_encoder *encoder = &pipe->encoder;
4255b809074SNoralf Trønnes 	struct drm_plane *plane = &pipe->plane;
4265b809074SNoralf Trønnes 	struct drm_crtc *crtc = &pipe->crtc;
4275b809074SNoralf Trønnes 	int ret;
4285b809074SNoralf Trønnes 
4295b809074SNoralf Trønnes 	pipe->connector = connector;
4305b809074SNoralf Trønnes 	pipe->funcs = funcs;
4315b809074SNoralf Trønnes 
4325b809074SNoralf Trønnes 	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
4335b809074SNoralf Trønnes 	ret = drm_universal_plane_init(dev, plane, 0,
4345b809074SNoralf Trønnes 				       &drm_simple_kms_plane_funcs,
4355b809074SNoralf Trønnes 				       formats, format_count,
436e6fc3b68SBen Widawsky 				       format_modifiers,
4375b809074SNoralf Trønnes 				       DRM_PLANE_TYPE_PRIMARY, NULL);
4385b809074SNoralf Trønnes 	if (ret)
4395b809074SNoralf Trønnes 		return ret;
4405b809074SNoralf Trønnes 
4415b809074SNoralf Trønnes 	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
4425b809074SNoralf Trønnes 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
4435b809074SNoralf Trønnes 					&drm_simple_kms_crtc_funcs, NULL);
4445b809074SNoralf Trønnes 	if (ret)
4455b809074SNoralf Trønnes 		return ret;
4465b809074SNoralf Trønnes 
4476a52193bSVille Syrjälä 	encoder->possible_crtcs = drm_crtc_mask(crtc);
44863170ac6SThomas Zimmermann 	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
4494f993973SAndrea Merello 	if (ret || !connector)
4505b809074SNoralf Trønnes 		return ret;
4515b809074SNoralf Trønnes 
452cde4c44dSDaniel Vetter 	return drm_connector_attach_encoder(connector, encoder);
4535b809074SNoralf Trønnes }
4545b809074SNoralf Trønnes EXPORT_SYMBOL(drm_simple_display_pipe_init);
4555b809074SNoralf Trønnes 
4565b809074SNoralf Trønnes MODULE_LICENSE("GPL");
457