xref: /dflybsd-src/sys/dev/drm/drm_simple_kms_helper.c (revision a85cb24f18e3804e75ab8bcda7692564d0563317)
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
26*a85cb24fSFranç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 
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 {
401dedbd3bSFrançois Tigeot 	return drm_atomic_add_affected_planes(state->state, crtc);
411dedbd3bSFrançois Tigeot }
421dedbd3bSFrançois Tigeot 
431dedbd3bSFrançois Tigeot static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc)
441dedbd3bSFrançois Tigeot {
451dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
461dedbd3bSFrançois Tigeot 
471dedbd3bSFrançois Tigeot 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
481dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->enable)
491dedbd3bSFrançois Tigeot 		return;
501dedbd3bSFrançois Tigeot 
511dedbd3bSFrançois Tigeot 	pipe->funcs->enable(pipe, crtc->state);
521dedbd3bSFrançois Tigeot }
531dedbd3bSFrançois Tigeot 
541dedbd3bSFrançois Tigeot static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc)
551dedbd3bSFrançois Tigeot {
561dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
571dedbd3bSFrançois Tigeot 
581dedbd3bSFrançois Tigeot 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
591dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->disable)
601dedbd3bSFrançois Tigeot 		return;
611dedbd3bSFrançois Tigeot 
621dedbd3bSFrançois Tigeot 	pipe->funcs->disable(pipe);
631dedbd3bSFrançois Tigeot }
641dedbd3bSFrançois Tigeot 
651dedbd3bSFrançois Tigeot static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
661dedbd3bSFrançois Tigeot 	.atomic_check = drm_simple_kms_crtc_check,
671dedbd3bSFrançois Tigeot 	.disable = drm_simple_kms_crtc_disable,
681dedbd3bSFrançois Tigeot 	.enable = drm_simple_kms_crtc_enable,
691dedbd3bSFrançois Tigeot };
701dedbd3bSFrançois Tigeot 
711dedbd3bSFrançois Tigeot static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
721dedbd3bSFrançois Tigeot 	.reset = drm_atomic_helper_crtc_reset,
731dedbd3bSFrançois Tigeot 	.destroy = drm_crtc_cleanup,
741dedbd3bSFrançois Tigeot 	.set_config = drm_atomic_helper_set_config,
751dedbd3bSFrançois Tigeot 	.page_flip = drm_atomic_helper_page_flip,
761dedbd3bSFrançois Tigeot 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
771dedbd3bSFrançois Tigeot 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
781dedbd3bSFrançois Tigeot };
791dedbd3bSFrançois Tigeot 
801dedbd3bSFrançois Tigeot static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
811dedbd3bSFrançois Tigeot 					struct drm_plane_state *plane_state)
821dedbd3bSFrançois Tigeot {
831dedbd3bSFrançois Tigeot 	struct drm_rect clip = { 0 };
841dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
851dedbd3bSFrançois Tigeot 	struct drm_crtc_state *crtc_state;
861dedbd3bSFrançois Tigeot 	int ret;
871dedbd3bSFrançois Tigeot 
881dedbd3bSFrançois Tigeot 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
89*a85cb24fSFrançois Tigeot 	crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
901dedbd3bSFrançois Tigeot 						   &pipe->crtc);
911dedbd3bSFrançois Tigeot 	if (crtc_state->enable != !!plane_state->crtc)
921dedbd3bSFrançois Tigeot 		return -EINVAL; /* plane must match crtc enable state */
931dedbd3bSFrançois Tigeot 
941dedbd3bSFrançois Tigeot 	if (!crtc_state->enable)
951dedbd3bSFrançois Tigeot 		return 0; /* nothing to check when disabling or disabled */
961dedbd3bSFrançois Tigeot 
971dedbd3bSFrançois Tigeot 	clip.x2 = crtc_state->adjusted_mode.hdisplay;
981dedbd3bSFrançois Tigeot 	clip.y2 = crtc_state->adjusted_mode.vdisplay;
991dedbd3bSFrançois Tigeot 
1001dedbd3bSFrançois Tigeot 	ret = drm_plane_helper_check_state(plane_state, &clip,
1011dedbd3bSFrançois Tigeot 					   DRM_PLANE_HELPER_NO_SCALING,
1021dedbd3bSFrançois Tigeot 					   DRM_PLANE_HELPER_NO_SCALING,
1031dedbd3bSFrançois Tigeot 					   false, true);
1041dedbd3bSFrançois Tigeot 	if (ret)
1051dedbd3bSFrançois Tigeot 		return ret;
1061dedbd3bSFrançois Tigeot 
1071dedbd3bSFrançois Tigeot 	if (!plane_state->visible)
1081dedbd3bSFrançois Tigeot 		return -EINVAL;
1091dedbd3bSFrançois Tigeot 
1101dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->check)
1111dedbd3bSFrançois Tigeot 		return 0;
1121dedbd3bSFrançois Tigeot 
1131dedbd3bSFrançois Tigeot 	return pipe->funcs->check(pipe, plane_state, crtc_state);
1141dedbd3bSFrançois Tigeot }
1151dedbd3bSFrançois Tigeot 
1161dedbd3bSFrançois Tigeot static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
117*a85cb24fSFrançois Tigeot 					struct drm_plane_state *old_pstate)
1181dedbd3bSFrançois Tigeot {
1191dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
1201dedbd3bSFrançois Tigeot 
1211dedbd3bSFrançois Tigeot 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
1221dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->update)
1231dedbd3bSFrançois Tigeot 		return;
1241dedbd3bSFrançois Tigeot 
125*a85cb24fSFrançois Tigeot 	pipe->funcs->update(pipe, old_pstate);
1261dedbd3bSFrançois Tigeot }
1271dedbd3bSFrançois Tigeot 
1281dedbd3bSFrançois Tigeot static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
1291dedbd3bSFrançois Tigeot 					   struct drm_plane_state *state)
1301dedbd3bSFrançois Tigeot {
1311dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
1321dedbd3bSFrançois Tigeot 
1331dedbd3bSFrançois Tigeot 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
1341dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->prepare_fb)
1351dedbd3bSFrançois Tigeot 		return 0;
1361dedbd3bSFrançois Tigeot 
1371dedbd3bSFrançois Tigeot 	return pipe->funcs->prepare_fb(pipe, state);
1381dedbd3bSFrançois Tigeot }
1391dedbd3bSFrançois Tigeot 
1401dedbd3bSFrançois Tigeot static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
1411dedbd3bSFrançois Tigeot 					    struct drm_plane_state *state)
1421dedbd3bSFrançois Tigeot {
1431dedbd3bSFrançois Tigeot 	struct drm_simple_display_pipe *pipe;
1441dedbd3bSFrançois Tigeot 
1451dedbd3bSFrançois Tigeot 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
1461dedbd3bSFrançois Tigeot 	if (!pipe->funcs || !pipe->funcs->cleanup_fb)
1471dedbd3bSFrançois Tigeot 		return;
1481dedbd3bSFrançois Tigeot 
1491dedbd3bSFrançois Tigeot 	pipe->funcs->cleanup_fb(pipe, state);
1501dedbd3bSFrançois Tigeot }
1511dedbd3bSFrançois Tigeot 
1521dedbd3bSFrançois Tigeot static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
1531dedbd3bSFrançois Tigeot 	.prepare_fb = drm_simple_kms_plane_prepare_fb,
1541dedbd3bSFrançois Tigeot 	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
1551dedbd3bSFrançois Tigeot 	.atomic_check = drm_simple_kms_plane_atomic_check,
1561dedbd3bSFrançois Tigeot 	.atomic_update = drm_simple_kms_plane_atomic_update,
1571dedbd3bSFrançois Tigeot };
1581dedbd3bSFrançois Tigeot 
1591dedbd3bSFrançois Tigeot static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
1601dedbd3bSFrançois Tigeot 	.update_plane		= drm_atomic_helper_update_plane,
1611dedbd3bSFrançois Tigeot 	.disable_plane		= drm_atomic_helper_disable_plane,
1621dedbd3bSFrançois Tigeot 	.destroy		= drm_plane_cleanup,
1631dedbd3bSFrançois Tigeot 	.reset			= drm_atomic_helper_plane_reset,
1641dedbd3bSFrançois Tigeot 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
1651dedbd3bSFrançois Tigeot 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
1661dedbd3bSFrançois Tigeot };
1671dedbd3bSFrançois Tigeot 
1681dedbd3bSFrançois Tigeot /**
1691dedbd3bSFrançois Tigeot  * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
1701dedbd3bSFrançois Tigeot  * @pipe: simple display pipe object
1711dedbd3bSFrançois Tigeot  * @bridge: bridge to attach
1721dedbd3bSFrançois Tigeot  *
1731dedbd3bSFrançois Tigeot  * Makes it possible to still use the drm_simple_display_pipe helpers when
1741dedbd3bSFrançois Tigeot  * a DRM bridge has to be used.
1751dedbd3bSFrançois Tigeot  *
1761dedbd3bSFrançois Tigeot  * Note that you probably want to initialize the pipe by passing a NULL
1771dedbd3bSFrançois Tigeot  * connector to drm_simple_display_pipe_init().
1781dedbd3bSFrançois Tigeot  *
1791dedbd3bSFrançois Tigeot  * Returns:
1801dedbd3bSFrançois Tigeot  * Zero on success, negative error code on failure.
1811dedbd3bSFrançois Tigeot  */
1821dedbd3bSFrançois Tigeot int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
1831dedbd3bSFrançois Tigeot 					  struct drm_bridge *bridge)
1841dedbd3bSFrançois Tigeot {
185*a85cb24fSFrançois Tigeot 	return drm_bridge_attach(&pipe->encoder, bridge, NULL);
1861dedbd3bSFrançois Tigeot }
1871dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
1881dedbd3bSFrançois Tigeot 
1891dedbd3bSFrançois Tigeot /**
1901dedbd3bSFrançois Tigeot  * drm_simple_display_pipe_init - Initialize a simple display pipeline
1911dedbd3bSFrançois Tigeot  * @dev: DRM device
1921dedbd3bSFrançois Tigeot  * @pipe: simple display pipe object to initialize
1931dedbd3bSFrançois Tigeot  * @funcs: callbacks for the display pipe (optional)
1941dedbd3bSFrançois Tigeot  * @formats: array of supported formats (DRM_FORMAT\_\*)
1951dedbd3bSFrançois Tigeot  * @format_count: number of elements in @formats
1961dedbd3bSFrançois Tigeot  * @connector: connector to attach and register (optional)
1971dedbd3bSFrançois Tigeot  *
1981dedbd3bSFrançois Tigeot  * Sets up a display pipeline which consist of a really simple
1991dedbd3bSFrançois Tigeot  * plane-crtc-encoder pipe.
2001dedbd3bSFrançois Tigeot  *
2011dedbd3bSFrançois Tigeot  * If a connector is supplied, the pipe will be coupled with the provided
2021dedbd3bSFrançois Tigeot  * connector. You may supply a NULL connector when using drm bridges, that
2031dedbd3bSFrançois Tigeot  * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
2041dedbd3bSFrançois Tigeot  *
2051dedbd3bSFrançois Tigeot  * Teardown of a simple display pipe is all handled automatically by the drm
2061dedbd3bSFrançois Tigeot  * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
2071dedbd3bSFrançois Tigeot  * release the memory for the structure themselves.
2081dedbd3bSFrançois Tigeot  *
2091dedbd3bSFrançois Tigeot  * Returns:
2101dedbd3bSFrançois Tigeot  * Zero on success, negative error code on failure.
2111dedbd3bSFrançois Tigeot  */
2121dedbd3bSFrançois Tigeot int drm_simple_display_pipe_init(struct drm_device *dev,
2131dedbd3bSFrançois Tigeot 			struct drm_simple_display_pipe *pipe,
2141dedbd3bSFrançois Tigeot 			const struct drm_simple_display_pipe_funcs *funcs,
2151dedbd3bSFrançois Tigeot 			const uint32_t *formats, unsigned int format_count,
2161dedbd3bSFrançois Tigeot 			struct drm_connector *connector)
2171dedbd3bSFrançois Tigeot {
2181dedbd3bSFrançois Tigeot 	struct drm_encoder *encoder = &pipe->encoder;
2191dedbd3bSFrançois Tigeot 	struct drm_plane *plane = &pipe->plane;
2201dedbd3bSFrançois Tigeot 	struct drm_crtc *crtc = &pipe->crtc;
2211dedbd3bSFrançois Tigeot 	int ret;
2221dedbd3bSFrançois Tigeot 
2231dedbd3bSFrançois Tigeot 	pipe->connector = connector;
2241dedbd3bSFrançois Tigeot 	pipe->funcs = funcs;
2251dedbd3bSFrançois Tigeot 
2261dedbd3bSFrançois Tigeot 	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
2271dedbd3bSFrançois Tigeot 	ret = drm_universal_plane_init(dev, plane, 0,
2281dedbd3bSFrançois Tigeot 				       &drm_simple_kms_plane_funcs,
2291dedbd3bSFrançois Tigeot 				       formats, format_count,
2301dedbd3bSFrançois Tigeot 				       DRM_PLANE_TYPE_PRIMARY, NULL);
2311dedbd3bSFrançois Tigeot 	if (ret)
2321dedbd3bSFrançois Tigeot 		return ret;
2331dedbd3bSFrançois Tigeot 
2341dedbd3bSFrançois Tigeot 	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
2351dedbd3bSFrançois Tigeot 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
2361dedbd3bSFrançois Tigeot 					&drm_simple_kms_crtc_funcs, NULL);
2371dedbd3bSFrançois Tigeot 	if (ret)
2381dedbd3bSFrançois Tigeot 		return ret;
2391dedbd3bSFrançois Tigeot 
2401dedbd3bSFrançois Tigeot 	encoder->possible_crtcs = 1 << drm_crtc_index(crtc);
2411dedbd3bSFrançois Tigeot 	ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs,
2421dedbd3bSFrançois Tigeot 			       DRM_MODE_ENCODER_NONE, NULL);
2431dedbd3bSFrançois Tigeot 	if (ret || !connector)
2441dedbd3bSFrançois Tigeot 		return ret;
2451dedbd3bSFrançois Tigeot 
2461dedbd3bSFrançois Tigeot 	return drm_mode_connector_attach_encoder(connector, encoder);
2471dedbd3bSFrançois Tigeot }
2481dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_simple_display_pipe_init);
2491dedbd3bSFrançois Tigeot 
2501dedbd3bSFrançois Tigeot MODULE_LICENSE("GPL");
251