xref: /dflybsd-src/sys/dev/drm/drm_simple_kms_helper.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
11dedbd3bSFrançois Tigeot /*
21dedbd3bSFrançois Tigeot  * Copyright (C) 2016 Noralf Trønnes
31dedbd3bSFrançois Tigeot  *
41dedbd3bSFrançois Tigeot  * This program is free software; you can redistribute it and/or modify
51dedbd3bSFrançois Tigeot  * it under the terms of the GNU General Public License as published by
61dedbd3bSFrançois Tigeot  * the Free Software Foundation; either version 2 of the License, or
71dedbd3bSFrançois Tigeot  * (at your option) any later version.
81dedbd3bSFrançois Tigeot  */
91dedbd3bSFrançois Tigeot 
101dedbd3bSFrançois Tigeot #include <drm/drmP.h>
111dedbd3bSFrançois Tigeot #include <drm/drm_atomic.h>
121dedbd3bSFrançois Tigeot #include <drm/drm_atomic_helper.h>
131dedbd3bSFrançois Tigeot #include <drm/drm_crtc_helper.h>
141dedbd3bSFrançois Tigeot #include <drm/drm_plane_helper.h>
151dedbd3bSFrançois Tigeot #include <drm/drm_simple_kms_helper.h>
161dedbd3bSFrançois Tigeot #include <linux/slab.h>
171dedbd3bSFrançois Tigeot 
181dedbd3bSFrançois Tigeot /**
191dedbd3bSFrançois Tigeot  * DOC: overview
201dedbd3bSFrançois Tigeot  *
211dedbd3bSFrançois Tigeot  * This helper library provides helpers for drivers for simple display
221dedbd3bSFrançois Tigeot  * hardware.
231dedbd3bSFrançois Tigeot  *
241dedbd3bSFrançois Tigeot  * drm_simple_display_pipe_init() initializes a simple display pipeline
251dedbd3bSFrançois Tigeot  * which has only one full-screen scanout buffer feeding one output. The
26a85cb24fSFrançois Tigeot  * pipeline is represented by &struct drm_simple_display_pipe and binds
271dedbd3bSFrançois Tigeot  * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed
281dedbd3bSFrançois Tigeot  * entity. Some flexibility for code reuse is provided through a separately
291dedbd3bSFrançois Tigeot  * allocated &drm_connector object and supporting optional &drm_bridge
301dedbd3bSFrançois Tigeot  * encoder drivers.
311dedbd3bSFrançois Tigeot  */
321dedbd3bSFrançois Tigeot 
331dedbd3bSFrançois Tigeot static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = {
341dedbd3bSFrançois Tigeot 	.destroy = drm_encoder_cleanup,
351dedbd3bSFrançois Tigeot };
361dedbd3bSFrançois Tigeot 
drm_simple_kms_crtc_check(struct drm_crtc * crtc,struct drm_crtc_state * state)371dedbd3bSFrançois Tigeot static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
381dedbd3bSFrançois Tigeot 				     struct drm_crtc_state *state)
391dedbd3bSFrançois Tigeot {
40*3f2dd94aSFrançois Tigeot 	bool has_primary = state->plane_mask &
41*3f2dd94aSFrançois Tigeot 			   BIT(drm_plane_index(crtc->primary));
42*3f2dd94aSFrançois Tigeot 
43*3f2dd94aSFrançois Tigeot 	/* We always want to have an active plane with an active CRTC */
44*3f2dd94aSFrançois Tigeot 	if (has_primary != state->enable)
45*3f2dd94aSFrançois Tigeot 		return -EINVAL;
46*3f2dd94aSFrançois Tigeot 
471dedbd3bSFrançois Tigeot 	return drm_atomic_add_affected_planes(state->state, crtc);
481dedbd3bSFrançois Tigeot }
491dedbd3bSFrançois Tigeot 
drm_simple_kms_crtc_enable(struct drm_crtc * crtc,struct drm_crtc_state * old_state)50*3f2dd94aSFrançois Tigeot static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
51*3f2dd94aSFrançois Tigeot 				       struct drm_crtc_state *old_state)
521dedbd3bSFrançois Tigeot {
531dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
541dedbd3bSFrançois Tigeot 
551dedbd3bSFrançois Tigeot 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
561dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->enable)
571dedbd3bSFrançois Tigeot 		return;
581dedbd3bSFrançois Tigeot 
591dedbd3bSFrançois Tigeot 	pipe->funcs->enable(pipe, crtc->state);
601dedbd3bSFrançois Tigeot }
611dedbd3bSFrançois Tigeot 
drm_simple_kms_crtc_disable(struct drm_crtc * crtc,struct drm_crtc_state * old_state)62*3f2dd94aSFrançois Tigeot static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
63*3f2dd94aSFrançois Tigeot 					struct drm_crtc_state *old_state)
641dedbd3bSFrançois Tigeot {
651dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
661dedbd3bSFrançois Tigeot 
671dedbd3bSFrançois Tigeot 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
681dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->disable)
691dedbd3bSFrançois Tigeot 		return;
701dedbd3bSFrançois Tigeot 
711dedbd3bSFrançois Tigeot 	pipe->funcs->disable(pipe);
721dedbd3bSFrançois Tigeot }
731dedbd3bSFrançois Tigeot 
741dedbd3bSFrançois Tigeot static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
751dedbd3bSFrançois Tigeot 	.atomic_check = drm_simple_kms_crtc_check,
76*3f2dd94aSFrançois Tigeot 	.atomic_enable = drm_simple_kms_crtc_enable,
77*3f2dd94aSFrançois Tigeot 	.atomic_disable = drm_simple_kms_crtc_disable,
781dedbd3bSFrançois Tigeot };
791dedbd3bSFrançois Tigeot 
801dedbd3bSFrançois Tigeot static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
811dedbd3bSFrançois Tigeot 	.reset = drm_atomic_helper_crtc_reset,
821dedbd3bSFrançois Tigeot 	.destroy = drm_crtc_cleanup,
831dedbd3bSFrançois Tigeot 	.set_config = drm_atomic_helper_set_config,
841dedbd3bSFrançois Tigeot 	.page_flip = drm_atomic_helper_page_flip,
851dedbd3bSFrançois Tigeot 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
861dedbd3bSFrançois Tigeot 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
871dedbd3bSFrançois Tigeot };
881dedbd3bSFrançois Tigeot 
drm_simple_kms_plane_atomic_check(struct drm_plane * plane,struct drm_plane_state * plane_state)891dedbd3bSFrançois Tigeot static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
901dedbd3bSFrançois Tigeot 					struct drm_plane_state *plane_state)
911dedbd3bSFrançois Tigeot {
921dedbd3bSFrançois Tigeot 	struct drm_rect clip = { 0 };
931dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
941dedbd3bSFrançois Tigeot 	struct drm_crtc_state *crtc_state;
951dedbd3bSFrançois Tigeot 	int ret;
961dedbd3bSFrançois Tigeot 
971dedbd3bSFrançois Tigeot 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
98a85cb24fSFrançois Tigeot 	crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
991dedbd3bSFrançois Tigeot 						   &pipe->crtc);
1001dedbd3bSFrançois Tigeot 	if (!crtc_state->enable)
1011dedbd3bSFrançois Tigeot 		return 0; /* nothing to check when disabling or disabled */
1021dedbd3bSFrançois Tigeot 
1031dedbd3bSFrançois Tigeot 	clip.x2 = crtc_state->adjusted_mode.hdisplay;
1041dedbd3bSFrançois Tigeot 	clip.y2 = crtc_state->adjusted_mode.vdisplay;
1051dedbd3bSFrançois Tigeot 
1061dedbd3bSFrançois Tigeot 	ret = drm_plane_helper_check_state(plane_state, &clip,
1071dedbd3bSFrançois Tigeot 					   DRM_PLANE_HELPER_NO_SCALING,
1081dedbd3bSFrançois Tigeot 					   DRM_PLANE_HELPER_NO_SCALING,
1091dedbd3bSFrançois Tigeot 					   false, true);
1101dedbd3bSFrançois Tigeot 	if (ret)
1111dedbd3bSFrançois Tigeot 		return ret;
1121dedbd3bSFrançois Tigeot 
1131dedbd3bSFrançois Tigeot 	if (!plane_state->visible)
1141dedbd3bSFrançois Tigeot 		return -EINVAL;
1151dedbd3bSFrançois Tigeot 
1161dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->check)
1171dedbd3bSFrançois Tigeot 		return 0;
1181dedbd3bSFrançois Tigeot 
1191dedbd3bSFrançois Tigeot 	return pipe->funcs->check(pipe, plane_state, crtc_state);
1201dedbd3bSFrançois Tigeot }
1211dedbd3bSFrançois Tigeot 
drm_simple_kms_plane_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_pstate)1221dedbd3bSFrançois Tigeot static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
123a85cb24fSFrançois Tigeot 					struct drm_plane_state *old_pstate)
1241dedbd3bSFrançois Tigeot {
1251dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
1261dedbd3bSFrançois Tigeot 
1271dedbd3bSFrançois Tigeot 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
1281dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->update)
1291dedbd3bSFrançois Tigeot 		return;
1301dedbd3bSFrançois Tigeot 
131a85cb24fSFrançois Tigeot 	pipe->funcs->update(pipe, old_pstate);
1321dedbd3bSFrançois Tigeot }
1331dedbd3bSFrançois Tigeot 
drm_simple_kms_plane_prepare_fb(struct drm_plane * plane,struct drm_plane_state * state)1341dedbd3bSFrançois Tigeot static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
1351dedbd3bSFrançois Tigeot 					   struct drm_plane_state *state)
1361dedbd3bSFrançois Tigeot {
1371dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
1381dedbd3bSFrançois Tigeot 
1391dedbd3bSFrançois Tigeot 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
1401dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->prepare_fb)
1411dedbd3bSFrançois Tigeot 		return 0;
1421dedbd3bSFrançois Tigeot 
1431dedbd3bSFrançois Tigeot 	return pipe->funcs->prepare_fb(pipe, state);
1441dedbd3bSFrançois Tigeot }
1451dedbd3bSFrançois Tigeot 
drm_simple_kms_plane_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * state)1461dedbd3bSFrançois Tigeot static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
1471dedbd3bSFrançois Tigeot 					    struct drm_plane_state *state)
1481dedbd3bSFrançois Tigeot {
1491dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
1501dedbd3bSFrançois Tigeot 
1511dedbd3bSFrançois Tigeot 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
1521dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->cleanup_fb)
1531dedbd3bSFrançois Tigeot 		return;
1541dedbd3bSFrançois Tigeot 
1551dedbd3bSFrançois Tigeot 	pipe->funcs->cleanup_fb(pipe, state);
1561dedbd3bSFrançois Tigeot }
1571dedbd3bSFrançois Tigeot 
1581dedbd3bSFrançois Tigeot static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
1591dedbd3bSFrançois Tigeot 	.prepare_fb = drm_simple_kms_plane_prepare_fb,
1601dedbd3bSFrançois Tigeot 	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
1611dedbd3bSFrançois Tigeot 	.atomic_check = drm_simple_kms_plane_atomic_check,
1621dedbd3bSFrançois Tigeot 	.atomic_update = drm_simple_kms_plane_atomic_update,
1631dedbd3bSFrançois Tigeot };
1641dedbd3bSFrançois Tigeot 
1651dedbd3bSFrançois Tigeot static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
1661dedbd3bSFrançois Tigeot 	.update_plane		= drm_atomic_helper_update_plane,
1671dedbd3bSFrançois Tigeot 	.disable_plane		= drm_atomic_helper_disable_plane,
1681dedbd3bSFrançois Tigeot 	.destroy		= drm_plane_cleanup,
1691dedbd3bSFrançois Tigeot 	.reset			= drm_atomic_helper_plane_reset,
1701dedbd3bSFrançois Tigeot 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
1711dedbd3bSFrançois Tigeot 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
1721dedbd3bSFrançois Tigeot };
1731dedbd3bSFrançois Tigeot 
1741dedbd3bSFrançois Tigeot /**
1751dedbd3bSFrançois Tigeot  * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
1761dedbd3bSFrançois Tigeot  * @pipe: simple display pipe object
1771dedbd3bSFrançois Tigeot  * @bridge: bridge to attach
1781dedbd3bSFrançois Tigeot  *
1791dedbd3bSFrançois Tigeot  * Makes it possible to still use the drm_simple_display_pipe helpers when
1801dedbd3bSFrançois Tigeot  * a DRM bridge has to be used.
1811dedbd3bSFrançois Tigeot  *
1821dedbd3bSFrançois Tigeot  * Note that you probably want to initialize the pipe by passing a NULL
1831dedbd3bSFrançois Tigeot  * connector to drm_simple_display_pipe_init().
1841dedbd3bSFrançois Tigeot  *
1851dedbd3bSFrançois Tigeot  * Returns:
1861dedbd3bSFrançois Tigeot  * Zero on success, negative error code on failure.
1871dedbd3bSFrançois Tigeot  */
drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe * pipe,struct drm_bridge * bridge)1881dedbd3bSFrançois Tigeot int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
1891dedbd3bSFrançois Tigeot 					  struct drm_bridge *bridge)
1901dedbd3bSFrançois Tigeot {
191a85cb24fSFrançois Tigeot 	return drm_bridge_attach(&pipe->encoder, bridge, NULL);
1921dedbd3bSFrançois Tigeot }
1931dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
1941dedbd3bSFrançois Tigeot 
1951dedbd3bSFrançois Tigeot /**
1961dedbd3bSFrançois Tigeot  * drm_simple_display_pipe_init - Initialize a simple display pipeline
1971dedbd3bSFrançois Tigeot  * @dev: DRM device
1981dedbd3bSFrançois Tigeot  * @pipe: simple display pipe object to initialize
1991dedbd3bSFrançois Tigeot  * @funcs: callbacks for the display pipe (optional)
2001dedbd3bSFrançois Tigeot  * @formats: array of supported formats (DRM_FORMAT\_\*)
2011dedbd3bSFrançois Tigeot  * @format_count: number of elements in @formats
202*3f2dd94aSFrançois Tigeot  * @format_modifiers: array of formats modifiers
2031dedbd3bSFrançois Tigeot  * @connector: connector to attach and register (optional)
2041dedbd3bSFrançois Tigeot  *
2051dedbd3bSFrançois Tigeot  * Sets up a display pipeline which consist of a really simple
2061dedbd3bSFrançois Tigeot  * plane-crtc-encoder pipe.
2071dedbd3bSFrançois Tigeot  *
2081dedbd3bSFrançois Tigeot  * If a connector is supplied, the pipe will be coupled with the provided
2091dedbd3bSFrançois Tigeot  * connector. You may supply a NULL connector when using drm bridges, that
2101dedbd3bSFrançois Tigeot  * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
2111dedbd3bSFrançois Tigeot  *
2121dedbd3bSFrançois Tigeot  * Teardown of a simple display pipe is all handled automatically by the drm
2131dedbd3bSFrançois Tigeot  * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
2141dedbd3bSFrançois Tigeot  * release the memory for the structure themselves.
2151dedbd3bSFrançois Tigeot  *
2161dedbd3bSFrançois Tigeot  * Returns:
2171dedbd3bSFrançois Tigeot  * Zero on success, negative error code on failure.
2181dedbd3bSFrançois Tigeot  */
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)2191dedbd3bSFrançois Tigeot int drm_simple_display_pipe_init(struct drm_device *dev,
2201dedbd3bSFrançois Tigeot 			struct drm_simple_display_pipe *pipe,
2211dedbd3bSFrançois Tigeot 			const struct drm_simple_display_pipe_funcs *funcs,
2221dedbd3bSFrançois Tigeot 			const uint32_t *formats, unsigned int format_count,
223*3f2dd94aSFrançois Tigeot 			const uint64_t *format_modifiers,
2241dedbd3bSFrançois Tigeot 			struct drm_connector *connector)
2251dedbd3bSFrançois Tigeot {
2261dedbd3bSFrançois Tigeot 	struct drm_encoder *encoder = &pipe->encoder;
2271dedbd3bSFrançois Tigeot 	struct drm_plane *plane = &pipe->plane;
2281dedbd3bSFrançois Tigeot 	struct drm_crtc *crtc = &pipe->crtc;
2291dedbd3bSFrançois Tigeot 	int ret;
2301dedbd3bSFrançois Tigeot 
2311dedbd3bSFrançois Tigeot 	pipe->connector = connector;
2321dedbd3bSFrançois Tigeot 	pipe->funcs = funcs;
2331dedbd3bSFrançois Tigeot 
2341dedbd3bSFrançois Tigeot 	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
2351dedbd3bSFrançois Tigeot 	ret = drm_universal_plane_init(dev, plane, 0,
2361dedbd3bSFrançois Tigeot 				       &drm_simple_kms_plane_funcs,
2371dedbd3bSFrançois Tigeot 				       formats, format_count,
238*3f2dd94aSFrançois Tigeot 				       format_modifiers,
2391dedbd3bSFrançois Tigeot 				       DRM_PLANE_TYPE_PRIMARY, NULL);
2401dedbd3bSFrançois Tigeot 	if (ret)
2411dedbd3bSFrançois Tigeot 		return ret;
2421dedbd3bSFrançois Tigeot 
2431dedbd3bSFrançois Tigeot 	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
2441dedbd3bSFrançois Tigeot 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
2451dedbd3bSFrançois Tigeot 					&drm_simple_kms_crtc_funcs, NULL);
2461dedbd3bSFrançois Tigeot 	if (ret)
2471dedbd3bSFrançois Tigeot 		return ret;
2481dedbd3bSFrançois Tigeot 
2491dedbd3bSFrançois Tigeot 	encoder->possible_crtcs = 1 << drm_crtc_index(crtc);
2501dedbd3bSFrançois Tigeot 	ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs,
2511dedbd3bSFrançois Tigeot 			       DRM_MODE_ENCODER_NONE, NULL);
2521dedbd3bSFrançois Tigeot 	if (ret || !connector)
2531dedbd3bSFrançois Tigeot 		return ret;
2541dedbd3bSFrançois Tigeot 
2551dedbd3bSFrançois Tigeot 	return drm_mode_connector_attach_encoder(connector, encoder);
2561dedbd3bSFrançois Tigeot }
2571dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_simple_display_pipe_init);
2581dedbd3bSFrançois Tigeot 
2591dedbd3bSFrançois Tigeot MODULE_LICENSE("GPL");
260