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 
14 static int
15 komeda_plane_init_data_flow(struct drm_plane_state *st,
16 			    struct komeda_data_flow_cfg *dflow)
17 {
18 	struct drm_framebuffer *fb = st->fb;
19 
20 	memset(dflow, 0, sizeof(*dflow));
21 
22 	dflow->blending_zorder = st->zpos;
23 
24 	/* if format doesn't have alpha, fix blend mode to PIXEL_NONE */
25 	dflow->pixel_blend_mode = fb->format->has_alpha ?
26 		st->pixel_blend_mode : DRM_MODE_BLEND_PIXEL_NONE;
27 	dflow->layer_alpha = st->alpha >> 8;
28 
29 	dflow->out_x = st->crtc_x;
30 	dflow->out_y = st->crtc_y;
31 	dflow->out_w = st->crtc_w;
32 	dflow->out_h = st->crtc_h;
33 
34 	dflow->in_x = st->src_x >> 16;
35 	dflow->in_y = st->src_y >> 16;
36 	dflow->in_w = st->src_w >> 16;
37 	dflow->in_h = st->src_h >> 16;
38 
39 	return 0;
40 }
41 
42 /**
43  * komeda_plane_atomic_check - build input data flow
44  * @plane: DRM plane
45  * @state: the plane state object
46  *
47  * RETURNS:
48  * Zero for success or -errno
49  */
50 static int
51 komeda_plane_atomic_check(struct drm_plane *plane,
52 			  struct drm_plane_state *state)
53 {
54 	struct komeda_plane *kplane = to_kplane(plane);
55 	struct komeda_plane_state *kplane_st = to_kplane_st(state);
56 	struct komeda_layer *layer = kplane->layer;
57 	struct drm_crtc_state *crtc_st;
58 	struct komeda_crtc *kcrtc;
59 	struct komeda_crtc_state *kcrtc_st;
60 	struct komeda_data_flow_cfg dflow;
61 	int err;
62 
63 	if (!state->crtc || !state->fb)
64 		return 0;
65 
66 	crtc_st = drm_atomic_get_crtc_state(state->state, state->crtc);
67 	if (!crtc_st->enable) {
68 		DRM_DEBUG_ATOMIC("Cannot update plane on a disabled CRTC.\n");
69 		return -EINVAL;
70 	}
71 
72 	/* crtc is inactive, skip the resource assignment */
73 	if (!crtc_st->active)
74 		return 0;
75 
76 	kcrtc = to_kcrtc(state->crtc);
77 	kcrtc_st = to_kcrtc_st(crtc_st);
78 
79 	err = komeda_plane_init_data_flow(state, &dflow);
80 	if (err)
81 		return err;
82 
83 	err = komeda_build_layer_data_flow(layer, kplane_st, kcrtc_st, &dflow);
84 
85 	return err;
86 }
87 
88 /* plane doesn't represent a real HW, so there is no HW update for plane.
89  * komeda handles all the HW update in crtc->atomic_flush
90  */
91 static void
92 komeda_plane_atomic_update(struct drm_plane *plane,
93 			   struct drm_plane_state *old_state)
94 {
95 }
96 
97 static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
98 	.atomic_check	= komeda_plane_atomic_check,
99 	.atomic_update	= komeda_plane_atomic_update,
100 };
101 
102 static void komeda_plane_destroy(struct drm_plane *plane)
103 {
104 	drm_plane_cleanup(plane);
105 
106 	kfree(to_kplane(plane));
107 }
108 
109 static void komeda_plane_reset(struct drm_plane *plane)
110 {
111 	struct komeda_plane_state *state;
112 	struct komeda_plane *kplane = to_kplane(plane);
113 
114 	if (plane->state)
115 		__drm_atomic_helper_plane_destroy_state(plane->state);
116 
117 	kfree(plane->state);
118 	plane->state = NULL;
119 
120 	state = kzalloc(sizeof(*state), GFP_KERNEL);
121 	if (state) {
122 		state->base.rotation = DRM_MODE_ROTATE_0;
123 		state->base.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
124 		state->base.alpha = DRM_BLEND_ALPHA_OPAQUE;
125 		state->base.zpos = kplane->layer->base.id;
126 		plane->state = &state->base;
127 		plane->state->plane = plane;
128 	}
129 }
130 
131 static struct drm_plane_state *
132 komeda_plane_atomic_duplicate_state(struct drm_plane *plane)
133 {
134 	struct komeda_plane_state *new;
135 
136 	if (WARN_ON(!plane->state))
137 		return NULL;
138 
139 	new = kzalloc(sizeof(*new), GFP_KERNEL);
140 	if (!new)
141 		return NULL;
142 
143 	__drm_atomic_helper_plane_duplicate_state(plane, &new->base);
144 
145 	return &new->base;
146 }
147 
148 static void
149 komeda_plane_atomic_destroy_state(struct drm_plane *plane,
150 				  struct drm_plane_state *state)
151 {
152 	__drm_atomic_helper_plane_destroy_state(state);
153 	kfree(to_kplane_st(state));
154 }
155 
156 static const struct drm_plane_funcs komeda_plane_funcs = {
157 	.update_plane		= drm_atomic_helper_update_plane,
158 	.disable_plane		= drm_atomic_helper_disable_plane,
159 	.destroy		= komeda_plane_destroy,
160 	.reset			= komeda_plane_reset,
161 	.atomic_duplicate_state	= komeda_plane_atomic_duplicate_state,
162 	.atomic_destroy_state	= komeda_plane_atomic_destroy_state,
163 };
164 
165 /* for komeda, which is pipeline can be share between crtcs */
166 static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
167 			      struct komeda_pipeline *pipe)
168 {
169 	struct komeda_crtc *crtc;
170 	u32 possible_crtcs = 0;
171 	int i;
172 
173 	for (i = 0; i < kms->n_crtcs; i++) {
174 		crtc = &kms->crtcs[i];
175 
176 		if ((pipe == crtc->master) || (pipe == crtc->slave))
177 			possible_crtcs |= BIT(i);
178 	}
179 
180 	return possible_crtcs;
181 }
182 
183 /* use Layer0 as primary */
184 static u32 get_plane_type(struct komeda_kms_dev *kms,
185 			  struct komeda_component *c)
186 {
187 	bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
188 
189 	return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
190 }
191 
192 static int komeda_plane_add(struct komeda_kms_dev *kms,
193 			    struct komeda_layer *layer)
194 {
195 	struct komeda_dev *mdev = kms->base.dev_private;
196 	struct komeda_component *c = &layer->base;
197 	struct komeda_plane *kplane;
198 	struct drm_plane *plane;
199 	u32 *formats, n_formats = 0;
200 	int err;
201 
202 	kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
203 	if (!kplane)
204 		return -ENOMEM;
205 
206 	plane = &kplane->base;
207 	kplane->layer = layer;
208 
209 	formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
210 					       layer->layer_type, &n_formats);
211 
212 	err = drm_universal_plane_init(&kms->base, plane,
213 			get_possible_crtcs(kms, c->pipeline),
214 			&komeda_plane_funcs,
215 			formats, n_formats, NULL,
216 			get_plane_type(kms, c),
217 			"%s", c->name);
218 
219 	komeda_put_fourcc_list(formats);
220 
221 	if (err)
222 		goto cleanup;
223 
224 	drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
225 
226 	return 0;
227 cleanup:
228 	komeda_plane_destroy(plane);
229 	return err;
230 }
231 
232 int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
233 {
234 	struct komeda_pipeline *pipe;
235 	int i, j, err;
236 
237 	for (i = 0; i < mdev->n_pipelines; i++) {
238 		pipe = mdev->pipelines[i];
239 
240 		for (j = 0; j < pipe->n_layers; j++) {
241 			err = komeda_plane_add(kms, pipe->layers[j]);
242 			if (err)
243 				return err;
244 		}
245 	}
246 
247 	return 0;
248 }
249