]> Git Repo - linux.git/blob - drivers/gpu/drm/sun4i/sun8i_vi_layer.c
drm/amdgpu: revert "add new bo flag that indicates BOs don't need fallback (v2)"
[linux.git] / drivers / gpu / drm / sun4i / sun8i_vi_layer.c
1 /*
2  * Copyright (C) Jernej Skrabec <[email protected]>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  */
9
10 #include <drm/drm_atomic.h>
11 #include <drm/drm_atomic_helper.h>
12 #include <drm/drm_crtc.h>
13 #include <drm/drm_crtc_helper.h>
14 #include <drm/drm_fb_cma_helper.h>
15 #include <drm/drm_gem_cma_helper.h>
16 #include <drm/drm_plane_helper.h>
17 #include <drm/drmP.h>
18
19 #include "sun8i_vi_layer.h"
20 #include "sun8i_mixer.h"
21 #include "sun8i_vi_scaler.h"
22
23 static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
24                                   int overlay, bool enable)
25 {
26         u32 val;
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(channel, overlay),
38                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
39
40         if (enable)
41                 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel);
42         else
43                 val = 0;
44
45         regmap_update_bits(mixer->engine.regs,
46                            SUN8I_MIXER_BLEND_PIPE_CTL,
47                            SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val);
48 }
49
50 static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
51                                        int overlay, struct drm_plane *plane)
52 {
53         struct drm_plane_state *state = plane->state;
54         const struct drm_format_info *format = state->fb->format;
55         u32 src_w, src_h, dst_w, dst_h;
56         u32 outsize, insize;
57         u32 hphase, vphase;
58         bool subsampled;
59
60         DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
61                          channel, overlay);
62
63         src_w = drm_rect_width(&state->src) >> 16;
64         src_h = drm_rect_height(&state->src) >> 16;
65         dst_w = drm_rect_width(&state->dst);
66         dst_h = drm_rect_height(&state->dst);
67
68         hphase = state->src.x1 & 0xffff;
69         vphase = state->src.y1 & 0xffff;
70
71         /* make coordinates dividable by subsampling factor */
72         if (format->hsub > 1) {
73                 int mask, remainder;
74
75                 mask = format->hsub - 1;
76                 remainder = (state->src.x1 >> 16) & mask;
77                 src_w = (src_w + remainder) & ~mask;
78                 hphase += remainder << 16;
79         }
80
81         if (format->vsub > 1) {
82                 int mask, remainder;
83
84                 mask = format->vsub - 1;
85                 remainder = (state->src.y1 >> 16) & mask;
86                 src_h = (src_h + remainder) & ~mask;
87                 vphase += remainder << 16;
88         }
89
90         insize = SUN8I_MIXER_SIZE(src_w, src_h);
91         outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
92
93         /* Set height and width */
94         DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
95                          (state->src.x1 >> 16) & ~(format->hsub - 1),
96                          (state->src.y1 >> 16) & ~(format->vsub - 1));
97         DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
98         regmap_write(mixer->engine.regs,
99                      SUN8I_MIXER_CHAN_VI_LAYER_SIZE(channel, overlay),
100                      insize);
101         regmap_write(mixer->engine.regs,
102                      SUN8I_MIXER_CHAN_VI_OVL_SIZE(channel),
103                      insize);
104
105         /*
106          * Scaler must be enabled for subsampled formats, so it scales
107          * chroma to same size as luma.
108          */
109         subsampled = format->hsub > 1 || format->vsub > 1;
110
111         if (insize != outsize || subsampled || hphase || vphase) {
112                 u32 hscale, vscale;
113
114                 DRM_DEBUG_DRIVER("HW scaling is enabled\n");
115
116                 hscale = state->src_w / state->crtc_w;
117                 vscale = state->src_h / state->crtc_h;
118
119                 sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
120                                       dst_h, hscale, vscale, hphase, vphase,
121                                       format);
122                 sun8i_vi_scaler_enable(mixer, channel, true);
123         } else {
124                 DRM_DEBUG_DRIVER("HW scaling is not needed\n");
125                 sun8i_vi_scaler_enable(mixer, channel, false);
126         }
127
128         /* Set base coordinates */
129         DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
130                          state->dst.x1, state->dst.y1);
131         DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
132         regmap_write(mixer->engine.regs,
133                      SUN8I_MIXER_BLEND_ATTR_COORD(channel),
134                      SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
135         regmap_write(mixer->engine.regs,
136                      SUN8I_MIXER_BLEND_ATTR_INSIZE(channel),
137                      outsize);
138
139         return 0;
140 }
141
142 static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
143                                          int overlay, struct drm_plane *plane)
144 {
145         struct drm_plane_state *state = plane->state;
146         const struct de2_fmt_info *fmt_info;
147         u32 val;
148
149         fmt_info = sun8i_mixer_format_info(state->fb->format->format);
150         if (!fmt_info) {
151                 DRM_DEBUG_DRIVER("Invalid format\n");
152                 return -EINVAL;
153         }
154
155         val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
156         regmap_update_bits(mixer->engine.regs,
157                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
158                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
159
160         if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
161                 sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_info->csc);
162                 sun8i_csc_enable_ccsc(mixer, channel, true);
163         } else {
164                 sun8i_csc_enable_ccsc(mixer, channel, false);
165         }
166
167         if (fmt_info->rgb)
168                 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
169         else
170                 val = 0;
171
172         regmap_update_bits(mixer->engine.regs,
173                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
174                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
175
176         return 0;
177 }
178
179 static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
180                                         int overlay, struct drm_plane *plane)
181 {
182         struct drm_plane_state *state = plane->state;
183         struct drm_framebuffer *fb = state->fb;
184         const struct drm_format_info *format = fb->format;
185         struct drm_gem_cma_object *gem;
186         u32 dx, dy, src_x, src_y;
187         dma_addr_t paddr;
188         int i;
189
190         /* Adjust x and y to be dividable by subsampling factor */
191         src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
192         src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
193
194         for (i = 0; i < format->num_planes; i++) {
195                 /* Get the physical address of the buffer in memory */
196                 gem = drm_fb_cma_get_gem_obj(fb, i);
197
198                 DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
199
200                 /* Compute the start of the displayed memory */
201                 paddr = gem->paddr + fb->offsets[i];
202
203                 dx = src_x;
204                 dy = src_y;
205
206                 if (i > 0) {
207                         dx /= format->hsub;
208                         dy /= format->vsub;
209                 }
210
211                 /* Fixup framebuffer address for src coordinates */
212                 paddr += dx * format->cpp[i];
213                 paddr += dy * fb->pitches[i];
214
215                 /* Set the line width */
216                 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
217                                  i + 1, fb->pitches[i]);
218                 regmap_write(mixer->engine.regs,
219                              SUN8I_MIXER_CHAN_VI_LAYER_PITCH(channel,
220                                                              overlay, i),
221                fb->pitches[i]);
222
223                 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
224                                  i + 1, &paddr);
225
226                 regmap_write(mixer->engine.regs,
227                              SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(channel,
228                                                                  overlay, i),
229                lower_32_bits(paddr));
230         }
231
232         return 0;
233 }
234
235 static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
236                                        struct drm_plane_state *state)
237 {
238         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
239         struct drm_crtc *crtc = state->crtc;
240         struct drm_crtc_state *crtc_state;
241         int min_scale, max_scale;
242
243         if (!crtc)
244                 return 0;
245
246         crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
247         if (WARN_ON(!crtc_state))
248                 return -EINVAL;
249
250         min_scale = DRM_PLANE_HELPER_NO_SCALING;
251         max_scale = DRM_PLANE_HELPER_NO_SCALING;
252
253         if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
254                 min_scale = SUN8I_VI_SCALER_SCALE_MIN;
255                 max_scale = SUN8I_VI_SCALER_SCALE_MAX;
256         }
257
258         return drm_atomic_helper_check_plane_state(state, crtc_state,
259                                                    min_scale, max_scale,
260                                                    true, true);
261 }
262
263 static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
264                                           struct drm_plane_state *old_state)
265 {
266         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
267         struct sun8i_mixer *mixer = layer->mixer;
268
269         sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false);
270 }
271
272 static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
273                                          struct drm_plane_state *old_state)
274 {
275         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
276         struct sun8i_mixer *mixer = layer->mixer;
277
278         if (!plane->state->visible) {
279                 sun8i_vi_layer_enable(mixer, layer->channel,
280                                       layer->overlay, false);
281                 return;
282         }
283
284         sun8i_vi_layer_update_coord(mixer, layer->channel,
285                                     layer->overlay, plane);
286         sun8i_vi_layer_update_formats(mixer, layer->channel,
287                                       layer->overlay, plane);
288         sun8i_vi_layer_update_buffer(mixer, layer->channel,
289                                      layer->overlay, plane);
290         sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, true);
291 }
292
293 static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
294         .atomic_check   = sun8i_vi_layer_atomic_check,
295         .atomic_disable = sun8i_vi_layer_atomic_disable,
296         .atomic_update  = sun8i_vi_layer_atomic_update,
297 };
298
299 static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
300         .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
301         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
302         .destroy                = drm_plane_cleanup,
303         .disable_plane          = drm_atomic_helper_disable_plane,
304         .reset                  = drm_atomic_helper_plane_reset,
305         .update_plane           = drm_atomic_helper_update_plane,
306 };
307
308 /*
309  * While all RGB formats are supported, VI planes don't support
310  * alpha blending, so there is no point having formats with alpha
311  * channel if their opaque analog exist.
312  */
313 static const u32 sun8i_vi_layer_formats[] = {
314         DRM_FORMAT_ABGR1555,
315         DRM_FORMAT_ABGR4444,
316         DRM_FORMAT_ARGB1555,
317         DRM_FORMAT_ARGB4444,
318         DRM_FORMAT_BGR565,
319         DRM_FORMAT_BGR888,
320         DRM_FORMAT_BGRA5551,
321         DRM_FORMAT_BGRA4444,
322         DRM_FORMAT_BGRX8888,
323         DRM_FORMAT_RGB565,
324         DRM_FORMAT_RGB888,
325         DRM_FORMAT_RGBA4444,
326         DRM_FORMAT_RGBA5551,
327         DRM_FORMAT_RGBX8888,
328         DRM_FORMAT_XBGR8888,
329         DRM_FORMAT_XRGB8888,
330
331         DRM_FORMAT_NV16,
332         DRM_FORMAT_NV12,
333         DRM_FORMAT_NV21,
334         DRM_FORMAT_NV61,
335         DRM_FORMAT_UYVY,
336         DRM_FORMAT_VYUY,
337         DRM_FORMAT_YUYV,
338         DRM_FORMAT_YVYU,
339         DRM_FORMAT_YUV411,
340         DRM_FORMAT_YUV420,
341         DRM_FORMAT_YUV422,
342         DRM_FORMAT_YUV444,
343         DRM_FORMAT_YVU411,
344         DRM_FORMAT_YVU420,
345         DRM_FORMAT_YVU422,
346         DRM_FORMAT_YVU444,
347 };
348
349 struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
350                                                struct sun8i_mixer *mixer,
351                                                int index)
352 {
353         struct sun8i_vi_layer *layer;
354         int ret;
355
356         layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
357         if (!layer)
358                 return ERR_PTR(-ENOMEM);
359
360         /* possible crtcs are set later */
361         ret = drm_universal_plane_init(drm, &layer->plane, 0,
362                                        &sun8i_vi_layer_funcs,
363                                        sun8i_vi_layer_formats,
364                                        ARRAY_SIZE(sun8i_vi_layer_formats),
365                                        NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
366         if (ret) {
367                 dev_err(drm->dev, "Couldn't initialize layer\n");
368                 return ERR_PTR(ret);
369         }
370
371         /* fixed zpos for now */
372         ret = drm_plane_create_zpos_immutable_property(&layer->plane, index);
373         if (ret) {
374                 dev_err(drm->dev, "Couldn't add zpos property\n");
375                 return ERR_PTR(ret);
376         }
377
378         drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
379         layer->mixer = mixer;
380         layer->channel = index;
381         layer->overlay = 0;
382
383         return layer;
384 }
This page took 0.05558 seconds and 4 git commands to generate.