Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / sun4i / sun8i_vi_layer.c
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_crtc.h>
9 #include <drm/drm_fb_cma_helper.h>
10 #include <drm/drm_gem_cma_helper.h>
11 #include <drm/drm_gem_framebuffer_helper.h>
12 #include <drm/drm_plane_helper.h>
13 #include <drm/drm_probe_helper.h>
14
15 #include "sun8i_vi_layer.h"
16 #include "sun8i_mixer.h"
17 #include "sun8i_vi_scaler.h"
18
19 static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
20                                   int overlay, bool enable, unsigned int zpos,
21                                   unsigned int old_zpos)
22 {
23         u32 val, bld_base, ch_base;
24
25         bld_base = sun8i_blender_base(mixer);
26         ch_base = sun8i_channel_base(mixer, channel);
27
28         DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
29                          enable ? "En" : "Dis", channel, overlay);
30
31         if (enable)
32                 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
33         else
34                 val = 0;
35
36         regmap_update_bits(mixer->engine.regs,
37                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
38                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
39
40         if (!enable || zpos != old_zpos) {
41                 regmap_update_bits(mixer->engine.regs,
42                                    SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
43                                    SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
44                                    0);
45
46                 regmap_update_bits(mixer->engine.regs,
47                                    SUN8I_MIXER_BLEND_ROUTE(bld_base),
48                                    SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
49                                    0);
50         }
51
52         if (enable) {
53                 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
54
55                 regmap_update_bits(mixer->engine.regs,
56                                    SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
57                                    val, val);
58
59                 val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
60
61                 regmap_update_bits(mixer->engine.regs,
62                                    SUN8I_MIXER_BLEND_ROUTE(bld_base),
63                                    SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
64                                    val);
65         }
66 }
67
68 static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
69                                        int overlay, struct drm_plane *plane,
70                                        unsigned int zpos)
71 {
72         struct drm_plane_state *state = plane->state;
73         const struct drm_format_info *format = state->fb->format;
74         u32 src_w, src_h, dst_w, dst_h;
75         u32 bld_base, ch_base;
76         u32 outsize, insize;
77         u32 hphase, vphase;
78         u32 hn = 0, hm = 0;
79         u32 vn = 0, vm = 0;
80         bool subsampled;
81
82         DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
83                          channel, overlay);
84
85         bld_base = sun8i_blender_base(mixer);
86         ch_base = sun8i_channel_base(mixer, channel);
87
88         src_w = drm_rect_width(&state->src) >> 16;
89         src_h = drm_rect_height(&state->src) >> 16;
90         dst_w = drm_rect_width(&state->dst);
91         dst_h = drm_rect_height(&state->dst);
92
93         hphase = state->src.x1 & 0xffff;
94         vphase = state->src.y1 & 0xffff;
95
96         /* make coordinates dividable by subsampling factor */
97         if (format->hsub > 1) {
98                 int mask, remainder;
99
100                 mask = format->hsub - 1;
101                 remainder = (state->src.x1 >> 16) & mask;
102                 src_w = (src_w + remainder) & ~mask;
103                 hphase += remainder << 16;
104         }
105
106         if (format->vsub > 1) {
107                 int mask, remainder;
108
109                 mask = format->vsub - 1;
110                 remainder = (state->src.y1 >> 16) & mask;
111                 src_h = (src_h + remainder) & ~mask;
112                 vphase += remainder << 16;
113         }
114
115         insize = SUN8I_MIXER_SIZE(src_w, src_h);
116         outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
117
118         /* Set height and width */
119         DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
120                          (state->src.x1 >> 16) & ~(format->hsub - 1),
121                          (state->src.y1 >> 16) & ~(format->vsub - 1));
122         DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
123         regmap_write(mixer->engine.regs,
124                      SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, overlay),
125                      insize);
126         regmap_write(mixer->engine.regs,
127                      SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
128                      insize);
129
130         /*
131          * Scaler must be enabled for subsampled formats, so it scales
132          * chroma to same size as luma.
133          */
134         subsampled = format->hsub > 1 || format->vsub > 1;
135
136         if (insize != outsize || subsampled || hphase || vphase) {
137                 unsigned int scanline, required;
138                 struct drm_display_mode *mode;
139                 u32 hscale, vscale, fps;
140                 u64 ability;
141
142                 DRM_DEBUG_DRIVER("HW scaling is enabled\n");
143
144                 mode = &plane->state->crtc->state->mode;
145                 fps = (mode->clock * 1000) / (mode->vtotal * mode->htotal);
146                 ability = clk_get_rate(mixer->mod_clk);
147                 /* BSP algorithm assumes 80% efficiency of VI scaler unit */
148                 ability *= 80;
149                 do_div(ability, mode->vdisplay * fps * max(src_w, dst_w));
150
151                 required = src_h * 100 / dst_h;
152
153                 if (ability < required) {
154                         DRM_DEBUG_DRIVER("Using vertical coarse scaling\n");
155                         vm = src_h;
156                         vn = (u32)ability * dst_h / 100;
157                         src_h = vn;
158                 }
159
160                 /* it seems that every RGB scaler has buffer for 2048 pixels */
161                 scanline = subsampled ? mixer->cfg->scanline_yuv : 2048;
162
163                 if (src_w > scanline) {
164                         DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
165                         hm = src_w;
166                         hn = scanline;
167                         src_w = hn;
168                 }
169
170                 hscale = (src_w << 16) / dst_w;
171                 vscale = (src_h << 16) / dst_h;
172
173                 sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
174                                       dst_h, hscale, vscale, hphase, vphase,
175                                       format);
176                 sun8i_vi_scaler_enable(mixer, channel, true);
177         } else {
178                 DRM_DEBUG_DRIVER("HW scaling is not needed\n");
179                 sun8i_vi_scaler_enable(mixer, channel, false);
180         }
181
182         regmap_write(mixer->engine.regs,
183                      SUN8I_MIXER_CHAN_VI_HDS_Y(ch_base),
184                      SUN8I_MIXER_CHAN_VI_DS_N(hn) |
185                      SUN8I_MIXER_CHAN_VI_DS_M(hm));
186         regmap_write(mixer->engine.regs,
187                      SUN8I_MIXER_CHAN_VI_HDS_UV(ch_base),
188                      SUN8I_MIXER_CHAN_VI_DS_N(hn) |
189                      SUN8I_MIXER_CHAN_VI_DS_M(hm));
190         regmap_write(mixer->engine.regs,
191                      SUN8I_MIXER_CHAN_VI_VDS_Y(ch_base),
192                      SUN8I_MIXER_CHAN_VI_DS_N(vn) |
193                      SUN8I_MIXER_CHAN_VI_DS_M(vm));
194         regmap_write(mixer->engine.regs,
195                      SUN8I_MIXER_CHAN_VI_VDS_UV(ch_base),
196                      SUN8I_MIXER_CHAN_VI_DS_N(vn) |
197                      SUN8I_MIXER_CHAN_VI_DS_M(vm));
198
199         /* Set base coordinates */
200         DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
201                          state->dst.x1, state->dst.y1);
202         DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
203         regmap_write(mixer->engine.regs,
204                      SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
205                      SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
206         regmap_write(mixer->engine.regs,
207                      SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
208                      outsize);
209
210         return 0;
211 }
212
213 static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
214                                          int overlay, struct drm_plane *plane)
215 {
216         struct drm_plane_state *state = plane->state;
217         const struct de2_fmt_info *fmt_info;
218         u32 val, ch_base;
219
220         ch_base = sun8i_channel_base(mixer, channel);
221
222         fmt_info = sun8i_mixer_format_info(state->fb->format->format);
223         if (!fmt_info) {
224                 DRM_DEBUG_DRIVER("Invalid format\n");
225                 return -EINVAL;
226         }
227
228         val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
229         regmap_update_bits(mixer->engine.regs,
230                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
231                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
232
233         if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
234                 sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_info->csc,
235                                                 state->color_encoding,
236                                                 state->color_range);
237                 sun8i_csc_enable_ccsc(mixer, channel, true);
238         } else {
239                 sun8i_csc_enable_ccsc(mixer, channel, false);
240         }
241
242         if (fmt_info->rgb)
243                 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
244         else
245                 val = 0;
246
247         regmap_update_bits(mixer->engine.regs,
248                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
249                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
250
251         /* It seems that YUV formats use global alpha setting. */
252         if (mixer->cfg->is_de3)
253                 regmap_update_bits(mixer->engine.regs,
254                                    SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
255                                                                   overlay),
256                                    SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK,
257                                    SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(0xff));
258
259         return 0;
260 }
261
262 static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
263                                         int overlay, struct drm_plane *plane)
264 {
265         struct drm_plane_state *state = plane->state;
266         struct drm_framebuffer *fb = state->fb;
267         const struct drm_format_info *format = fb->format;
268         struct drm_gem_cma_object *gem;
269         u32 dx, dy, src_x, src_y;
270         dma_addr_t paddr;
271         u32 ch_base;
272         int i;
273
274         ch_base = sun8i_channel_base(mixer, channel);
275
276         /* Adjust x and y to be dividable by subsampling factor */
277         src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
278         src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
279
280         for (i = 0; i < format->num_planes; i++) {
281                 /* Get the physical address of the buffer in memory */
282                 gem = drm_fb_cma_get_gem_obj(fb, i);
283
284                 DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
285
286                 /* Compute the start of the displayed memory */
287                 paddr = gem->paddr + fb->offsets[i];
288
289                 dx = src_x;
290                 dy = src_y;
291
292                 if (i > 0) {
293                         dx /= format->hsub;
294                         dy /= format->vsub;
295                 }
296
297                 /* Fixup framebuffer address for src coordinates */
298                 paddr += dx * format->cpp[i];
299                 paddr += dy * fb->pitches[i];
300
301                 /* Set the line width */
302                 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
303                                  i + 1, fb->pitches[i]);
304                 regmap_write(mixer->engine.regs,
305                              SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
306                                                              overlay, i),
307                              fb->pitches[i]);
308
309                 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
310                                  i + 1, &paddr);
311
312                 regmap_write(mixer->engine.regs,
313                              SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
314                                                                  overlay, i),
315                              lower_32_bits(paddr));
316         }
317
318         return 0;
319 }
320
321 static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
322                                        struct drm_plane_state *state)
323 {
324         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
325         struct drm_crtc *crtc = state->crtc;
326         struct drm_crtc_state *crtc_state;
327         int min_scale, max_scale;
328
329         if (!crtc)
330                 return 0;
331
332         crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
333         if (WARN_ON(!crtc_state))
334                 return -EINVAL;
335
336         min_scale = DRM_PLANE_HELPER_NO_SCALING;
337         max_scale = DRM_PLANE_HELPER_NO_SCALING;
338
339         if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
340                 min_scale = SUN8I_VI_SCALER_SCALE_MIN;
341                 max_scale = SUN8I_VI_SCALER_SCALE_MAX;
342         }
343
344         return drm_atomic_helper_check_plane_state(state, crtc_state,
345                                                    min_scale, max_scale,
346                                                    true, true);
347 }
348
349 static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
350                                           struct drm_plane_state *old_state)
351 {
352         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
353         unsigned int old_zpos = old_state->normalized_zpos;
354         struct sun8i_mixer *mixer = layer->mixer;
355
356         sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0,
357                               old_zpos);
358 }
359
360 static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
361                                          struct drm_plane_state *old_state)
362 {
363         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
364         unsigned int zpos = plane->state->normalized_zpos;
365         unsigned int old_zpos = old_state->normalized_zpos;
366         struct sun8i_mixer *mixer = layer->mixer;
367
368         if (!plane->state->visible) {
369                 sun8i_vi_layer_enable(mixer, layer->channel,
370                                       layer->overlay, false, 0, old_zpos);
371                 return;
372         }
373
374         sun8i_vi_layer_update_coord(mixer, layer->channel,
375                                     layer->overlay, plane, zpos);
376         sun8i_vi_layer_update_formats(mixer, layer->channel,
377                                       layer->overlay, plane);
378         sun8i_vi_layer_update_buffer(mixer, layer->channel,
379                                      layer->overlay, plane);
380         sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay,
381                               true, zpos, old_zpos);
382 }
383
384 static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
385         .prepare_fb     = drm_gem_fb_prepare_fb,
386         .atomic_check   = sun8i_vi_layer_atomic_check,
387         .atomic_disable = sun8i_vi_layer_atomic_disable,
388         .atomic_update  = sun8i_vi_layer_atomic_update,
389 };
390
391 static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
392         .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
393         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
394         .destroy                = drm_plane_cleanup,
395         .disable_plane          = drm_atomic_helper_disable_plane,
396         .reset                  = drm_atomic_helper_plane_reset,
397         .update_plane           = drm_atomic_helper_update_plane,
398 };
399
400 /*
401  * While DE2 VI layer supports same RGB formats as UI layer, alpha
402  * channel is ignored. This structure lists all unique variants
403  * where alpha channel is replaced with "don't care" (X) channel.
404  */
405 static const u32 sun8i_vi_layer_formats[] = {
406         DRM_FORMAT_BGR565,
407         DRM_FORMAT_BGR888,
408         DRM_FORMAT_BGRX4444,
409         DRM_FORMAT_BGRX5551,
410         DRM_FORMAT_BGRX8888,
411         DRM_FORMAT_RGB565,
412         DRM_FORMAT_RGB888,
413         DRM_FORMAT_RGBX4444,
414         DRM_FORMAT_RGBX5551,
415         DRM_FORMAT_RGBX8888,
416         DRM_FORMAT_XBGR1555,
417         DRM_FORMAT_XBGR4444,
418         DRM_FORMAT_XBGR8888,
419         DRM_FORMAT_XRGB1555,
420         DRM_FORMAT_XRGB4444,
421         DRM_FORMAT_XRGB8888,
422
423         DRM_FORMAT_NV16,
424         DRM_FORMAT_NV12,
425         DRM_FORMAT_NV21,
426         DRM_FORMAT_NV61,
427         DRM_FORMAT_UYVY,
428         DRM_FORMAT_VYUY,
429         DRM_FORMAT_YUYV,
430         DRM_FORMAT_YVYU,
431         DRM_FORMAT_YUV411,
432         DRM_FORMAT_YUV420,
433         DRM_FORMAT_YUV422,
434         DRM_FORMAT_YVU411,
435         DRM_FORMAT_YVU420,
436         DRM_FORMAT_YVU422,
437 };
438
439 static const u32 sun8i_vi_layer_de3_formats[] = {
440         DRM_FORMAT_ABGR1555,
441         DRM_FORMAT_ABGR2101010,
442         DRM_FORMAT_ABGR4444,
443         DRM_FORMAT_ABGR8888,
444         DRM_FORMAT_ARGB1555,
445         DRM_FORMAT_ARGB2101010,
446         DRM_FORMAT_ARGB4444,
447         DRM_FORMAT_ARGB8888,
448         DRM_FORMAT_BGR565,
449         DRM_FORMAT_BGR888,
450         DRM_FORMAT_BGRA1010102,
451         DRM_FORMAT_BGRA5551,
452         DRM_FORMAT_BGRA4444,
453         DRM_FORMAT_BGRA8888,
454         DRM_FORMAT_BGRX8888,
455         DRM_FORMAT_RGB565,
456         DRM_FORMAT_RGB888,
457         DRM_FORMAT_RGBA1010102,
458         DRM_FORMAT_RGBA4444,
459         DRM_FORMAT_RGBA5551,
460         DRM_FORMAT_RGBA8888,
461         DRM_FORMAT_RGBX8888,
462         DRM_FORMAT_XBGR8888,
463         DRM_FORMAT_XRGB8888,
464
465         DRM_FORMAT_NV16,
466         DRM_FORMAT_NV12,
467         DRM_FORMAT_NV21,
468         DRM_FORMAT_NV61,
469         DRM_FORMAT_P010,
470         DRM_FORMAT_P210,
471         DRM_FORMAT_UYVY,
472         DRM_FORMAT_VYUY,
473         DRM_FORMAT_YUYV,
474         DRM_FORMAT_YVYU,
475         DRM_FORMAT_YUV411,
476         DRM_FORMAT_YUV420,
477         DRM_FORMAT_YUV422,
478         DRM_FORMAT_YVU411,
479         DRM_FORMAT_YVU420,
480         DRM_FORMAT_YVU422,
481 };
482
483 struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
484                                                struct sun8i_mixer *mixer,
485                                                int index)
486 {
487         u32 supported_encodings, supported_ranges;
488         unsigned int plane_cnt, format_count;
489         struct sun8i_vi_layer *layer;
490         const u32 *formats;
491         int ret;
492
493         layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
494         if (!layer)
495                 return ERR_PTR(-ENOMEM);
496
497         if (mixer->cfg->is_de3) {
498                 formats = sun8i_vi_layer_de3_formats;
499                 format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
500         } else {
501                 formats = sun8i_vi_layer_formats;
502                 format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
503         }
504
505         /* possible crtcs are set later */
506         ret = drm_universal_plane_init(drm, &layer->plane, 0,
507                                        &sun8i_vi_layer_funcs,
508                                        formats, format_count,
509                                        NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
510         if (ret) {
511                 dev_err(drm->dev, "Couldn't initialize layer\n");
512                 return ERR_PTR(ret);
513         }
514
515         plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
516
517         ret = drm_plane_create_zpos_property(&layer->plane, index,
518                                              0, plane_cnt - 1);
519         if (ret) {
520                 dev_err(drm->dev, "Couldn't add zpos property\n");
521                 return ERR_PTR(ret);
522         }
523
524         supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
525                               BIT(DRM_COLOR_YCBCR_BT709);
526
527         supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
528                            BIT(DRM_COLOR_YCBCR_FULL_RANGE);
529
530         ret = drm_plane_create_color_properties(&layer->plane,
531                                                 supported_encodings,
532                                                 supported_ranges,
533                                                 DRM_COLOR_YCBCR_BT709,
534                                                 DRM_COLOR_YCBCR_LIMITED_RANGE);
535         if (ret) {
536                 dev_err(drm->dev, "Couldn't add encoding and range properties!\n");
537                 return ERR_PTR(ret);
538         }
539
540         drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
541         layer->mixer = mixer;
542         layer->channel = index;
543         layer->overlay = 0;
544
545         return layer;
546 }