1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4  * Author: James.Qian.Wang <james.qian.wang@arm.com>
5  *
6  */
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_helper.h>
9 #include <drm/drm_plane_helper.h>
10 #include <drm/drm_print.h>
11 #include "komeda_dev.h"
12 #include "komeda_kms.h"
13 #include "komeda_framebuffer.h"
14 
15 static int
16 komeda_plane_init_data_flow(struct drm_plane_state *st,
17 			    struct komeda_crtc_state *kcrtc_st,
18 			    struct komeda_data_flow_cfg *dflow)
19 {
20 	struct komeda_plane *kplane = to_kplane(st->plane);
21 	struct komeda_plane_state *kplane_st = to_kplane_st(st);
22 	struct drm_framebuffer *fb = st->fb;
23 	const struct komeda_format_caps *caps = to_kfb(fb)->format_caps;
24 	struct komeda_pipeline *pipe = kplane->layer->base.pipeline;
25 
26 	memset(dflow, 0, sizeof(*dflow));
27 
28 	dflow->blending_zorder = st->normalized_zpos;
29 	if (pipe == to_kcrtc(st->crtc)->master)
30 		dflow->blending_zorder -= kcrtc_st->max_slave_zorder;
31 	if (dflow->blending_zorder < 0) {
32 		DRM_DEBUG_ATOMIC("%s zorder:%d < max_slave_zorder: %d.\n",
33 				 st->plane->name, st->normalized_zpos,
34 				 kcrtc_st->max_slave_zorder);
35 		return -EINVAL;
36 	}
37 
38 	dflow->pixel_blend_mode = st->pixel_blend_mode;
39 	dflow->layer_alpha = st->alpha >> 8;
40 
41 	dflow->out_x = st->crtc_x;
42 	dflow->out_y = st->crtc_y;
43 	dflow->out_w = st->crtc_w;
44 	dflow->out_h = st->crtc_h;
45 
46 	dflow->in_x = st->src_x >> 16;
47 	dflow->in_y = st->src_y >> 16;
48 	dflow->in_w = st->src_w >> 16;
49 	dflow->in_h = st->src_h >> 16;
50 
51 	dflow->rot = drm_rotation_simplify(st->rotation, caps->supported_rots);
52 	if (!has_bits(dflow->rot, caps->supported_rots)) {
53 		DRM_DEBUG_ATOMIC("rotation(0x%x) isn't supported by %s.\n",
54 				 dflow->rot,
55 				 komeda_get_format_name(caps->fourcc,
56 							fb->modifier));
57 		return -EINVAL;
58 	}
59 
60 	dflow->en_img_enhancement = !!kplane_st->img_enhancement;
61 	dflow->en_split = !!kplane_st->layer_split;
62 
63 	komeda_complete_data_flow_cfg(dflow, fb);
64 
65 	return 0;
66 }
67 
68 /**
69  * komeda_plane_atomic_check - build input data flow
70  * @plane: DRM plane
71  * @state: the plane state object
72  *
73  * RETURNS:
74  * Zero for success or -errno
75  */
76 static int
77 komeda_plane_atomic_check(struct drm_plane *plane,
78 			  struct drm_plane_state *state)
79 {
80 	struct komeda_plane *kplane = to_kplane(plane);
81 	struct komeda_plane_state *kplane_st = to_kplane_st(state);
82 	struct komeda_layer *layer = kplane->layer;
83 	struct drm_crtc_state *crtc_st;
84 	struct komeda_crtc_state *kcrtc_st;
85 	struct komeda_data_flow_cfg dflow;
86 	int err;
87 
88 	if (!state->crtc || !state->fb)
89 		return 0;
90 
91 	crtc_st = drm_atomic_get_crtc_state(state->state, state->crtc);
92 	if (IS_ERR(crtc_st) || !crtc_st->enable) {
93 		DRM_DEBUG_ATOMIC("Cannot update plane on a disabled CRTC.\n");
94 		return -EINVAL;
95 	}
96 
97 	/* crtc is inactive, skip the resource assignment */
98 	if (!crtc_st->active)
99 		return 0;
100 
101 	kcrtc_st = to_kcrtc_st(crtc_st);
102 
103 	err = komeda_plane_init_data_flow(state, kcrtc_st, &dflow);
104 	if (err)
105 		return err;
106 
107 	if (dflow.en_split)
108 		err = komeda_build_layer_split_data_flow(layer,
109 				kplane_st, kcrtc_st, &dflow);
110 	else
111 		err = komeda_build_layer_data_flow(layer,
112 				kplane_st, kcrtc_st, &dflow);
113 
114 	return err;
115 }
116 
117 /* plane doesn't represent a real HW, so there is no HW update for plane.
118  * komeda handles all the HW update in crtc->atomic_flush
119  */
120 static void
121 komeda_plane_atomic_update(struct drm_plane *plane,
122 			   struct drm_plane_state *old_state)
123 {
124 }
125 
126 static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
127 	.atomic_check	= komeda_plane_atomic_check,
128 	.atomic_update	= komeda_plane_atomic_update,
129 };
130 
131 static void komeda_plane_destroy(struct drm_plane *plane)
132 {
133 	drm_plane_cleanup(plane);
134 
135 	kfree(to_kplane(plane));
136 }
137 
138 static void komeda_plane_reset(struct drm_plane *plane)
139 {
140 	struct komeda_plane_state *state;
141 	struct komeda_plane *kplane = to_kplane(plane);
142 
143 	if (plane->state)
144 		__drm_atomic_helper_plane_destroy_state(plane->state);
145 
146 	kfree(plane->state);
147 	plane->state = NULL;
148 
149 	state = kzalloc(sizeof(*state), GFP_KERNEL);
150 	if (state) {
151 		state->base.rotation = DRM_MODE_ROTATE_0;
152 		state->base.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
153 		state->base.alpha = DRM_BLEND_ALPHA_OPAQUE;
154 		state->base.zpos = kplane->layer->base.id;
155 		state->base.color_encoding = DRM_COLOR_YCBCR_BT601;
156 		state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
157 		plane->state = &state->base;
158 		plane->state->plane = plane;
159 	}
160 }
161 
162 static struct drm_plane_state *
163 komeda_plane_atomic_duplicate_state(struct drm_plane *plane)
164 {
165 	struct komeda_plane_state *new, *old;
166 
167 	if (WARN_ON(!plane->state))
168 		return NULL;
169 
170 	new = kzalloc(sizeof(*new), GFP_KERNEL);
171 	if (!new)
172 		return NULL;
173 
174 	__drm_atomic_helper_plane_duplicate_state(plane, &new->base);
175 
176 	old = to_kplane_st(plane->state);
177 
178 	new->img_enhancement = old->img_enhancement;
179 
180 	return &new->base;
181 }
182 
183 static void
184 komeda_plane_atomic_destroy_state(struct drm_plane *plane,
185 				  struct drm_plane_state *state)
186 {
187 	__drm_atomic_helper_plane_destroy_state(state);
188 	kfree(to_kplane_st(state));
189 }
190 
191 static int
192 komeda_plane_atomic_get_property(struct drm_plane *plane,
193 				 const struct drm_plane_state *state,
194 				 struct drm_property *property,
195 				 uint64_t *val)
196 {
197 	struct komeda_plane *kplane = to_kplane(plane);
198 	struct komeda_plane_state *st = to_kplane_st(state);
199 
200 	if (property == kplane->prop_img_enhancement)
201 		*val = st->img_enhancement;
202 	else if (property == kplane->prop_layer_split)
203 		*val = st->layer_split;
204 	else
205 		return -EINVAL;
206 
207 	return 0;
208 }
209 
210 static int
211 komeda_plane_atomic_set_property(struct drm_plane *plane,
212 				 struct drm_plane_state *state,
213 				 struct drm_property *property,
214 				 uint64_t val)
215 {
216 	struct komeda_plane *kplane = to_kplane(plane);
217 	struct komeda_plane_state *st = to_kplane_st(state);
218 
219 	if (property == kplane->prop_img_enhancement)
220 		st->img_enhancement = !!val;
221 	else if (property == kplane->prop_layer_split)
222 		st->layer_split = !!val;
223 	else
224 		return -EINVAL;
225 
226 	return 0;
227 }
228 
229 static bool
230 komeda_plane_format_mod_supported(struct drm_plane *plane,
231 				  u32 format, u64 modifier)
232 {
233 	struct komeda_dev *mdev = plane->dev->dev_private;
234 	struct komeda_plane *kplane = to_kplane(plane);
235 	u32 layer_type = kplane->layer->layer_type;
236 
237 	return komeda_format_mod_supported(&mdev->fmt_tbl, layer_type,
238 					   format, modifier, 0);
239 }
240 
241 static const struct drm_plane_funcs komeda_plane_funcs = {
242 	.update_plane		= drm_atomic_helper_update_plane,
243 	.disable_plane		= drm_atomic_helper_disable_plane,
244 	.destroy		= komeda_plane_destroy,
245 	.reset			= komeda_plane_reset,
246 	.atomic_duplicate_state	= komeda_plane_atomic_duplicate_state,
247 	.atomic_destroy_state	= komeda_plane_atomic_destroy_state,
248 	.atomic_get_property	= komeda_plane_atomic_get_property,
249 	.atomic_set_property	= komeda_plane_atomic_set_property,
250 	.format_mod_supported	= komeda_plane_format_mod_supported,
251 };
252 
253 static int
254 komeda_plane_create_layer_properties(struct komeda_plane *kplane,
255 				     struct komeda_layer *layer)
256 {
257 	struct drm_device *drm = kplane->base.dev;
258 	struct drm_plane *plane = &kplane->base;
259 	struct drm_property *prop = NULL;
260 
261 	/* property: layer image_enhancement */
262 	if (layer->base.supported_outputs & KOMEDA_PIPELINE_SCALERS) {
263 		prop = drm_property_create_bool(drm, DRM_MODE_PROP_ATOMIC,
264 						"img_enhancement");
265 		if (!prop)
266 			return -ENOMEM;
267 
268 		drm_object_attach_property(&plane->base, prop, 0);
269 		kplane->prop_img_enhancement = prop;
270 	}
271 
272 	/* property: layer split */
273 	if (layer->right) {
274 		prop = drm_property_create_bool(drm, DRM_MODE_PROP_ATOMIC,
275 						"layer_split");
276 		if (!prop)
277 			return -ENOMEM;
278 		kplane->prop_layer_split = prop;
279 		drm_object_attach_property(&plane->base, prop, 0);
280 	}
281 
282 	return 0;
283 }
284 
285 /* for komeda, which is pipeline can be share between crtcs */
286 static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
287 			      struct komeda_pipeline *pipe)
288 {
289 	struct komeda_crtc *crtc;
290 	u32 possible_crtcs = 0;
291 	int i;
292 
293 	for (i = 0; i < kms->n_crtcs; i++) {
294 		crtc = &kms->crtcs[i];
295 
296 		if ((pipe == crtc->master) || (pipe == crtc->slave))
297 			possible_crtcs |= BIT(i);
298 	}
299 
300 	return possible_crtcs;
301 }
302 
303 static void
304 komeda_set_crtc_plane_mask(struct komeda_kms_dev *kms,
305 			   struct komeda_pipeline *pipe,
306 			   struct drm_plane *plane)
307 {
308 	struct komeda_crtc *kcrtc;
309 	int i;
310 
311 	for (i = 0; i < kms->n_crtcs; i++) {
312 		kcrtc = &kms->crtcs[i];
313 
314 		if (pipe == kcrtc->slave)
315 			kcrtc->slave_planes |= BIT(drm_plane_index(plane));
316 	}
317 }
318 
319 /* use Layer0 as primary */
320 static u32 get_plane_type(struct komeda_kms_dev *kms,
321 			  struct komeda_component *c)
322 {
323 	bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
324 
325 	return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
326 }
327 
328 static int komeda_plane_add(struct komeda_kms_dev *kms,
329 			    struct komeda_layer *layer)
330 {
331 	struct komeda_dev *mdev = kms->base.dev_private;
332 	struct komeda_component *c = &layer->base;
333 	struct komeda_plane *kplane;
334 	struct drm_plane *plane;
335 	u32 *formats, n_formats = 0;
336 	int err;
337 
338 	kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
339 	if (!kplane)
340 		return -ENOMEM;
341 
342 	plane = &kplane->base;
343 	kplane->layer = layer;
344 
345 	formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
346 					       layer->layer_type, &n_formats);
347 
348 	err = drm_universal_plane_init(&kms->base, plane,
349 			get_possible_crtcs(kms, c->pipeline),
350 			&komeda_plane_funcs,
351 			formats, n_formats, komeda_supported_modifiers,
352 			get_plane_type(kms, c),
353 			"%s", c->name);
354 
355 	komeda_put_fourcc_list(formats);
356 
357 	if (err)
358 		goto cleanup;
359 
360 	drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
361 
362 	err = drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
363 						 layer->supported_rots);
364 	if (err)
365 		goto cleanup;
366 
367 	err = drm_plane_create_alpha_property(plane);
368 	if (err)
369 		goto cleanup;
370 
371 	err = drm_plane_create_blend_mode_property(plane,
372 			BIT(DRM_MODE_BLEND_PIXEL_NONE) |
373 			BIT(DRM_MODE_BLEND_PREMULTI)   |
374 			BIT(DRM_MODE_BLEND_COVERAGE));
375 	if (err)
376 		goto cleanup;
377 
378 	err = komeda_plane_create_layer_properties(kplane, layer);
379 	if (err)
380 		goto cleanup;
381 
382 	err = drm_plane_create_color_properties(plane,
383 			BIT(DRM_COLOR_YCBCR_BT601) |
384 			BIT(DRM_COLOR_YCBCR_BT709) |
385 			BIT(DRM_COLOR_YCBCR_BT2020),
386 			BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
387 			BIT(DRM_COLOR_YCBCR_FULL_RANGE),
388 			DRM_COLOR_YCBCR_BT601,
389 			DRM_COLOR_YCBCR_LIMITED_RANGE);
390 	if (err)
391 		goto cleanup;
392 
393 	err = drm_plane_create_zpos_property(plane, layer->base.id, 0, 8);
394 	if (err)
395 		goto cleanup;
396 
397 	komeda_set_crtc_plane_mask(kms, c->pipeline, plane);
398 
399 	return 0;
400 cleanup:
401 	komeda_plane_destroy(plane);
402 	return err;
403 }
404 
405 int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
406 {
407 	struct komeda_pipeline *pipe;
408 	int i, j, err;
409 
410 	for (i = 0; i < mdev->n_pipelines; i++) {
411 		pipe = mdev->pipelines[i];
412 
413 		for (j = 0; j < pipe->n_layers; j++) {
414 			err = komeda_plane_add(kms, pipe->layers[j]);
415 			if (err)
416 				return err;
417 		}
418 	}
419 
420 	return 0;
421 }
422