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_state *kcrtc_st;
59 	struct komeda_data_flow_cfg dflow;
60 	int err;
61 
62 	if (!state->crtc || !state->fb)
63 		return 0;
64 
65 	crtc_st = drm_atomic_get_crtc_state(state->state, state->crtc);
66 	if (IS_ERR(crtc_st) || !crtc_st->enable) {
67 		DRM_DEBUG_ATOMIC("Cannot update plane on a disabled CRTC.\n");
68 		return -EINVAL;
69 	}
70 
71 	/* crtc is inactive, skip the resource assignment */
72 	if (!crtc_st->active)
73 		return 0;
74 
75 	kcrtc_st = to_kcrtc_st(crtc_st);
76 
77 	err = komeda_plane_init_data_flow(state, &dflow);
78 	if (err)
79 		return err;
80 
81 	err = komeda_build_layer_data_flow(layer, kplane_st, kcrtc_st, &dflow);
82 
83 	return err;
84 }
85 
86 /* plane doesn't represent a real HW, so there is no HW update for plane.
87  * komeda handles all the HW update in crtc->atomic_flush
88  */
89 static void
90 komeda_plane_atomic_update(struct drm_plane *plane,
91 			   struct drm_plane_state *old_state)
92 {
93 }
94 
95 static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
96 	.atomic_check	= komeda_plane_atomic_check,
97 	.atomic_update	= komeda_plane_atomic_update,
98 };
99 
100 static void komeda_plane_destroy(struct drm_plane *plane)
101 {
102 	drm_plane_cleanup(plane);
103 
104 	kfree(to_kplane(plane));
105 }
106 
107 static void komeda_plane_reset(struct drm_plane *plane)
108 {
109 	struct komeda_plane_state *state;
110 	struct komeda_plane *kplane = to_kplane(plane);
111 
112 	if (plane->state)
113 		__drm_atomic_helper_plane_destroy_state(plane->state);
114 
115 	kfree(plane->state);
116 	plane->state = NULL;
117 
118 	state = kzalloc(sizeof(*state), GFP_KERNEL);
119 	if (state) {
120 		state->base.rotation = DRM_MODE_ROTATE_0;
121 		state->base.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
122 		state->base.alpha = DRM_BLEND_ALPHA_OPAQUE;
123 		state->base.zpos = kplane->layer->base.id;
124 		plane->state = &state->base;
125 		plane->state->plane = plane;
126 	}
127 }
128 
129 static struct drm_plane_state *
130 komeda_plane_atomic_duplicate_state(struct drm_plane *plane)
131 {
132 	struct komeda_plane_state *new;
133 
134 	if (WARN_ON(!plane->state))
135 		return NULL;
136 
137 	new = kzalloc(sizeof(*new), GFP_KERNEL);
138 	if (!new)
139 		return NULL;
140 
141 	__drm_atomic_helper_plane_duplicate_state(plane, &new->base);
142 
143 	return &new->base;
144 }
145 
146 static void
147 komeda_plane_atomic_destroy_state(struct drm_plane *plane,
148 				  struct drm_plane_state *state)
149 {
150 	__drm_atomic_helper_plane_destroy_state(state);
151 	kfree(to_kplane_st(state));
152 }
153 
154 static const struct drm_plane_funcs komeda_plane_funcs = {
155 	.update_plane		= drm_atomic_helper_update_plane,
156 	.disable_plane		= drm_atomic_helper_disable_plane,
157 	.destroy		= komeda_plane_destroy,
158 	.reset			= komeda_plane_reset,
159 	.atomic_duplicate_state	= komeda_plane_atomic_duplicate_state,
160 	.atomic_destroy_state	= komeda_plane_atomic_destroy_state,
161 };
162 
163 /* for komeda, which is pipeline can be share between crtcs */
164 static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
165 			      struct komeda_pipeline *pipe)
166 {
167 	struct komeda_crtc *crtc;
168 	u32 possible_crtcs = 0;
169 	int i;
170 
171 	for (i = 0; i < kms->n_crtcs; i++) {
172 		crtc = &kms->crtcs[i];
173 
174 		if ((pipe == crtc->master) || (pipe == crtc->slave))
175 			possible_crtcs |= BIT(i);
176 	}
177 
178 	return possible_crtcs;
179 }
180 
181 /* use Layer0 as primary */
182 static u32 get_plane_type(struct komeda_kms_dev *kms,
183 			  struct komeda_component *c)
184 {
185 	bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
186 
187 	return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
188 }
189 
190 static int komeda_plane_add(struct komeda_kms_dev *kms,
191 			    struct komeda_layer *layer)
192 {
193 	struct komeda_dev *mdev = kms->base.dev_private;
194 	struct komeda_component *c = &layer->base;
195 	struct komeda_plane *kplane;
196 	struct drm_plane *plane;
197 	u32 *formats, n_formats = 0;
198 	int err;
199 
200 	kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
201 	if (!kplane)
202 		return -ENOMEM;
203 
204 	plane = &kplane->base;
205 	kplane->layer = layer;
206 
207 	formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
208 					       layer->layer_type, &n_formats);
209 
210 	err = drm_universal_plane_init(&kms->base, plane,
211 			get_possible_crtcs(kms, c->pipeline),
212 			&komeda_plane_funcs,
213 			formats, n_formats, NULL,
214 			get_plane_type(kms, c),
215 			"%s", c->name);
216 
217 	komeda_put_fourcc_list(formats);
218 
219 	if (err)
220 		goto cleanup;
221 
222 	drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
223 
224 	return 0;
225 cleanup:
226 	komeda_plane_destroy(plane);
227 	return err;
228 }
229 
230 int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
231 {
232 	struct komeda_pipeline *pipe;
233 	int i, j, err;
234 
235 	for (i = 0; i < mdev->n_pipelines; i++) {
236 		pipe = mdev->pipelines[i];
237 
238 		for (j = 0; j < pipe->n_layers; j++) {
239 			err = komeda_plane_add(kms, pipe->layers[j]);
240 			if (err)
241 				return err;
242 		}
243 	}
244 
245 	return 0;
246 }
247