1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 #include <drm/drm_atomic_state_helper.h>
4 #include <drm/drm_gem_atomic_helper.h>
5 #include <drm/drm_gem_framebuffer_helper.h>
6 #include <drm/drm_simple_kms_helper.h>
7 
8 #include "drm_internal.h"
9 
10 /**
11  * DOC: overview
12  *
13  * The GEM atomic helpers library implements generic atomic-commit
14  * functions for drivers that use GEM objects. Currently, it provides
15  * plane state and framebuffer BO mappings for planes with shadow
16  * buffers.
17  */
18 
19 /*
20  * Shadow-buffered Planes
21  */
22 
23 static struct drm_plane_state *
24 drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane)
25 {
26 	struct drm_plane_state *plane_state = plane->state;
27 	struct drm_shadow_plane_state *new_shadow_plane_state;
28 
29 	if (!plane_state)
30 		return NULL;
31 
32 	new_shadow_plane_state = kzalloc(sizeof(*new_shadow_plane_state), GFP_KERNEL);
33 	if (!new_shadow_plane_state)
34 		return NULL;
35 	__drm_atomic_helper_plane_duplicate_state(plane, &new_shadow_plane_state->base);
36 
37 	return &new_shadow_plane_state->base;
38 }
39 
40 static void drm_gem_destroy_shadow_plane_state(struct drm_plane *plane,
41 					       struct drm_plane_state *plane_state)
42 {
43 	struct drm_shadow_plane_state *shadow_plane_state =
44 		to_drm_shadow_plane_state(plane_state);
45 
46 	__drm_atomic_helper_plane_destroy_state(&shadow_plane_state->base);
47 	kfree(shadow_plane_state);
48 }
49 
50 static void drm_gem_reset_shadow_plane(struct drm_plane *plane)
51 {
52 	struct drm_shadow_plane_state *shadow_plane_state;
53 
54 	if (plane->state) {
55 		drm_gem_destroy_shadow_plane_state(plane, plane->state);
56 		plane->state = NULL; /* must be set to NULL here */
57 	}
58 
59 	shadow_plane_state = kzalloc(sizeof(*shadow_plane_state), GFP_KERNEL);
60 	if (!shadow_plane_state)
61 		return;
62 	__drm_atomic_helper_plane_reset(plane, &shadow_plane_state->base);
63 }
64 
65 static int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state)
66 {
67 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
68 	struct drm_framebuffer *fb = plane_state->fb;
69 	struct drm_gem_object *obj;
70 	struct dma_buf_map map;
71 	int ret;
72 	size_t i;
73 
74 	if (!fb)
75 		return 0;
76 
77 	ret = drm_gem_fb_prepare_fb(plane, plane_state);
78 	if (ret)
79 		return ret;
80 
81 	for (i = 0; i < ARRAY_SIZE(shadow_plane_state->map); ++i) {
82 		obj = drm_gem_fb_get_obj(fb, i);
83 		if (!obj)
84 			continue;
85 		ret = drm_gem_vmap(obj, &map);
86 		if (ret)
87 			goto err_drm_gem_vunmap;
88 		shadow_plane_state->map[i] = map;
89 	}
90 
91 	return 0;
92 
93 err_drm_gem_vunmap:
94 	while (i) {
95 		--i;
96 		obj = drm_gem_fb_get_obj(fb, i);
97 		if (!obj)
98 			continue;
99 		drm_gem_vunmap(obj, &shadow_plane_state->map[i]);
100 	}
101 	return ret;
102 }
103 
104 static void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state)
105 {
106 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
107 	struct drm_framebuffer *fb = plane_state->fb;
108 	size_t i = ARRAY_SIZE(shadow_plane_state->map);
109 	struct drm_gem_object *obj;
110 
111 	if (!fb)
112 		return;
113 
114 	while (i) {
115 		--i;
116 		obj = drm_gem_fb_get_obj(fb, i);
117 		if (!obj)
118 			continue;
119 		drm_gem_vunmap(obj, &shadow_plane_state->map[i]);
120 	}
121 }
122 
123 /**
124  * drm_gem_simple_kms_prepare_shadow_fb - prepares shadow framebuffers
125  * @pipe: the simple display pipe
126  * @plane_state: the plane state of type struct drm_shadow_plane_state
127  *
128  * This function implements struct drm_simple_display_funcs.prepare_fb. It
129  * maps all buffer objects of the plane's framebuffer into kernel address
130  * space and stores them in struct drm_shadow_plane_state.map. The
131  * framebuffer will be synchronized as part of the atomic commit.
132  *
133  * See drm_gem_simple_kms_cleanup_shadow_fb() for cleanup.
134  *
135  * Returns:
136  * 0 on success, or a negative errno code otherwise.
137  */
138 int drm_gem_simple_kms_prepare_shadow_fb(struct drm_simple_display_pipe *pipe,
139 					 struct drm_plane_state *plane_state)
140 {
141 	return drm_gem_prepare_shadow_fb(&pipe->plane, plane_state);
142 }
143 EXPORT_SYMBOL(drm_gem_simple_kms_prepare_shadow_fb);
144 
145 /**
146  * drm_gem_simple_kms_cleanup_shadow_fb - releases shadow framebuffers
147  * @pipe: the simple display pipe
148  * @plane_state: the plane state of type struct drm_shadow_plane_state
149  *
150  * This function implements struct drm_simple_display_funcs.cleanup_fb.
151  * This function unmaps all buffer objects of the plane's framebuffer.
152  *
153  * See drm_gem_simple_kms_prepare_shadow_fb().
154  */
155 void drm_gem_simple_kms_cleanup_shadow_fb(struct drm_simple_display_pipe *pipe,
156 					  struct drm_plane_state *plane_state)
157 {
158 	drm_gem_cleanup_shadow_fb(&pipe->plane, plane_state);
159 }
160 EXPORT_SYMBOL(drm_gem_simple_kms_cleanup_shadow_fb);
161 
162 /**
163  * drm_gem_simple_kms_reset_shadow_plane - resets a shadow-buffered plane
164  * @pipe: the simple display pipe
165  *
166  * This function implements struct drm_simple_display_funcs.reset_plane
167  * for shadow-buffered planes.
168  */
169 void drm_gem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe *pipe)
170 {
171 	drm_gem_reset_shadow_plane(&pipe->plane);
172 }
173 EXPORT_SYMBOL(drm_gem_simple_kms_reset_shadow_plane);
174 
175 /**
176  * drm_gem_simple_kms_duplicate_shadow_plane_state - duplicates shadow-buffered plane state
177  * @pipe: the simple display pipe
178  *
179  * This function implements struct drm_simple_display_funcs.duplicate_plane_state
180  * for shadow-buffered planes. It does not duplicate existing mappings of the shadow
181  * buffers. Mappings are maintained during the atomic commit by the plane's prepare_fb
182  * and cleanup_fb helpers.
183  *
184  * Returns:
185  * A pointer to a new plane state on success, or NULL otherwise.
186  */
187 struct drm_plane_state *
188 drm_gem_simple_kms_duplicate_shadow_plane_state(struct drm_simple_display_pipe *pipe)
189 {
190 	return drm_gem_duplicate_shadow_plane_state(&pipe->plane);
191 }
192 EXPORT_SYMBOL(drm_gem_simple_kms_duplicate_shadow_plane_state);
193 
194 /**
195  * drm_gem_simple_kms_destroy_shadow_plane_state - resets shadow-buffered plane state
196  * @pipe: the simple display pipe
197  * @plane_state: the plane state of type struct drm_shadow_plane_state
198  *
199  * This function implements struct drm_simple_display_funcs.destroy_plane_state
200  * for shadow-buffered planes. It expects that mappings of shadow buffers
201  * have been released already.
202  */
203 void drm_gem_simple_kms_destroy_shadow_plane_state(struct drm_simple_display_pipe *pipe,
204 						   struct drm_plane_state *plane_state)
205 {
206 	drm_gem_destroy_shadow_plane_state(&pipe->plane, plane_state);
207 }
208 EXPORT_SYMBOL(drm_gem_simple_kms_destroy_shadow_plane_state);
209