]> Git Repo - linux.git/blob - drivers/gpu/drm/armada/armada_plane.c
Merge tag 'fpga-fixes-for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mdf...
[linux.git] / drivers / gpu / drm / armada / armada_plane.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2012 Russell King
4  *  Rewritten from the dovefb driver, and Armada510 manuals.
5  */
6 #include <drm/drmP.h>
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_helper.h>
9 #include <drm/drm_plane_helper.h>
10 #include "armada_crtc.h"
11 #include "armada_drm.h"
12 #include "armada_fb.h"
13 #include "armada_gem.h"
14 #include "armada_hw.h"
15 #include "armada_plane.h"
16 #include "armada_trace.h"
17
18 static const uint32_t armada_primary_formats[] = {
19         DRM_FORMAT_UYVY,
20         DRM_FORMAT_YUYV,
21         DRM_FORMAT_VYUY,
22         DRM_FORMAT_YVYU,
23         DRM_FORMAT_ARGB8888,
24         DRM_FORMAT_ABGR8888,
25         DRM_FORMAT_XRGB8888,
26         DRM_FORMAT_XBGR8888,
27         DRM_FORMAT_RGB888,
28         DRM_FORMAT_BGR888,
29         DRM_FORMAT_ARGB1555,
30         DRM_FORMAT_ABGR1555,
31         DRM_FORMAT_RGB565,
32         DRM_FORMAT_BGR565,
33 };
34
35 void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
36         u16 pitches[3], bool interlaced)
37 {
38         struct drm_framebuffer *fb = state->fb;
39         const struct drm_format_info *format = fb->format;
40         unsigned int num_planes = format->num_planes;
41         unsigned int x = state->src.x1 >> 16;
42         unsigned int y = state->src.y1 >> 16;
43         u32 addr = drm_fb_obj(fb)->dev_addr;
44         int i;
45
46         DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",
47                       fb->pitches[0], x, y, format->cpp[0] * 8);
48
49         if (num_planes > 3)
50                 num_planes = 3;
51
52         addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] +
53                       x * format->cpp[0];
54         pitches[0] = fb->pitches[0];
55
56         y /= format->vsub;
57         x /= format->hsub;
58
59         for (i = 1; i < num_planes; i++) {
60                 addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] +
61                               x * format->cpp[i];
62                 pitches[i] = fb->pitches[i];
63         }
64         for (; i < 3; i++) {
65                 addrs[0][i] = 0;
66                 pitches[i] = 0;
67         }
68         if (interlaced) {
69                 for (i = 0; i < 3; i++) {
70                         addrs[1][i] = addrs[0][i] + pitches[i];
71                         pitches[i] *= 2;
72                 }
73         } else {
74                 for (i = 0; i < 3; i++)
75                         addrs[1][i] = addrs[0][i];
76         }
77 }
78
79 int armada_drm_plane_prepare_fb(struct drm_plane *plane,
80         struct drm_plane_state *state)
81 {
82         DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
83                 plane->base.id, plane->name,
84                 state->fb ? state->fb->base.id : 0);
85
86         /*
87          * Take a reference on the new framebuffer - we want to
88          * hold on to it while the hardware is displaying it.
89          */
90         if (state->fb)
91                 drm_framebuffer_get(state->fb);
92         return 0;
93 }
94
95 void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
96         struct drm_plane_state *old_state)
97 {
98         DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
99                 plane->base.id, plane->name,
100                 old_state->fb ? old_state->fb->base.id : 0);
101
102         if (old_state->fb)
103                 drm_framebuffer_put(old_state->fb);
104 }
105
106 int armada_drm_plane_atomic_check(struct drm_plane *plane,
107         struct drm_plane_state *state)
108 {
109         struct armada_plane_state *st = to_armada_plane_state(state);
110         struct drm_crtc *crtc = state->crtc;
111         struct drm_crtc_state *crtc_state;
112         bool interlace;
113         int ret;
114
115         if (!state->fb || WARN_ON(!state->crtc)) {
116                 state->visible = false;
117                 return 0;
118         }
119
120         if (state->state)
121                 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
122         else
123                 crtc_state = crtc->state;
124
125         ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0,
126                                                   INT_MAX, true, false);
127         if (ret)
128                 return ret;
129
130         interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
131         if (interlace) {
132                 if ((state->dst.y1 | state->dst.y2) & 1)
133                         return -EINVAL;
134                 st->src_hw = drm_rect_height(&state->src) >> 17;
135                 st->dst_yx = state->dst.y1 >> 1;
136                 st->dst_hw = drm_rect_height(&state->dst) >> 1;
137         } else {
138                 st->src_hw = drm_rect_height(&state->src) >> 16;
139                 st->dst_yx = state->dst.y1;
140                 st->dst_hw = drm_rect_height(&state->dst);
141         }
142
143         st->src_hw <<= 16;
144         st->src_hw |= drm_rect_width(&state->src) >> 16;
145         st->dst_yx <<= 16;
146         st->dst_yx |= state->dst.x1 & 0x0000ffff;
147         st->dst_hw <<= 16;
148         st->dst_hw |= drm_rect_width(&state->dst) & 0x0000ffff;
149
150         armada_drm_plane_calc(state, st->addrs, st->pitches, interlace);
151         st->interlace = interlace;
152
153         return 0;
154 }
155
156 static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
157         struct drm_plane_state *old_state)
158 {
159         struct drm_plane_state *state = plane->state;
160         struct armada_crtc *dcrtc;
161         struct armada_regs *regs;
162         u32 cfg, cfg_mask, val;
163         unsigned int idx;
164
165         DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
166
167         if (!state->fb || WARN_ON(!state->crtc))
168                 return;
169
170         DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
171                 plane->base.id, plane->name,
172                 state->crtc->base.id, state->crtc->name,
173                 state->fb->base.id,
174                 old_state->visible, state->visible);
175
176         dcrtc = drm_to_armada_crtc(state->crtc);
177         regs = dcrtc->regs + dcrtc->regs_idx;
178
179         idx = 0;
180         if (!old_state->visible && state->visible) {
181                 val = CFG_PDWN64x66;
182                 if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
183                         val |= CFG_PDWN256x24;
184                 armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
185         }
186         val = armada_src_hw(state);
187         if (armada_src_hw(old_state) != val)
188                 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
189         val = armada_dst_yx(state);
190         if (armada_dst_yx(old_state) != val)
191                 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
192         val = armada_dst_hw(state);
193         if (armada_dst_hw(old_state) != val)
194                 armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
195         if (old_state->src.x1 != state->src.x1 ||
196             old_state->src.y1 != state->src.y1 ||
197             old_state->fb != state->fb ||
198             state->crtc->state->mode_changed) {
199                 armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
200                                      LCD_CFG_GRA_START_ADDR0);
201                 armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0),
202                                      LCD_CFG_GRA_START_ADDR1);
203                 armada_reg_queue_mod(regs, idx, armada_pitch(state, 0), 0xffff,
204                                      LCD_CFG_GRA_PITCH);
205         }
206         if (old_state->fb != state->fb ||
207             state->crtc->state->mode_changed) {
208                 cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
209                       CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod);
210                 if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
211                         cfg |= CFG_PALETTE_ENA;
212                 if (state->visible)
213                         cfg |= CFG_GRA_ENA;
214                 if (to_armada_plane_state(state)->interlace)
215                         cfg |= CFG_GRA_FTOGGLE;
216                 cfg_mask = CFG_GRAFORMAT |
217                            CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
218                                        CFG_SWAPYU | CFG_YUV2RGB) |
219                            CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
220                            CFG_GRA_ENA;
221         } else if (old_state->visible != state->visible) {
222                 cfg = state->visible ? CFG_GRA_ENA : 0;
223                 cfg_mask = CFG_GRA_ENA;
224         } else {
225                 cfg = cfg_mask = 0;
226         }
227         if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) ||
228             drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) {
229                 cfg_mask |= CFG_GRA_HSMOOTH;
230                 if (drm_rect_width(&state->src) >> 16 !=
231                     drm_rect_width(&state->dst))
232                         cfg |= CFG_GRA_HSMOOTH;
233         }
234
235         if (cfg_mask)
236                 armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
237                                      LCD_SPU_DMA_CTRL0);
238
239         dcrtc->regs_idx += idx;
240 }
241
242 static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
243         struct drm_plane_state *old_state)
244 {
245         struct armada_crtc *dcrtc;
246         struct armada_regs *regs;
247         unsigned int idx = 0;
248
249         DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
250
251         if (!old_state->crtc)
252                 return;
253
254         DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
255                 plane->base.id, plane->name,
256                 old_state->crtc->base.id, old_state->crtc->name,
257                 old_state->fb->base.id);
258
259         dcrtc = drm_to_armada_crtc(old_state->crtc);
260         regs = dcrtc->regs + dcrtc->regs_idx;
261
262         /* Disable plane and power down most RAMs and FIFOs */
263         armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
264         armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |
265                              CFG_PDWN32x32 | CFG_PDWN64x66,
266                              0, LCD_SPU_SRAM_PARA1);
267
268         dcrtc->regs_idx += idx;
269 }
270
271 static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
272         .prepare_fb     = armada_drm_plane_prepare_fb,
273         .cleanup_fb     = armada_drm_plane_cleanup_fb,
274         .atomic_check   = armada_drm_plane_atomic_check,
275         .atomic_update  = armada_drm_primary_plane_atomic_update,
276         .atomic_disable = armada_drm_primary_plane_atomic_disable,
277 };
278
279 void armada_plane_reset(struct drm_plane *plane)
280 {
281         struct armada_plane_state *st;
282         if (plane->state)
283                 __drm_atomic_helper_plane_destroy_state(plane->state);
284         kfree(plane->state);
285         st = kzalloc(sizeof(*st), GFP_KERNEL);
286         if (st)
287                 __drm_atomic_helper_plane_reset(plane, &st->base);
288 }
289
290 struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
291 {
292         struct armada_plane_state *st;
293
294         if (WARN_ON(!plane->state))
295                 return NULL;
296
297         st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
298         if (st)
299                 __drm_atomic_helper_plane_duplicate_state(plane, &st->base);
300
301         return &st->base;
302 }
303
304 static const struct drm_plane_funcs armada_primary_plane_funcs = {
305         .update_plane   = drm_atomic_helper_update_plane,
306         .disable_plane  = drm_atomic_helper_disable_plane,
307         .destroy        = drm_primary_helper_destroy,
308         .reset          = armada_plane_reset,
309         .atomic_duplicate_state = armada_plane_duplicate_state,
310         .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
311 };
312
313 int armada_drm_primary_plane_init(struct drm_device *drm,
314         struct drm_plane *primary)
315 {
316         int ret;
317
318         drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs);
319
320         ret = drm_universal_plane_init(drm, primary, 0,
321                                        &armada_primary_plane_funcs,
322                                        armada_primary_formats,
323                                        ARRAY_SIZE(armada_primary_formats),
324                                        NULL,
325                                        DRM_PLANE_TYPE_PRIMARY, NULL);
326
327         return ret;
328 }
This page took 0.05545 seconds and 4 git commands to generate.