161f1c4a8Sjames qian wang (Arm Technology China) // SPDX-License-Identifier: GPL-2.0
261f1c4a8Sjames qian wang (Arm Technology China) /*
361f1c4a8Sjames qian wang (Arm Technology China)  * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
461f1c4a8Sjames qian wang (Arm Technology China)  * Author: James.Qian.Wang <james.qian.wang@arm.com>
561f1c4a8Sjames qian wang (Arm Technology China)  *
661f1c4a8Sjames qian wang (Arm Technology China)  */
761f1c4a8Sjames qian wang (Arm Technology China) #include <drm/drm_atomic.h>
861f1c4a8Sjames qian wang (Arm Technology China) #include <drm/drm_atomic_helper.h>
961f1c4a8Sjames qian wang (Arm Technology China) #include <drm/drm_plane_helper.h>
109e560309Sjames qian wang (Arm Technology China) #include <drm/drm_print.h>
1161f1c4a8Sjames qian wang (Arm Technology China) #include "komeda_dev.h"
1261f1c4a8Sjames qian wang (Arm Technology China) #include "komeda_kms.h"
1361f1c4a8Sjames qian wang (Arm Technology China) 
149e560309Sjames qian wang (Arm Technology China) static int
159e560309Sjames qian wang (Arm Technology China) komeda_plane_init_data_flow(struct drm_plane_state *st,
169e560309Sjames qian wang (Arm Technology China) 			    struct komeda_data_flow_cfg *dflow)
179e560309Sjames qian wang (Arm Technology China) {
189e560309Sjames qian wang (Arm Technology China) 	struct drm_framebuffer *fb = st->fb;
199e560309Sjames qian wang (Arm Technology China) 
209e560309Sjames qian wang (Arm Technology China) 	memset(dflow, 0, sizeof(*dflow));
219e560309Sjames qian wang (Arm Technology China) 
229e560309Sjames qian wang (Arm Technology China) 	dflow->blending_zorder = st->zpos;
239e560309Sjames qian wang (Arm Technology China) 
249e560309Sjames qian wang (Arm Technology China) 	/* if format doesn't have alpha, fix blend mode to PIXEL_NONE */
259e560309Sjames qian wang (Arm Technology China) 	dflow->pixel_blend_mode = fb->format->has_alpha ?
269e560309Sjames qian wang (Arm Technology China) 		st->pixel_blend_mode : DRM_MODE_BLEND_PIXEL_NONE;
279e560309Sjames qian wang (Arm Technology China) 	dflow->layer_alpha = st->alpha >> 8;
289e560309Sjames qian wang (Arm Technology China) 
299e560309Sjames qian wang (Arm Technology China) 	dflow->out_x = st->crtc_x;
309e560309Sjames qian wang (Arm Technology China) 	dflow->out_y = st->crtc_y;
319e560309Sjames qian wang (Arm Technology China) 	dflow->out_w = st->crtc_w;
329e560309Sjames qian wang (Arm Technology China) 	dflow->out_h = st->crtc_h;
339e560309Sjames qian wang (Arm Technology China) 
349e560309Sjames qian wang (Arm Technology China) 	dflow->in_x = st->src_x >> 16;
359e560309Sjames qian wang (Arm Technology China) 	dflow->in_y = st->src_y >> 16;
369e560309Sjames qian wang (Arm Technology China) 	dflow->in_w = st->src_w >> 16;
379e560309Sjames qian wang (Arm Technology China) 	dflow->in_h = st->src_h >> 16;
389e560309Sjames qian wang (Arm Technology China) 
39d92b66b8Sjames qian wang (Arm Technology China) 	komeda_complete_data_flow_cfg(dflow);
40502932a0Sjames qian wang (Arm Technology China) 
419e560309Sjames qian wang (Arm Technology China) 	return 0;
429e560309Sjames qian wang (Arm Technology China) }
439e560309Sjames qian wang (Arm Technology China) 
448c919745Sjames qian wang (Arm Technology China) /**
458c919745Sjames qian wang (Arm Technology China)  * komeda_plane_atomic_check - build input data flow
468c919745Sjames qian wang (Arm Technology China)  * @plane: DRM plane
478c919745Sjames qian wang (Arm Technology China)  * @state: the plane state object
488c919745Sjames qian wang (Arm Technology China)  *
498c919745Sjames qian wang (Arm Technology China)  * RETURNS:
508c919745Sjames qian wang (Arm Technology China)  * Zero for success or -errno
518c919745Sjames qian wang (Arm Technology China)  */
5215e9122dSjames qian wang (Arm Technology China) static int
5315e9122dSjames qian wang (Arm Technology China) komeda_plane_atomic_check(struct drm_plane *plane,
549e560309Sjames qian wang (Arm Technology China) 			  struct drm_plane_state *state)
559e560309Sjames qian wang (Arm Technology China) {
569e560309Sjames qian wang (Arm Technology China) 	struct komeda_plane *kplane = to_kplane(plane);
579e560309Sjames qian wang (Arm Technology China) 	struct komeda_plane_state *kplane_st = to_kplane_st(state);
589e560309Sjames qian wang (Arm Technology China) 	struct komeda_layer *layer = kplane->layer;
599e560309Sjames qian wang (Arm Technology China) 	struct drm_crtc_state *crtc_st;
609e560309Sjames qian wang (Arm Technology China) 	struct komeda_crtc_state *kcrtc_st;
619e560309Sjames qian wang (Arm Technology China) 	struct komeda_data_flow_cfg dflow;
629e560309Sjames qian wang (Arm Technology China) 	int err;
639e560309Sjames qian wang (Arm Technology China) 
649e560309Sjames qian wang (Arm Technology China) 	if (!state->crtc || !state->fb)
659e560309Sjames qian wang (Arm Technology China) 		return 0;
669e560309Sjames qian wang (Arm Technology China) 
679e560309Sjames qian wang (Arm Technology China) 	crtc_st = drm_atomic_get_crtc_state(state->state, state->crtc);
686d10dc61SDan Carpenter 	if (IS_ERR(crtc_st) || !crtc_st->enable) {
699e560309Sjames qian wang (Arm Technology China) 		DRM_DEBUG_ATOMIC("Cannot update plane on a disabled CRTC.\n");
709e560309Sjames qian wang (Arm Technology China) 		return -EINVAL;
719e560309Sjames qian wang (Arm Technology China) 	}
729e560309Sjames qian wang (Arm Technology China) 
739e560309Sjames qian wang (Arm Technology China) 	/* crtc is inactive, skip the resource assignment */
749e560309Sjames qian wang (Arm Technology China) 	if (!crtc_st->active)
759e560309Sjames qian wang (Arm Technology China) 		return 0;
769e560309Sjames qian wang (Arm Technology China) 
779e560309Sjames qian wang (Arm Technology China) 	kcrtc_st = to_kcrtc_st(crtc_st);
789e560309Sjames qian wang (Arm Technology China) 
799e560309Sjames qian wang (Arm Technology China) 	err = komeda_plane_init_data_flow(state, &dflow);
809e560309Sjames qian wang (Arm Technology China) 	if (err)
819e560309Sjames qian wang (Arm Technology China) 		return err;
829e560309Sjames qian wang (Arm Technology China) 
839e560309Sjames qian wang (Arm Technology China) 	err = komeda_build_layer_data_flow(layer, kplane_st, kcrtc_st, &dflow);
849e560309Sjames qian wang (Arm Technology China) 
859e560309Sjames qian wang (Arm Technology China) 	return err;
869e560309Sjames qian wang (Arm Technology China) }
879e560309Sjames qian wang (Arm Technology China) 
889e560309Sjames qian wang (Arm Technology China) /* plane doesn't represent a real HW, so there is no HW update for plane.
899e560309Sjames qian wang (Arm Technology China)  * komeda handles all the HW update in crtc->atomic_flush
909e560309Sjames qian wang (Arm Technology China)  */
9115e9122dSjames qian wang (Arm Technology China) static void
9215e9122dSjames qian wang (Arm Technology China) komeda_plane_atomic_update(struct drm_plane *plane,
939e560309Sjames qian wang (Arm Technology China) 			   struct drm_plane_state *old_state)
949e560309Sjames qian wang (Arm Technology China) {
959e560309Sjames qian wang (Arm Technology China) }
969e560309Sjames qian wang (Arm Technology China) 
9761f1c4a8Sjames qian wang (Arm Technology China) static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
989e560309Sjames qian wang (Arm Technology China) 	.atomic_check	= komeda_plane_atomic_check,
999e560309Sjames qian wang (Arm Technology China) 	.atomic_update	= komeda_plane_atomic_update,
10061f1c4a8Sjames qian wang (Arm Technology China) };
10161f1c4a8Sjames qian wang (Arm Technology China) 
10261f1c4a8Sjames qian wang (Arm Technology China) static void komeda_plane_destroy(struct drm_plane *plane)
10361f1c4a8Sjames qian wang (Arm Technology China) {
10461f1c4a8Sjames qian wang (Arm Technology China) 	drm_plane_cleanup(plane);
10561f1c4a8Sjames qian wang (Arm Technology China) 
10661f1c4a8Sjames qian wang (Arm Technology China) 	kfree(to_kplane(plane));
10761f1c4a8Sjames qian wang (Arm Technology China) }
10861f1c4a8Sjames qian wang (Arm Technology China) 
1099e560309Sjames qian wang (Arm Technology China) static void komeda_plane_reset(struct drm_plane *plane)
1109e560309Sjames qian wang (Arm Technology China) {
1119e560309Sjames qian wang (Arm Technology China) 	struct komeda_plane_state *state;
1129e560309Sjames qian wang (Arm Technology China) 	struct komeda_plane *kplane = to_kplane(plane);
1139e560309Sjames qian wang (Arm Technology China) 
1149e560309Sjames qian wang (Arm Technology China) 	if (plane->state)
1159e560309Sjames qian wang (Arm Technology China) 		__drm_atomic_helper_plane_destroy_state(plane->state);
1169e560309Sjames qian wang (Arm Technology China) 
1179e560309Sjames qian wang (Arm Technology China) 	kfree(plane->state);
1189e560309Sjames qian wang (Arm Technology China) 	plane->state = NULL;
1199e560309Sjames qian wang (Arm Technology China) 
1209e560309Sjames qian wang (Arm Technology China) 	state = kzalloc(sizeof(*state), GFP_KERNEL);
1219e560309Sjames qian wang (Arm Technology China) 	if (state) {
1229e560309Sjames qian wang (Arm Technology China) 		state->base.rotation = DRM_MODE_ROTATE_0;
1239e560309Sjames qian wang (Arm Technology China) 		state->base.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
1249e560309Sjames qian wang (Arm Technology China) 		state->base.alpha = DRM_BLEND_ALPHA_OPAQUE;
1259e560309Sjames qian wang (Arm Technology China) 		state->base.zpos = kplane->layer->base.id;
1269e560309Sjames qian wang (Arm Technology China) 		plane->state = &state->base;
1279e560309Sjames qian wang (Arm Technology China) 		plane->state->plane = plane;
1289e560309Sjames qian wang (Arm Technology China) 	}
1299e560309Sjames qian wang (Arm Technology China) }
1309e560309Sjames qian wang (Arm Technology China) 
1319e560309Sjames qian wang (Arm Technology China) static struct drm_plane_state *
1329e560309Sjames qian wang (Arm Technology China) komeda_plane_atomic_duplicate_state(struct drm_plane *plane)
1339e560309Sjames qian wang (Arm Technology China) {
1349e560309Sjames qian wang (Arm Technology China) 	struct komeda_plane_state *new;
1359e560309Sjames qian wang (Arm Technology China) 
1369e560309Sjames qian wang (Arm Technology China) 	if (WARN_ON(!plane->state))
1379e560309Sjames qian wang (Arm Technology China) 		return NULL;
1389e560309Sjames qian wang (Arm Technology China) 
1399e560309Sjames qian wang (Arm Technology China) 	new = kzalloc(sizeof(*new), GFP_KERNEL);
1409e560309Sjames qian wang (Arm Technology China) 	if (!new)
1419e560309Sjames qian wang (Arm Technology China) 		return NULL;
1429e560309Sjames qian wang (Arm Technology China) 
1439e560309Sjames qian wang (Arm Technology China) 	__drm_atomic_helper_plane_duplicate_state(plane, &new->base);
1449e560309Sjames qian wang (Arm Technology China) 
1459e560309Sjames qian wang (Arm Technology China) 	return &new->base;
1469e560309Sjames qian wang (Arm Technology China) }
1479e560309Sjames qian wang (Arm Technology China) 
1489e560309Sjames qian wang (Arm Technology China) static void
1499e560309Sjames qian wang (Arm Technology China) komeda_plane_atomic_destroy_state(struct drm_plane *plane,
1509e560309Sjames qian wang (Arm Technology China) 				  struct drm_plane_state *state)
1519e560309Sjames qian wang (Arm Technology China) {
1529e560309Sjames qian wang (Arm Technology China) 	__drm_atomic_helper_plane_destroy_state(state);
1539e560309Sjames qian wang (Arm Technology China) 	kfree(to_kplane_st(state));
1549e560309Sjames qian wang (Arm Technology China) }
1559e560309Sjames qian wang (Arm Technology China) 
15665ad2392Sjames qian wang (Arm Technology China) static bool
15765ad2392Sjames qian wang (Arm Technology China) komeda_plane_format_mod_supported(struct drm_plane *plane,
15865ad2392Sjames qian wang (Arm Technology China) 				  u32 format, u64 modifier)
15965ad2392Sjames qian wang (Arm Technology China) {
16065ad2392Sjames qian wang (Arm Technology China) 	struct komeda_dev *mdev = plane->dev->dev_private;
16165ad2392Sjames qian wang (Arm Technology China) 	struct komeda_plane *kplane = to_kplane(plane);
16265ad2392Sjames qian wang (Arm Technology China) 	u32 layer_type = kplane->layer->layer_type;
16365ad2392Sjames qian wang (Arm Technology China) 
16465ad2392Sjames qian wang (Arm Technology China) 	return komeda_format_mod_supported(&mdev->fmt_tbl, layer_type,
16565ad2392Sjames qian wang (Arm Technology China) 					   format, modifier);
16665ad2392Sjames qian wang (Arm Technology China) }
16765ad2392Sjames qian wang (Arm Technology China) 
16861f1c4a8Sjames qian wang (Arm Technology China) static const struct drm_plane_funcs komeda_plane_funcs = {
1699e560309Sjames qian wang (Arm Technology China) 	.update_plane		= drm_atomic_helper_update_plane,
1709e560309Sjames qian wang (Arm Technology China) 	.disable_plane		= drm_atomic_helper_disable_plane,
1719e560309Sjames qian wang (Arm Technology China) 	.destroy		= komeda_plane_destroy,
1729e560309Sjames qian wang (Arm Technology China) 	.reset			= komeda_plane_reset,
1739e560309Sjames qian wang (Arm Technology China) 	.atomic_duplicate_state	= komeda_plane_atomic_duplicate_state,
1749e560309Sjames qian wang (Arm Technology China) 	.atomic_destroy_state	= komeda_plane_atomic_destroy_state,
17565ad2392Sjames qian wang (Arm Technology China) 	.format_mod_supported	= komeda_plane_format_mod_supported,
17661f1c4a8Sjames qian wang (Arm Technology China) };
17761f1c4a8Sjames qian wang (Arm Technology China) 
17861f1c4a8Sjames qian wang (Arm Technology China) /* for komeda, which is pipeline can be share between crtcs */
17961f1c4a8Sjames qian wang (Arm Technology China) static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
18061f1c4a8Sjames qian wang (Arm Technology China) 			      struct komeda_pipeline *pipe)
18161f1c4a8Sjames qian wang (Arm Technology China) {
18261f1c4a8Sjames qian wang (Arm Technology China) 	struct komeda_crtc *crtc;
18361f1c4a8Sjames qian wang (Arm Technology China) 	u32 possible_crtcs = 0;
18461f1c4a8Sjames qian wang (Arm Technology China) 	int i;
18561f1c4a8Sjames qian wang (Arm Technology China) 
18661f1c4a8Sjames qian wang (Arm Technology China) 	for (i = 0; i < kms->n_crtcs; i++) {
18761f1c4a8Sjames qian wang (Arm Technology China) 		crtc = &kms->crtcs[i];
18861f1c4a8Sjames qian wang (Arm Technology China) 
18961f1c4a8Sjames qian wang (Arm Technology China) 		if ((pipe == crtc->master) || (pipe == crtc->slave))
19061f1c4a8Sjames qian wang (Arm Technology China) 			possible_crtcs |= BIT(i);
19161f1c4a8Sjames qian wang (Arm Technology China) 	}
19261f1c4a8Sjames qian wang (Arm Technology China) 
19361f1c4a8Sjames qian wang (Arm Technology China) 	return possible_crtcs;
19461f1c4a8Sjames qian wang (Arm Technology China) }
19561f1c4a8Sjames qian wang (Arm Technology China) 
19661f1c4a8Sjames qian wang (Arm Technology China) /* use Layer0 as primary */
19761f1c4a8Sjames qian wang (Arm Technology China) static u32 get_plane_type(struct komeda_kms_dev *kms,
19861f1c4a8Sjames qian wang (Arm Technology China) 			  struct komeda_component *c)
19961f1c4a8Sjames qian wang (Arm Technology China) {
20061f1c4a8Sjames qian wang (Arm Technology China) 	bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
20161f1c4a8Sjames qian wang (Arm Technology China) 
20261f1c4a8Sjames qian wang (Arm Technology China) 	return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
20361f1c4a8Sjames qian wang (Arm Technology China) }
20461f1c4a8Sjames qian wang (Arm Technology China) 
20561f1c4a8Sjames qian wang (Arm Technology China) static int komeda_plane_add(struct komeda_kms_dev *kms,
20661f1c4a8Sjames qian wang (Arm Technology China) 			    struct komeda_layer *layer)
20761f1c4a8Sjames qian wang (Arm Technology China) {
20861f1c4a8Sjames qian wang (Arm Technology China) 	struct komeda_dev *mdev = kms->base.dev_private;
20961f1c4a8Sjames qian wang (Arm Technology China) 	struct komeda_component *c = &layer->base;
21061f1c4a8Sjames qian wang (Arm Technology China) 	struct komeda_plane *kplane;
21161f1c4a8Sjames qian wang (Arm Technology China) 	struct drm_plane *plane;
21261f1c4a8Sjames qian wang (Arm Technology China) 	u32 *formats, n_formats = 0;
21361f1c4a8Sjames qian wang (Arm Technology China) 	int err;
21461f1c4a8Sjames qian wang (Arm Technology China) 
21561f1c4a8Sjames qian wang (Arm Technology China) 	kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
21661f1c4a8Sjames qian wang (Arm Technology China) 	if (!kplane)
21761f1c4a8Sjames qian wang (Arm Technology China) 		return -ENOMEM;
21861f1c4a8Sjames qian wang (Arm Technology China) 
21961f1c4a8Sjames qian wang (Arm Technology China) 	plane = &kplane->base;
22061f1c4a8Sjames qian wang (Arm Technology China) 	kplane->layer = layer;
22161f1c4a8Sjames qian wang (Arm Technology China) 
22261f1c4a8Sjames qian wang (Arm Technology China) 	formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
22361f1c4a8Sjames qian wang (Arm Technology China) 					       layer->layer_type, &n_formats);
22461f1c4a8Sjames qian wang (Arm Technology China) 
22561f1c4a8Sjames qian wang (Arm Technology China) 	err = drm_universal_plane_init(&kms->base, plane,
22661f1c4a8Sjames qian wang (Arm Technology China) 			get_possible_crtcs(kms, c->pipeline),
22761f1c4a8Sjames qian wang (Arm Technology China) 			&komeda_plane_funcs,
22865ad2392Sjames qian wang (Arm Technology China) 			formats, n_formats, komeda_supported_modifiers,
22961f1c4a8Sjames qian wang (Arm Technology China) 			get_plane_type(kms, c),
23061f1c4a8Sjames qian wang (Arm Technology China) 			"%s", c->name);
23161f1c4a8Sjames qian wang (Arm Technology China) 
23261f1c4a8Sjames qian wang (Arm Technology China) 	komeda_put_fourcc_list(formats);
23361f1c4a8Sjames qian wang (Arm Technology China) 
23461f1c4a8Sjames qian wang (Arm Technology China) 	if (err)
23561f1c4a8Sjames qian wang (Arm Technology China) 		goto cleanup;
23661f1c4a8Sjames qian wang (Arm Technology China) 
23761f1c4a8Sjames qian wang (Arm Technology China) 	drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
23861f1c4a8Sjames qian wang (Arm Technology China) 
23961f1c4a8Sjames qian wang (Arm Technology China) 	return 0;
24061f1c4a8Sjames qian wang (Arm Technology China) cleanup:
24161f1c4a8Sjames qian wang (Arm Technology China) 	komeda_plane_destroy(plane);
24261f1c4a8Sjames qian wang (Arm Technology China) 	return err;
24361f1c4a8Sjames qian wang (Arm Technology China) }
24461f1c4a8Sjames qian wang (Arm Technology China) 
24561f1c4a8Sjames qian wang (Arm Technology China) int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
24661f1c4a8Sjames qian wang (Arm Technology China) {
24761f1c4a8Sjames qian wang (Arm Technology China) 	struct komeda_pipeline *pipe;
24861f1c4a8Sjames qian wang (Arm Technology China) 	int i, j, err;
24961f1c4a8Sjames qian wang (Arm Technology China) 
25061f1c4a8Sjames qian wang (Arm Technology China) 	for (i = 0; i < mdev->n_pipelines; i++) {
25161f1c4a8Sjames qian wang (Arm Technology China) 		pipe = mdev->pipelines[i];
25261f1c4a8Sjames qian wang (Arm Technology China) 
25361f1c4a8Sjames qian wang (Arm Technology China) 		for (j = 0; j < pipe->n_layers; j++) {
25461f1c4a8Sjames qian wang (Arm Technology China) 			err = komeda_plane_add(kms, pipe->layers[j]);
25561f1c4a8Sjames qian wang (Arm Technology China) 			if (err)
25661f1c4a8Sjames qian wang (Arm Technology China) 				return err;
25761f1c4a8Sjames qian wang (Arm Technology China) 		}
25861f1c4a8Sjames qian wang (Arm Technology China) 	}
25961f1c4a8Sjames qian wang (Arm Technology China) 
26061f1c4a8Sjames qian wang (Arm Technology China) 	return 0;
26161f1c4a8Sjames qian wang (Arm Technology China) }
262