xref: /linux/drivers/gpu/drm/sun4i/sun8i_vi_layer.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
4  */
5 
6 #include <drm/drm_atomic.h>
7 #include <drm/drm_atomic_helper.h>
8 #include <drm/drm_blend.h>
9 #include <drm/drm_crtc.h>
10 #include <drm/drm_fb_dma_helper.h>
11 #include <drm/drm_framebuffer.h>
12 #include <drm/drm_gem_atomic_helper.h>
13 #include <drm/drm_gem_dma_helper.h>
14 #include <drm/drm_print.h>
15 #include <drm/drm_probe_helper.h>
16 
17 #include "sun4i_crtc.h"
18 #include "sun8i_csc.h"
19 #include "sun8i_mixer.h"
20 #include "sun8i_vi_layer.h"
21 #include "sun8i_vi_scaler.h"
22 
23 static void sun8i_vi_layer_disable(struct sun8i_layer *layer)
24 {
25 	u32 ch_base = sun8i_channel_base(layer);
26 
27 	regmap_write(layer->regs,
28 		     SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, layer->overlay), 0);
29 }
30 
31 static void sun8i_vi_layer_update_attributes(struct sun8i_layer *layer,
32 					     struct drm_plane *plane)
33 {
34 	struct drm_plane_state *state = plane->state;
35 	const struct drm_format_info *fmt;
36 	u32 val, ch_base, hw_fmt;
37 
38 	ch_base = sun8i_channel_base(layer);
39 	fmt = state->fb->format;
40 	sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
41 
42 	val = hw_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
43 	if (!fmt->is_yuv)
44 		val |= SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
45 	val |= SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
46 	if (layer->cfg->de_type >= SUN8I_MIXER_DE3) {
47 		val |= SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(state->alpha >> 8);
48 		val |= (state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
49 			SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_PIXEL :
50 			SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_COMBINED;
51 	}
52 
53 	regmap_write(layer->regs,
54 		     SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, layer->overlay), val);
55 
56 	if (layer->cfg->de2_fcc_alpha) {
57 		regmap_write(layer->regs,
58 			     SUN8I_MIXER_FCC_GLOBAL_ALPHA_REG,
59 			     SUN8I_MIXER_FCC_GLOBAL_ALPHA(state->alpha >> 8));
60 	}
61 }
62 
63 static void sun8i_vi_layer_update_coord(struct sun8i_layer *layer,
64 					struct drm_plane *plane)
65 {
66 	struct drm_plane_state *state = plane->state;
67 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(state->crtc);
68 	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(scrtc->engine);
69 	const struct drm_format_info *format = state->fb->format;
70 	u32 src_w, src_h, dst_w, dst_h;
71 	u32 outsize, insize;
72 	u32 hphase, vphase;
73 	u32 hn = 0, hm = 0;
74 	u32 vn = 0, vm = 0;
75 	bool subsampled;
76 	u32 ch_base;
77 
78 	DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
79 			 layer->channel, layer->overlay);
80 
81 	ch_base = sun8i_channel_base(layer);
82 
83 	src_w = drm_rect_width(&state->src) >> 16;
84 	src_h = drm_rect_height(&state->src) >> 16;
85 	dst_w = drm_rect_width(&state->dst);
86 	dst_h = drm_rect_height(&state->dst);
87 
88 	hphase = state->src.x1 & 0xffff;
89 	vphase = state->src.y1 & 0xffff;
90 
91 	/* make coordinates dividable by subsampling factor */
92 	if (format->hsub > 1) {
93 		int mask, remainder;
94 
95 		mask = format->hsub - 1;
96 		remainder = (state->src.x1 >> 16) & mask;
97 		src_w = (src_w + remainder) & ~mask;
98 		hphase += remainder << 16;
99 	}
100 
101 	if (format->vsub > 1) {
102 		int mask, remainder;
103 
104 		mask = format->vsub - 1;
105 		remainder = (state->src.y1 >> 16) & mask;
106 		src_h = (src_h + remainder) & ~mask;
107 		vphase += remainder << 16;
108 	}
109 
110 	insize = SUN8I_MIXER_SIZE(src_w, src_h);
111 	outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
112 
113 	/* Set height and width */
114 	DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
115 			 (state->src.x1 >> 16) & ~(format->hsub - 1),
116 			 (state->src.y1 >> 16) & ~(format->vsub - 1));
117 	DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
118 	regmap_write(layer->regs,
119 		     SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, layer->overlay),
120 		     insize);
121 	regmap_write(layer->regs,
122 		     SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
123 		     insize);
124 
125 	/*
126 	 * Scaler must be enabled for subsampled formats, so it scales
127 	 * chroma to same size as luma.
128 	 */
129 	subsampled = format->hsub > 1 || format->vsub > 1;
130 
131 	if (insize != outsize || subsampled || hphase || vphase) {
132 		unsigned int scanline, required;
133 		struct drm_display_mode *mode;
134 		u32 hscale, vscale, fps;
135 		u64 ability;
136 
137 		DRM_DEBUG_DRIVER("HW scaling is enabled\n");
138 
139 		mode = &plane->state->crtc->state->mode;
140 		fps = (mode->clock * 1000) / (mode->vtotal * mode->htotal);
141 		ability = clk_get_rate(mixer->mod_clk);
142 		/* BSP algorithm assumes 80% efficiency of VI scaler unit */
143 		ability *= 80;
144 		do_div(ability, mode->vdisplay * fps * max(src_w, dst_w));
145 
146 		required = src_h * 100 / dst_h;
147 
148 		if (ability < required) {
149 			DRM_DEBUG_DRIVER("Using vertical coarse scaling\n");
150 			vm = src_h;
151 			vn = (u32)ability * dst_h / 100;
152 			src_h = vn;
153 		}
154 
155 		/* it seems that every RGB scaler has buffer for 2048 pixels */
156 		scanline = subsampled ? layer->cfg->scanline_yuv : 2048;
157 
158 		if (src_w > scanline) {
159 			DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
160 			hm = src_w;
161 			hn = scanline;
162 			src_w = hn;
163 		}
164 
165 		hscale = (src_w << 16) / dst_w;
166 		vscale = (src_h << 16) / dst_h;
167 
168 		sun8i_vi_scaler_setup(layer, src_w, src_h, dst_w, dst_h,
169 				      hscale, vscale, hphase, vphase, format);
170 		sun8i_vi_scaler_enable(layer, true);
171 	} else {
172 		DRM_DEBUG_DRIVER("HW scaling is not needed\n");
173 		sun8i_vi_scaler_enable(layer, false);
174 	}
175 
176 	regmap_write(layer->regs,
177 		     SUN8I_MIXER_CHAN_VI_HDS_Y(ch_base),
178 		     SUN8I_MIXER_CHAN_VI_DS_N(hn) |
179 		     SUN8I_MIXER_CHAN_VI_DS_M(hm));
180 	regmap_write(layer->regs,
181 		     SUN8I_MIXER_CHAN_VI_HDS_UV(ch_base),
182 		     SUN8I_MIXER_CHAN_VI_DS_N(hn) |
183 		     SUN8I_MIXER_CHAN_VI_DS_M(hm));
184 	regmap_write(layer->regs,
185 		     SUN8I_MIXER_CHAN_VI_VDS_Y(ch_base),
186 		     SUN8I_MIXER_CHAN_VI_DS_N(vn) |
187 		     SUN8I_MIXER_CHAN_VI_DS_M(vm));
188 	regmap_write(layer->regs,
189 		     SUN8I_MIXER_CHAN_VI_VDS_UV(ch_base),
190 		     SUN8I_MIXER_CHAN_VI_DS_N(vn) |
191 		     SUN8I_MIXER_CHAN_VI_DS_M(vm));
192 }
193 
194 static void sun8i_vi_layer_update_buffer(struct sun8i_layer *layer,
195 					 struct drm_plane *plane)
196 {
197 	struct drm_plane_state *state = plane->state;
198 	struct drm_framebuffer *fb = state->fb;
199 	const struct drm_format_info *format = fb->format;
200 	dma_addr_t dma_addr;
201 	u32 ch_base;
202 	int i;
203 
204 	ch_base = sun8i_channel_base(layer);
205 
206 	for (i = 0; i < format->num_planes; i++) {
207 		/* Get the start of the displayed memory */
208 		dma_addr = drm_fb_dma_get_gem_addr(fb, state, i);
209 
210 		/* Set the line width */
211 		DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
212 				 i + 1, fb->pitches[i]);
213 		regmap_write(layer->regs,
214 			     SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
215 							     layer->overlay, i),
216 			     fb->pitches[i]);
217 
218 		DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
219 				 i + 1, &dma_addr);
220 
221 		regmap_write(layer->regs,
222 			     SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
223 								 layer->overlay, i),
224 			     lower_32_bits(dma_addr));
225 	}
226 }
227 
228 static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
229 				       struct drm_atomic_state *state)
230 {
231 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
232 										 plane);
233 	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
234 	struct drm_crtc *crtc = new_plane_state->crtc;
235 	struct drm_crtc_state *crtc_state;
236 	const struct drm_format_info *fmt;
237 	int min_scale, max_scale, ret;
238 	u32 hw_fmt;
239 
240 	if (!crtc)
241 		return 0;
242 
243 	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
244 	if (WARN_ON(!crtc_state))
245 		return -EINVAL;
246 
247 	fmt = new_plane_state->fb->format;
248 	ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
249 	if (ret) {
250 		DRM_DEBUG_DRIVER("Invalid plane format\n");
251 		return ret;
252 	}
253 
254 	min_scale = DRM_PLANE_NO_SCALING;
255 	max_scale = DRM_PLANE_NO_SCALING;
256 
257 	if (layer->cfg->scaler_mask & BIT(layer->channel)) {
258 		min_scale = SUN8I_VI_SCALER_SCALE_MIN;
259 		max_scale = SUN8I_VI_SCALER_SCALE_MAX;
260 	}
261 
262 	return drm_atomic_helper_check_plane_state(new_plane_state,
263 						   crtc_state,
264 						   min_scale, max_scale,
265 						   true, true);
266 }
267 
268 static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
269 					 struct drm_atomic_state *state)
270 {
271 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
272 									   plane);
273 	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
274 
275 	if (!new_state->crtc || !new_state->visible) {
276 		sun8i_vi_layer_disable(layer);
277 		return;
278 	}
279 
280 	sun8i_vi_layer_update_attributes(layer, plane);
281 	sun8i_vi_layer_update_coord(layer, plane);
282 	sun8i_csc_config(layer, new_state);
283 	sun8i_vi_layer_update_buffer(layer, plane);
284 }
285 
286 static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
287 	.atomic_check	= sun8i_vi_layer_atomic_check,
288 	.atomic_update	= sun8i_vi_layer_atomic_update,
289 };
290 
291 static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
292 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
293 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
294 	.destroy		= drm_plane_cleanup,
295 	.disable_plane		= drm_atomic_helper_disable_plane,
296 	.reset			= drm_atomic_helper_plane_reset,
297 	.update_plane		= drm_atomic_helper_update_plane,
298 };
299 
300 /*
301  * While DE2 VI layer supports same RGB formats as UI layer, alpha
302  * channel is ignored. This structure lists all unique variants
303  * where alpha channel is replaced with "don't care" (X) channel.
304  */
305 static const u32 sun8i_vi_layer_formats[] = {
306 	DRM_FORMAT_BGR565,
307 	DRM_FORMAT_BGR888,
308 	DRM_FORMAT_BGRX4444,
309 	DRM_FORMAT_BGRX5551,
310 	DRM_FORMAT_BGRX8888,
311 	DRM_FORMAT_RGB565,
312 	DRM_FORMAT_RGB888,
313 	DRM_FORMAT_RGBX4444,
314 	DRM_FORMAT_RGBX5551,
315 	DRM_FORMAT_RGBX8888,
316 	DRM_FORMAT_XBGR1555,
317 	DRM_FORMAT_XBGR4444,
318 	DRM_FORMAT_XBGR8888,
319 	DRM_FORMAT_XRGB1555,
320 	DRM_FORMAT_XRGB4444,
321 	DRM_FORMAT_XRGB8888,
322 
323 	DRM_FORMAT_NV16,
324 	DRM_FORMAT_NV12,
325 	DRM_FORMAT_NV21,
326 	DRM_FORMAT_NV61,
327 	DRM_FORMAT_UYVY,
328 	DRM_FORMAT_VYUY,
329 	DRM_FORMAT_YUYV,
330 	DRM_FORMAT_YVYU,
331 	DRM_FORMAT_YUV411,
332 	DRM_FORMAT_YUV420,
333 	DRM_FORMAT_YUV422,
334 	DRM_FORMAT_YVU411,
335 	DRM_FORMAT_YVU420,
336 	DRM_FORMAT_YVU422,
337 };
338 
339 static const u32 sun8i_vi_layer_de3_formats[] = {
340 	DRM_FORMAT_ABGR1555,
341 	DRM_FORMAT_ABGR2101010,
342 	DRM_FORMAT_ABGR4444,
343 	DRM_FORMAT_ABGR8888,
344 	DRM_FORMAT_ARGB1555,
345 	DRM_FORMAT_ARGB2101010,
346 	DRM_FORMAT_ARGB4444,
347 	DRM_FORMAT_ARGB8888,
348 	DRM_FORMAT_BGR565,
349 	DRM_FORMAT_BGR888,
350 	DRM_FORMAT_BGRA1010102,
351 	DRM_FORMAT_BGRA5551,
352 	DRM_FORMAT_BGRA4444,
353 	DRM_FORMAT_BGRA8888,
354 	DRM_FORMAT_BGRX8888,
355 	DRM_FORMAT_RGB565,
356 	DRM_FORMAT_RGB888,
357 	DRM_FORMAT_RGBA1010102,
358 	DRM_FORMAT_RGBA4444,
359 	DRM_FORMAT_RGBA5551,
360 	DRM_FORMAT_RGBA8888,
361 	DRM_FORMAT_RGBX8888,
362 	DRM_FORMAT_XBGR8888,
363 	DRM_FORMAT_XRGB8888,
364 
365 	DRM_FORMAT_NV16,
366 	DRM_FORMAT_NV12,
367 	DRM_FORMAT_NV21,
368 	DRM_FORMAT_NV61,
369 	DRM_FORMAT_P010,
370 	DRM_FORMAT_P210,
371 	DRM_FORMAT_UYVY,
372 	DRM_FORMAT_VYUY,
373 	DRM_FORMAT_YUYV,
374 	DRM_FORMAT_YVYU,
375 	DRM_FORMAT_YUV411,
376 	DRM_FORMAT_YUV420,
377 	DRM_FORMAT_YUV422,
378 	DRM_FORMAT_YVU411,
379 	DRM_FORMAT_YVU420,
380 	DRM_FORMAT_YVU422,
381 };
382 
383 static const uint64_t sun8i_layer_modifiers[] = {
384 	DRM_FORMAT_MOD_LINEAR,
385 	DRM_FORMAT_MOD_INVALID
386 };
387 
388 struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
389 					    enum drm_plane_type type,
390 					    struct regmap *regs,
391 					    int index, int phy_index,
392 					    int plane_cnt,
393 					    const struct sun8i_layer_cfg *cfg)
394 {
395 	u32 supported_encodings, supported_ranges;
396 	unsigned int format_count;
397 	struct sun8i_layer *layer;
398 	const u32 *formats;
399 	int ret;
400 
401 	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
402 	if (!layer)
403 		return ERR_PTR(-ENOMEM);
404 
405 	layer->type = SUN8I_LAYER_TYPE_VI;
406 	layer->index = index;
407 	layer->channel = phy_index;
408 	layer->overlay = 0;
409 	layer->regs = regs;
410 	layer->cfg = cfg;
411 
412 	if (layer->cfg->de_type >= SUN8I_MIXER_DE3) {
413 		formats = sun8i_vi_layer_de3_formats;
414 		format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
415 	} else {
416 		formats = sun8i_vi_layer_formats;
417 		format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
418 	}
419 
420 	/* possible crtcs are set later */
421 	ret = drm_universal_plane_init(drm, &layer->plane, 0,
422 				       &sun8i_vi_layer_funcs,
423 				       formats, format_count,
424 				       sun8i_layer_modifiers,
425 				       type, NULL);
426 	if (ret) {
427 		dev_err(drm->dev, "Couldn't initialize layer\n");
428 		return ERR_PTR(ret);
429 	}
430 
431 	if (layer->cfg->de2_fcc_alpha || layer->cfg->de_type >= SUN8I_MIXER_DE3) {
432 		ret = drm_plane_create_alpha_property(&layer->plane);
433 		if (ret) {
434 			dev_err(drm->dev, "Couldn't add alpha property\n");
435 			return ERR_PTR(ret);
436 		}
437 	}
438 
439 	ret = drm_plane_create_zpos_property(&layer->plane, index,
440 					     0, plane_cnt - 1);
441 	if (ret) {
442 		dev_err(drm->dev, "Couldn't add zpos property\n");
443 		return ERR_PTR(ret);
444 	}
445 
446 	supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
447 			      BIT(DRM_COLOR_YCBCR_BT709);
448 	if (layer->cfg->de_type >= SUN8I_MIXER_DE3)
449 		supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020);
450 
451 	supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
452 			   BIT(DRM_COLOR_YCBCR_FULL_RANGE);
453 
454 	ret = drm_plane_create_color_properties(&layer->plane,
455 						supported_encodings,
456 						supported_ranges,
457 						DRM_COLOR_YCBCR_BT709,
458 						DRM_COLOR_YCBCR_LIMITED_RANGE);
459 	if (ret) {
460 		dev_err(drm->dev, "Couldn't add encoding and range properties!\n");
461 		return ERR_PTR(ret);
462 	}
463 
464 	drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
465 
466 	return layer;
467 }
468