]> Git Repo - linux.git/blob - drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c
Merge tag 'cxl-for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
[linux.git] / drivers / gpu / drm / renesas / shmobile / shmob_drm_plane.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * shmob_drm_plane.c  --  SH Mobile DRM Planes
4  *
5  * Copyright (C) 2012 Renesas Electronics Corporation
6  *
7  * Laurent Pinchart ([email protected])
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_fb_dma_helper.h>
14 #include <drm/drm_fourcc.h>
15 #include <drm/drm_framebuffer.h>
16 #include <drm/drm_gem_dma_helper.h>
17
18 #include "shmob_drm_drv.h"
19 #include "shmob_drm_kms.h"
20 #include "shmob_drm_plane.h"
21 #include "shmob_drm_regs.h"
22
23 struct shmob_drm_plane {
24         struct drm_plane base;
25         unsigned int index;
26 };
27
28 struct shmob_drm_plane_state {
29         struct drm_plane_state base;
30
31         const struct shmob_drm_format_info *format;
32         u32 dma[2];
33 };
34
35 static inline struct shmob_drm_plane *to_shmob_plane(struct drm_plane *plane)
36 {
37         return container_of(plane, struct shmob_drm_plane, base);
38 }
39
40 static inline struct shmob_drm_plane_state *to_shmob_plane_state(struct drm_plane_state *state)
41 {
42         return container_of(state, struct shmob_drm_plane_state, base);
43 }
44
45 static void shmob_drm_plane_compute_base(struct shmob_drm_plane_state *sstate)
46 {
47         struct drm_framebuffer *fb = sstate->base.fb;
48         unsigned int x = sstate->base.src_x >> 16;
49         unsigned int y = sstate->base.src_y >> 16;
50         struct drm_gem_dma_object *gem;
51         unsigned int bpp;
52
53         bpp = shmob_drm_format_is_yuv(sstate->format) ? 8 : sstate->format->bpp;
54         gem = drm_fb_dma_get_gem_obj(fb, 0);
55         sstate->dma[0] = gem->dma_addr + fb->offsets[0]
56                        + y * fb->pitches[0] + x * bpp / 8;
57
58         if (shmob_drm_format_is_yuv(sstate->format)) {
59                 bpp = sstate->format->bpp - 8;
60                 gem = drm_fb_dma_get_gem_obj(fb, 1);
61                 sstate->dma[1] = gem->dma_addr + fb->offsets[1]
62                                + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
63                                + x * (bpp == 16 ? 2 : 1);
64         }
65 }
66
67 static void shmob_drm_primary_plane_setup(struct shmob_drm_plane *splane,
68                                           struct drm_plane_state *state)
69 {
70         struct shmob_drm_plane_state *sstate = to_shmob_plane_state(state);
71         struct shmob_drm_device *sdev = to_shmob_device(splane->base.dev);
72         struct drm_framebuffer *fb = state->fb;
73
74         /* TODO: Handle YUV colorspaces. Hardcode REC709 for now. */
75         lcdc_write(sdev, LDDFR, sstate->format->lddfr | LDDFR_CF1);
76         lcdc_write(sdev, LDMLSR, fb->pitches[0]);
77
78         /* Word and long word swap. */
79         lcdc_write(sdev, LDDDSR, sstate->format->ldddsr);
80
81         lcdc_write_mirror(sdev, LDSA1R, sstate->dma[0]);
82         if (shmob_drm_format_is_yuv(sstate->format))
83                 lcdc_write_mirror(sdev, LDSA2R, sstate->dma[1]);
84
85         lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ LDRCNTR_MRS);
86 }
87
88 static void shmob_drm_overlay_plane_setup(struct shmob_drm_plane *splane,
89                                           struct drm_plane_state *state)
90 {
91         struct shmob_drm_plane_state *sstate = to_shmob_plane_state(state);
92         struct shmob_drm_device *sdev = to_shmob_device(splane->base.dev);
93         struct drm_framebuffer *fb = state->fb;
94         u32 format;
95
96         /* TODO: Support ROP3 mode */
97         format = LDBBSIFR_EN | ((state->alpha >> 8) << LDBBSIFR_LAY_SHIFT) |
98                  sstate->format->ldbbsifr;
99
100 #define plane_reg_dump(sdev, splane, reg) \
101         dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
102                 splane->index, #reg, \
103                 lcdc_read(sdev, reg(splane->index)), \
104                 lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
105
106         plane_reg_dump(sdev, splane, LDBnBSIFR);
107         plane_reg_dump(sdev, splane, LDBnBSSZR);
108         plane_reg_dump(sdev, splane, LDBnBLOCR);
109         plane_reg_dump(sdev, splane, LDBnBSMWR);
110         plane_reg_dump(sdev, splane, LDBnBSAYR);
111         plane_reg_dump(sdev, splane, LDBnBSACR);
112
113         lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
114         dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
115                 "LDBCR", lcdc_read(sdev, LDBCR));
116
117         lcdc_write(sdev, LDBnBSIFR(splane->index), format);
118
119         lcdc_write(sdev, LDBnBSSZR(splane->index),
120                    (state->crtc_h << LDBBSSZR_BVSS_SHIFT) |
121                    (state->crtc_w << LDBBSSZR_BHSS_SHIFT));
122         lcdc_write(sdev, LDBnBLOCR(splane->index),
123                    (state->crtc_y << LDBBLOCR_CVLC_SHIFT) |
124                    (state->crtc_x << LDBBLOCR_CHLC_SHIFT));
125         lcdc_write(sdev, LDBnBSMWR(splane->index),
126                    fb->pitches[0] << LDBBSMWR_BSMW_SHIFT);
127
128         lcdc_write(sdev, LDBnBSAYR(splane->index), sstate->dma[0]);
129         if (shmob_drm_format_is_yuv(sstate->format))
130                 lcdc_write(sdev, LDBnBSACR(splane->index), sstate->dma[1]);
131
132         lcdc_write(sdev, LDBCR,
133                    LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
134         dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
135                 "LDBCR", lcdc_read(sdev, LDBCR));
136
137         plane_reg_dump(sdev, splane, LDBnBSIFR);
138         plane_reg_dump(sdev, splane, LDBnBSSZR);
139         plane_reg_dump(sdev, splane, LDBnBLOCR);
140         plane_reg_dump(sdev, splane, LDBnBSMWR);
141         plane_reg_dump(sdev, splane, LDBnBSAYR);
142         plane_reg_dump(sdev, splane, LDBnBSACR);
143 }
144
145 static int shmob_drm_plane_atomic_check(struct drm_plane *plane,
146                                         struct drm_atomic_state *state)
147 {
148         struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
149         struct shmob_drm_plane_state *sstate = to_shmob_plane_state(new_plane_state);
150         struct drm_crtc_state *crtc_state;
151         bool is_primary = plane->type == DRM_PLANE_TYPE_PRIMARY;
152         int ret;
153
154         if (!new_plane_state->crtc) {
155                 /*
156                  * The visible field is not reset by the DRM core but only
157                  * updated by drm_atomic_helper_check_plane_state(), set it
158                  * manually.
159                  */
160                 new_plane_state->visible = false;
161                 sstate->format = NULL;
162                 return 0;
163         }
164
165         crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc);
166         if (IS_ERR(crtc_state))
167                 return PTR_ERR(crtc_state);
168
169         ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
170                                                   DRM_PLANE_NO_SCALING,
171                                                   DRM_PLANE_NO_SCALING,
172                                                   !is_primary, true);
173         if (ret < 0)
174                 return ret;
175
176         if (!new_plane_state->visible) {
177                 sstate->format = NULL;
178                 return 0;
179         }
180
181         sstate->format = shmob_drm_format_info(new_plane_state->fb->format->format);
182         if (!sstate->format) {
183                 dev_dbg(plane->dev->dev,
184                         "plane_atomic_check: unsupported format %p4cc\n",
185                         &new_plane_state->fb->format->format);
186                 return -EINVAL;
187         }
188
189         shmob_drm_plane_compute_base(sstate);
190
191         return 0;
192 }
193
194 static void shmob_drm_plane_atomic_update(struct drm_plane *plane,
195                                           struct drm_atomic_state *state)
196 {
197         struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
198         struct shmob_drm_plane *splane = to_shmob_plane(plane);
199
200         if (!new_plane_state->visible)
201                 return;
202
203         if (plane->type == DRM_PLANE_TYPE_PRIMARY)
204                 shmob_drm_primary_plane_setup(splane, new_plane_state);
205         else
206                 shmob_drm_overlay_plane_setup(splane, new_plane_state);
207 }
208
209 static void shmob_drm_plane_atomic_disable(struct drm_plane *plane,
210                                            struct drm_atomic_state *state)
211 {
212         struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
213         struct shmob_drm_device *sdev = to_shmob_device(plane->dev);
214         struct shmob_drm_plane *splane = to_shmob_plane(plane);
215
216         if (!old_state->crtc)
217                 return;
218
219         if (plane->type != DRM_PLANE_TYPE_OVERLAY)
220                 return;
221
222         lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
223         lcdc_write(sdev, LDBnBSIFR(splane->index), 0);
224         lcdc_write(sdev, LDBCR,
225                          LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
226 }
227
228 static struct drm_plane_state *
229 shmob_drm_plane_atomic_duplicate_state(struct drm_plane *plane)
230 {
231         struct shmob_drm_plane_state *state;
232         struct shmob_drm_plane_state *copy;
233
234         if (WARN_ON(!plane->state))
235                 return NULL;
236
237         state = to_shmob_plane_state(plane->state);
238         copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
239         if (copy == NULL)
240                 return NULL;
241
242         __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
243
244         return &copy->base;
245 }
246
247 static void shmob_drm_plane_atomic_destroy_state(struct drm_plane *plane,
248                                                  struct drm_plane_state *state)
249 {
250         __drm_atomic_helper_plane_destroy_state(state);
251         kfree(to_shmob_plane_state(state));
252 }
253
254 static void shmob_drm_plane_reset(struct drm_plane *plane)
255 {
256         struct shmob_drm_plane_state *state;
257
258         if (plane->state) {
259                 shmob_drm_plane_atomic_destroy_state(plane, plane->state);
260                 plane->state = NULL;
261         }
262
263         state = kzalloc(sizeof(*state), GFP_KERNEL);
264         if (state == NULL)
265                 return;
266
267         __drm_atomic_helper_plane_reset(plane, &state->base);
268 }
269
270 static const struct drm_plane_helper_funcs shmob_drm_plane_helper_funcs = {
271         .atomic_check = shmob_drm_plane_atomic_check,
272         .atomic_update = shmob_drm_plane_atomic_update,
273         .atomic_disable = shmob_drm_plane_atomic_disable,
274 };
275
276 static const struct drm_plane_funcs shmob_drm_plane_funcs = {
277         .update_plane = drm_atomic_helper_update_plane,
278         .disable_plane = drm_atomic_helper_disable_plane,
279         .reset = shmob_drm_plane_reset,
280         .atomic_duplicate_state = shmob_drm_plane_atomic_duplicate_state,
281         .atomic_destroy_state = shmob_drm_plane_atomic_destroy_state,
282 };
283
284 static const uint32_t formats[] = {
285         DRM_FORMAT_RGB565,
286         DRM_FORMAT_RGB888,
287         DRM_FORMAT_ARGB8888,
288         DRM_FORMAT_XRGB8888,
289         DRM_FORMAT_NV12,
290         DRM_FORMAT_NV21,
291         DRM_FORMAT_NV16,
292         DRM_FORMAT_NV61,
293         DRM_FORMAT_NV24,
294         DRM_FORMAT_NV42,
295 };
296
297 struct drm_plane *shmob_drm_plane_create(struct shmob_drm_device *sdev,
298                                          enum drm_plane_type type,
299                                          unsigned int index)
300 {
301         struct shmob_drm_plane *splane;
302
303         splane = drmm_universal_plane_alloc(&sdev->ddev,
304                                             struct shmob_drm_plane, base, 1,
305                                             &shmob_drm_plane_funcs, formats,
306                                             ARRAY_SIZE(formats),  NULL, type,
307                                             NULL);
308         if (IS_ERR(splane))
309                 return ERR_CAST(splane);
310
311         splane->index = index;
312
313         drm_plane_helper_add(&splane->base, &shmob_drm_plane_helper_funcs);
314
315         return &splane->base;
316 }
This page took 0.052549 seconds and 4 git commands to generate.