xref: /linux/drivers/gpu/drm/drm_simple_kms_helper.c (revision 0b20a0f8c3cb6f74fe326101b62eeb5e2c56a53c)
15b809074SNoralf Trønnes /*
25b809074SNoralf Trønnes  * Copyright (C) 2016 Noralf Trønnes
35b809074SNoralf Trønnes  *
45b809074SNoralf Trønnes  * This program is free software; you can redistribute it and/or modify
55b809074SNoralf Trønnes  * it under the terms of the GNU General Public License as published by
65b809074SNoralf Trønnes  * the Free Software Foundation; either version 2 of the License, or
75b809074SNoralf Trønnes  * (at your option) any later version.
85b809074SNoralf Trønnes  */
95b809074SNoralf Trønnes 
105b809074SNoralf Trønnes #include <drm/drmP.h>
115b809074SNoralf Trønnes #include <drm/drm_atomic.h>
125b809074SNoralf Trønnes #include <drm/drm_atomic_helper.h>
135b809074SNoralf Trønnes #include <drm/drm_crtc_helper.h>
145b809074SNoralf Trønnes #include <drm/drm_plane_helper.h>
155b809074SNoralf Trønnes #include <drm/drm_simple_kms_helper.h>
165b809074SNoralf Trønnes #include <linux/slab.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.
315b809074SNoralf Trønnes  */
325b809074SNoralf Trønnes 
335b809074SNoralf Trønnes static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = {
345b809074SNoralf Trønnes 	.destroy = drm_encoder_cleanup,
355b809074SNoralf Trønnes };
365b809074SNoralf Trønnes 
376dcf0de7SDaniel Vetter static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
386dcf0de7SDaniel Vetter 				     struct drm_crtc_state *state)
396dcf0de7SDaniel Vetter {
406dcf0de7SDaniel Vetter 	return drm_atomic_add_affected_planes(state->state, crtc);
416dcf0de7SDaniel Vetter }
426dcf0de7SDaniel Vetter 
43*0b20a0f8SLaurent Pinchart static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
44*0b20a0f8SLaurent Pinchart 				       struct drm_crtc_state *old_state)
455b809074SNoralf Trønnes {
465b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
475b809074SNoralf Trønnes 
485b809074SNoralf Trønnes 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
495b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->enable)
505b809074SNoralf Trønnes 		return;
515b809074SNoralf Trønnes 
525b809074SNoralf Trønnes 	pipe->funcs->enable(pipe, crtc->state);
535b809074SNoralf Trønnes }
545b809074SNoralf Trønnes 
555b809074SNoralf Trønnes static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc)
565b809074SNoralf Trønnes {
575b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
585b809074SNoralf Trønnes 
595b809074SNoralf Trønnes 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
605b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->disable)
615b809074SNoralf Trønnes 		return;
625b809074SNoralf Trønnes 
635b809074SNoralf Trønnes 	pipe->funcs->disable(pipe);
645b809074SNoralf Trønnes }
655b809074SNoralf Trønnes 
665b809074SNoralf Trønnes static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
676dcf0de7SDaniel Vetter 	.atomic_check = drm_simple_kms_crtc_check,
68*0b20a0f8SLaurent Pinchart 	.atomic_enable = drm_simple_kms_crtc_enable,
695b809074SNoralf Trønnes 	.disable = drm_simple_kms_crtc_disable,
705b809074SNoralf Trønnes };
715b809074SNoralf Trønnes 
725b809074SNoralf Trønnes static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
735b809074SNoralf Trønnes 	.reset = drm_atomic_helper_crtc_reset,
745b809074SNoralf Trønnes 	.destroy = drm_crtc_cleanup,
755b809074SNoralf Trønnes 	.set_config = drm_atomic_helper_set_config,
765b809074SNoralf Trønnes 	.page_flip = drm_atomic_helper_page_flip,
775b809074SNoralf Trønnes 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
785b809074SNoralf Trønnes 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
795b809074SNoralf Trønnes };
805b809074SNoralf Trønnes 
815b809074SNoralf Trønnes static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
825b809074SNoralf Trønnes 					struct drm_plane_state *plane_state)
835b809074SNoralf Trønnes {
845b809074SNoralf Trønnes 	struct drm_rect clip = { 0 };
855b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
865b809074SNoralf Trønnes 	struct drm_crtc_state *crtc_state;
875b809074SNoralf Trønnes 	int ret;
885b809074SNoralf Trønnes 
895b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
90b4d93679SMaarten Lankhorst 	crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
915b809074SNoralf Trønnes 						   &pipe->crtc);
925b809074SNoralf Trønnes 	if (crtc_state->enable != !!plane_state->crtc)
935b809074SNoralf Trønnes 		return -EINVAL; /* plane must match crtc enable state */
945b809074SNoralf Trønnes 
955b809074SNoralf Trønnes 	if (!crtc_state->enable)
965b809074SNoralf Trønnes 		return 0; /* nothing to check when disabling or disabled */
975b809074SNoralf Trønnes 
985b809074SNoralf Trønnes 	clip.x2 = crtc_state->adjusted_mode.hdisplay;
995b809074SNoralf Trønnes 	clip.y2 = crtc_state->adjusted_mode.vdisplay;
1004be12cc2SVille Syrjälä 
1014be12cc2SVille Syrjälä 	ret = drm_plane_helper_check_state(plane_state, &clip,
1025b809074SNoralf Trønnes 					   DRM_PLANE_HELPER_NO_SCALING,
1035b809074SNoralf Trønnes 					   DRM_PLANE_HELPER_NO_SCALING,
1044be12cc2SVille Syrjälä 					   false, true);
1055b809074SNoralf Trønnes 	if (ret)
1065b809074SNoralf Trønnes 		return ret;
1075b809074SNoralf Trønnes 
1084be12cc2SVille Syrjälä 	if (!plane_state->visible)
1095b809074SNoralf Trønnes 		return -EINVAL;
1105b809074SNoralf Trønnes 
1115b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->check)
1125b809074SNoralf Trønnes 		return 0;
1135b809074SNoralf Trønnes 
1145b809074SNoralf Trønnes 	return pipe->funcs->check(pipe, plane_state, crtc_state);
1155b809074SNoralf Trønnes }
1165b809074SNoralf Trønnes 
1175b809074SNoralf Trønnes static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
118bcd2ba02SEric Anholt 					struct drm_plane_state *old_pstate)
1195b809074SNoralf Trønnes {
1205b809074SNoralf Trønnes 	struct drm_simple_display_pipe *pipe;
1215b809074SNoralf Trønnes 
1225b809074SNoralf Trønnes 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
1235b809074SNoralf Trønnes 	if (!pipe->funcs || !pipe->funcs->update)
1245b809074SNoralf Trønnes 		return;
1255b809074SNoralf Trønnes 
126bcd2ba02SEric Anholt 	pipe->funcs->update(pipe, old_pstate);
1275b809074SNoralf Trønnes }
1285b809074SNoralf Trønnes 
1297d83a155SMarek Vasut static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
1307d83a155SMarek Vasut 					   struct drm_plane_state *state)
1317d83a155SMarek Vasut {
1327d83a155SMarek Vasut 	struct drm_simple_display_pipe *pipe;
1337d83a155SMarek Vasut 
1347d83a155SMarek Vasut 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
1357d83a155SMarek Vasut 	if (!pipe->funcs || !pipe->funcs->prepare_fb)
1367d83a155SMarek Vasut 		return 0;
1377d83a155SMarek Vasut 
1387d83a155SMarek Vasut 	return pipe->funcs->prepare_fb(pipe, state);
1397d83a155SMarek Vasut }
1407d83a155SMarek Vasut 
1417d83a155SMarek Vasut static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
1427d83a155SMarek Vasut 					    struct drm_plane_state *state)
1437d83a155SMarek Vasut {
1447d83a155SMarek Vasut 	struct drm_simple_display_pipe *pipe;
1457d83a155SMarek Vasut 
1467d83a155SMarek Vasut 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
1477d83a155SMarek Vasut 	if (!pipe->funcs || !pipe->funcs->cleanup_fb)
1487d83a155SMarek Vasut 		return;
1497d83a155SMarek Vasut 
1507d83a155SMarek Vasut 	pipe->funcs->cleanup_fb(pipe, state);
1517d83a155SMarek Vasut }
1527d83a155SMarek Vasut 
1535b809074SNoralf Trønnes static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
1547d83a155SMarek Vasut 	.prepare_fb = drm_simple_kms_plane_prepare_fb,
1557d83a155SMarek Vasut 	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
1565b809074SNoralf Trønnes 	.atomic_check = drm_simple_kms_plane_atomic_check,
1575b809074SNoralf Trønnes 	.atomic_update = drm_simple_kms_plane_atomic_update,
1585b809074SNoralf Trønnes };
1595b809074SNoralf Trønnes 
1605b809074SNoralf Trønnes static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
1615b809074SNoralf Trønnes 	.update_plane		= drm_atomic_helper_update_plane,
1625b809074SNoralf Trønnes 	.disable_plane		= drm_atomic_helper_disable_plane,
1635b809074SNoralf Trønnes 	.destroy		= drm_plane_cleanup,
1645b809074SNoralf Trønnes 	.reset			= drm_atomic_helper_plane_reset,
1655b809074SNoralf Trønnes 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
1665b809074SNoralf Trønnes 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
1675b809074SNoralf Trønnes };
1685b809074SNoralf Trønnes 
1695b809074SNoralf Trønnes /**
170315486c6SAndrea Merello  * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
171315486c6SAndrea Merello  * @pipe: simple display pipe object
172315486c6SAndrea Merello  * @bridge: bridge to attach
173315486c6SAndrea Merello  *
174315486c6SAndrea Merello  * Makes it possible to still use the drm_simple_display_pipe helpers when
175315486c6SAndrea Merello  * a DRM bridge has to be used.
176315486c6SAndrea Merello  *
177315486c6SAndrea Merello  * Note that you probably want to initialize the pipe by passing a NULL
178315486c6SAndrea Merello  * connector to drm_simple_display_pipe_init().
179315486c6SAndrea Merello  *
180315486c6SAndrea Merello  * Returns:
181315486c6SAndrea Merello  * Zero on success, negative error code on failure.
182315486c6SAndrea Merello  */
183315486c6SAndrea Merello int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
184315486c6SAndrea Merello 					  struct drm_bridge *bridge)
185315486c6SAndrea Merello {
1863bb80f24SLaurent Pinchart 	return drm_bridge_attach(&pipe->encoder, bridge, NULL);
187315486c6SAndrea Merello }
188315486c6SAndrea Merello EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
189315486c6SAndrea Merello 
190315486c6SAndrea Merello /**
1915b809074SNoralf Trønnes  * drm_simple_display_pipe_init - Initialize a simple display pipeline
1925b809074SNoralf Trønnes  * @dev: DRM device
1935b809074SNoralf Trønnes  * @pipe: simple display pipe object to initialize
1945b809074SNoralf Trønnes  * @funcs: callbacks for the display pipe (optional)
19562cacc79SDaniel Vetter  * @formats: array of supported formats (DRM_FORMAT\_\*)
1965b809074SNoralf Trønnes  * @format_count: number of elements in @formats
1974f993973SAndrea Merello  * @connector: connector to attach and register (optional)
1985b809074SNoralf Trønnes  *
1995b809074SNoralf Trønnes  * Sets up a display pipeline which consist of a really simple
2004f993973SAndrea Merello  * plane-crtc-encoder pipe.
2014f993973SAndrea Merello  *
2024f993973SAndrea Merello  * If a connector is supplied, the pipe will be coupled with the provided
2034f993973SAndrea Merello  * connector. You may supply a NULL connector when using drm bridges, that
2044f993973SAndrea Merello  * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
2054f993973SAndrea Merello  *
2065b809074SNoralf Trønnes  * Teardown of a simple display pipe is all handled automatically by the drm
2075b809074SNoralf Trønnes  * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
2085b809074SNoralf Trønnes  * release the memory for the structure themselves.
2095b809074SNoralf Trønnes  *
2105b809074SNoralf Trønnes  * Returns:
2115b809074SNoralf Trønnes  * Zero on success, negative error code on failure.
2125b809074SNoralf Trønnes  */
2135b809074SNoralf Trønnes int drm_simple_display_pipe_init(struct drm_device *dev,
2145b809074SNoralf Trønnes 			struct drm_simple_display_pipe *pipe,
2155b809074SNoralf Trønnes 			const struct drm_simple_display_pipe_funcs *funcs,
2165b809074SNoralf Trønnes 			const uint32_t *formats, unsigned int format_count,
2175b809074SNoralf Trønnes 			struct drm_connector *connector)
2185b809074SNoralf Trønnes {
2195b809074SNoralf Trønnes 	struct drm_encoder *encoder = &pipe->encoder;
2205b809074SNoralf Trønnes 	struct drm_plane *plane = &pipe->plane;
2215b809074SNoralf Trønnes 	struct drm_crtc *crtc = &pipe->crtc;
2225b809074SNoralf Trønnes 	int ret;
2235b809074SNoralf Trønnes 
2245b809074SNoralf Trønnes 	pipe->connector = connector;
2255b809074SNoralf Trønnes 	pipe->funcs = funcs;
2265b809074SNoralf Trønnes 
2275b809074SNoralf Trønnes 	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
2285b809074SNoralf Trønnes 	ret = drm_universal_plane_init(dev, plane, 0,
2295b809074SNoralf Trønnes 				       &drm_simple_kms_plane_funcs,
2305b809074SNoralf Trønnes 				       formats, format_count,
2315b809074SNoralf Trønnes 				       DRM_PLANE_TYPE_PRIMARY, NULL);
2325b809074SNoralf Trønnes 	if (ret)
2335b809074SNoralf Trønnes 		return ret;
2345b809074SNoralf Trønnes 
2355b809074SNoralf Trønnes 	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
2365b809074SNoralf Trønnes 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
2375b809074SNoralf Trønnes 					&drm_simple_kms_crtc_funcs, NULL);
2385b809074SNoralf Trønnes 	if (ret)
2395b809074SNoralf Trønnes 		return ret;
2405b809074SNoralf Trønnes 
2415b809074SNoralf Trønnes 	encoder->possible_crtcs = 1 << drm_crtc_index(crtc);
2425b809074SNoralf Trønnes 	ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs,
2435b809074SNoralf Trønnes 			       DRM_MODE_ENCODER_NONE, NULL);
2444f993973SAndrea Merello 	if (ret || !connector)
2455b809074SNoralf Trønnes 		return ret;
2465b809074SNoralf Trønnes 
2475b809074SNoralf Trønnes 	return drm_mode_connector_attach_encoder(connector, encoder);
2485b809074SNoralf Trønnes }
2495b809074SNoralf Trønnes EXPORT_SYMBOL(drm_simple_display_pipe_init);
2505b809074SNoralf Trønnes 
2515b809074SNoralf Trønnes MODULE_LICENSE("GPL");
252