Linux-libre 5.3.12-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 #include <drm/drmP.h>
15
16 #include "sun8i_vi_layer.h"
17 #include "sun8i_mixer.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 int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
215                                          int overlay, struct drm_plane *plane)
216 {
217         struct drm_plane_state *state = plane->state;
218         const struct de2_fmt_info *fmt_info;
219         u32 val, ch_base;
220
221         ch_base = sun8i_channel_base(mixer, channel);
222
223         fmt_info = sun8i_mixer_format_info(state->fb->format->format);
224         if (!fmt_info) {
225                 DRM_DEBUG_DRIVER("Invalid format\n");
226                 return -EINVAL;
227         }
228
229         val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
230         regmap_update_bits(mixer->engine.regs,
231                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
232                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
233
234         if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
235                 sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_info->csc);
236                 sun8i_csc_enable_ccsc(mixer, channel, true);
237         } else {
238                 sun8i_csc_enable_ccsc(mixer, channel, false);
239         }
240
241         if (fmt_info->rgb)
242                 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
243         else
244                 val = 0;
245
246         regmap_update_bits(mixer->engine.regs,
247                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
248                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
249
250         /* It seems that YUV formats use global alpha setting. */
251         if (mixer->cfg->is_de3)
252                 regmap_update_bits(mixer->engine.regs,
253                                    SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
254                                                                   overlay),
255                                    SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK,
256                                    SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(0xff));
257
258         return 0;
259 }
260
261 static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
262                                         int overlay, struct drm_plane *plane)
263 {
264         struct drm_plane_state *state = plane->state;
265         struct drm_framebuffer *fb = state->fb;
266         const struct drm_format_info *format = fb->format;
267         struct drm_gem_cma_object *gem;
268         u32 dx, dy, src_x, src_y;
269         dma_addr_t paddr;
270         u32 ch_base;
271         int i;
272
273         ch_base = sun8i_channel_base(mixer, channel);
274
275         /* Adjust x and y to be dividable by subsampling factor */
276         src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
277         src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
278
279         for (i = 0; i < format->num_planes; i++) {
280                 /* Get the physical address of the buffer in memory */
281                 gem = drm_fb_cma_get_gem_obj(fb, i);
282
283                 DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
284
285                 /* Compute the start of the displayed memory */
286                 paddr = gem->paddr + fb->offsets[i];
287
288                 dx = src_x;
289                 dy = src_y;
290
291                 if (i > 0) {
292                         dx /= format->hsub;
293                         dy /= format->vsub;
294                 }
295
296                 /* Fixup framebuffer address for src coordinates */
297                 paddr += dx * format->cpp[i];
298                 paddr += dy * fb->pitches[i];
299
300                 /* Set the line width */
301                 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
302                                  i + 1, fb->pitches[i]);
303                 regmap_write(mixer->engine.regs,
304                              SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
305                                                              overlay, i),
306                              fb->pitches[i]);
307
308                 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
309                                  i + 1, &paddr);
310
311                 regmap_write(mixer->engine.regs,
312                              SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
313                                                                  overlay, i),
314                              lower_32_bits(paddr));
315         }
316
317         return 0;
318 }
319
320 static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
321                                        struct drm_plane_state *state)
322 {
323         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
324         struct drm_crtc *crtc = state->crtc;
325         struct drm_crtc_state *crtc_state;
326         int min_scale, max_scale;
327
328         if (!crtc)
329                 return 0;
330
331         crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
332         if (WARN_ON(!crtc_state))
333                 return -EINVAL;
334
335         min_scale = DRM_PLANE_HELPER_NO_SCALING;
336         max_scale = DRM_PLANE_HELPER_NO_SCALING;
337
338         if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
339                 min_scale = SUN8I_VI_SCALER_SCALE_MIN;
340                 max_scale = SUN8I_VI_SCALER_SCALE_MAX;
341         }
342
343         return drm_atomic_helper_check_plane_state(state, crtc_state,
344                                                    min_scale, max_scale,
345                                                    true, true);
346 }
347
348 static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
349                                           struct drm_plane_state *old_state)
350 {
351         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
352         unsigned int old_zpos = old_state->normalized_zpos;
353         struct sun8i_mixer *mixer = layer->mixer;
354
355         sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0,
356                               old_zpos);
357 }
358
359 static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
360                                          struct drm_plane_state *old_state)
361 {
362         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
363         unsigned int zpos = plane->state->normalized_zpos;
364         unsigned int old_zpos = old_state->normalized_zpos;
365         struct sun8i_mixer *mixer = layer->mixer;
366
367         if (!plane->state->visible) {
368                 sun8i_vi_layer_enable(mixer, layer->channel,
369                                       layer->overlay, false, 0, old_zpos);
370                 return;
371         }
372
373         sun8i_vi_layer_update_coord(mixer, layer->channel,
374                                     layer->overlay, plane, zpos);
375         sun8i_vi_layer_update_formats(mixer, layer->channel,
376                                       layer->overlay, plane);
377         sun8i_vi_layer_update_buffer(mixer, layer->channel,
378                                      layer->overlay, plane);
379         sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay,
380                               true, zpos, old_zpos);
381 }
382
383 static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
384         .prepare_fb     = drm_gem_fb_prepare_fb,
385         .atomic_check   = sun8i_vi_layer_atomic_check,
386         .atomic_disable = sun8i_vi_layer_atomic_disable,
387         .atomic_update  = sun8i_vi_layer_atomic_update,
388 };
389
390 static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
391         .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
392         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
393         .destroy                = drm_plane_cleanup,
394         .disable_plane          = drm_atomic_helper_disable_plane,
395         .reset                  = drm_atomic_helper_plane_reset,
396         .update_plane           = drm_atomic_helper_update_plane,
397 };
398
399 /*
400  * While all RGB formats are supported, VI planes don't support
401  * alpha blending, so there is no point having formats with alpha
402  * channel if their opaque analog exist.
403  */
404 static const u32 sun8i_vi_layer_formats[] = {
405         DRM_FORMAT_ABGR1555,
406         DRM_FORMAT_ABGR4444,
407         DRM_FORMAT_ARGB1555,
408         DRM_FORMAT_ARGB4444,
409         DRM_FORMAT_BGR565,
410         DRM_FORMAT_BGR888,
411         DRM_FORMAT_BGRA5551,
412         DRM_FORMAT_BGRA4444,
413         DRM_FORMAT_BGRX8888,
414         DRM_FORMAT_RGB565,
415         DRM_FORMAT_RGB888,
416         DRM_FORMAT_RGBA4444,
417         DRM_FORMAT_RGBA5551,
418         DRM_FORMAT_RGBX8888,
419         DRM_FORMAT_XBGR8888,
420         DRM_FORMAT_XRGB8888,
421
422         DRM_FORMAT_NV16,
423         DRM_FORMAT_NV12,
424         DRM_FORMAT_NV21,
425         DRM_FORMAT_NV61,
426         DRM_FORMAT_UYVY,
427         DRM_FORMAT_VYUY,
428         DRM_FORMAT_YUYV,
429         DRM_FORMAT_YVYU,
430         DRM_FORMAT_YUV411,
431         DRM_FORMAT_YUV420,
432         DRM_FORMAT_YUV422,
433         DRM_FORMAT_YUV444,
434         DRM_FORMAT_YVU411,
435         DRM_FORMAT_YVU420,
436         DRM_FORMAT_YVU422,
437         DRM_FORMAT_YVU444,
438 };
439
440 struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
441                                                struct sun8i_mixer *mixer,
442                                                int index)
443 {
444         struct sun8i_vi_layer *layer;
445         unsigned int plane_cnt;
446         int ret;
447
448         layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
449         if (!layer)
450                 return ERR_PTR(-ENOMEM);
451
452         /* possible crtcs are set later */
453         ret = drm_universal_plane_init(drm, &layer->plane, 0,
454                                        &sun8i_vi_layer_funcs,
455                                        sun8i_vi_layer_formats,
456                                        ARRAY_SIZE(sun8i_vi_layer_formats),
457                                        NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
458         if (ret) {
459                 dev_err(drm->dev, "Couldn't initialize layer\n");
460                 return ERR_PTR(ret);
461         }
462
463         plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
464
465         ret = drm_plane_create_zpos_property(&layer->plane, index,
466                                              0, plane_cnt - 1);
467         if (ret) {
468                 dev_err(drm->dev, "Couldn't add zpos property\n");
469                 return ERR_PTR(ret);
470         }
471
472         drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
473         layer->mixer = mixer;
474         layer->channel = index;
475         layer->overlay = 0;
476
477         return layer;
478 }