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