Linux-libre 5.0.14-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / 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 (laurent.pinchart@ideasonboard.com)
8  */
9
10 #include <drm/drmP.h>
11 #include <drm/drm_crtc.h>
12 #include <drm/drm_crtc_helper.h>
13 #include <drm/drm_fb_cma_helper.h>
14 #include <drm/drm_gem_cma_helper.h>
15
16 #include "shmob_drm_drv.h"
17 #include "shmob_drm_kms.h"
18 #include "shmob_drm_plane.h"
19 #include "shmob_drm_regs.h"
20
21 struct shmob_drm_plane {
22         struct drm_plane plane;
23         unsigned int index;
24         unsigned int alpha;
25
26         const struct shmob_drm_format_info *format;
27         unsigned long dma[2];
28
29         unsigned int src_x;
30         unsigned int src_y;
31         unsigned int crtc_x;
32         unsigned int crtc_y;
33         unsigned int crtc_w;
34         unsigned int crtc_h;
35 };
36
37 #define to_shmob_plane(p)       container_of(p, struct shmob_drm_plane, plane)
38
39 static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane,
40                                          struct drm_framebuffer *fb,
41                                          int x, int y)
42 {
43         struct drm_gem_cma_object *gem;
44         unsigned int bpp;
45
46         bpp = splane->format->yuv ? 8 : splane->format->bpp;
47         gem = drm_fb_cma_get_gem_obj(fb, 0);
48         splane->dma[0] = gem->paddr + fb->offsets[0]
49                        + y * fb->pitches[0] + x * bpp / 8;
50
51         if (splane->format->yuv) {
52                 bpp = splane->format->bpp - 8;
53                 gem = drm_fb_cma_get_gem_obj(fb, 1);
54                 splane->dma[1] = gem->paddr + fb->offsets[1]
55                                + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
56                                + x * (bpp == 16 ? 2 : 1);
57         }
58 }
59
60 static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane,
61                                     struct drm_framebuffer *fb)
62 {
63         struct shmob_drm_device *sdev = splane->plane.dev->dev_private;
64         u32 format;
65
66         /* TODO: Support ROP3 mode */
67         format = LDBBSIFR_EN | (splane->alpha << LDBBSIFR_LAY_SHIFT);
68
69         switch (splane->format->fourcc) {
70         case DRM_FORMAT_RGB565:
71         case DRM_FORMAT_NV21:
72         case DRM_FORMAT_NV61:
73         case DRM_FORMAT_NV42:
74                 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
75                 break;
76         case DRM_FORMAT_RGB888:
77         case DRM_FORMAT_NV12:
78         case DRM_FORMAT_NV16:
79         case DRM_FORMAT_NV24:
80                 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
81                 break;
82         case DRM_FORMAT_ARGB8888:
83         default:
84                 format |= LDBBSIFR_SWPL;
85                 break;
86         }
87
88         switch (splane->format->fourcc) {
89         case DRM_FORMAT_RGB565:
90                 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
91                 break;
92         case DRM_FORMAT_RGB888:
93                 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
94                 break;
95         case DRM_FORMAT_ARGB8888:
96                 format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
97                 break;
98         case DRM_FORMAT_NV12:
99         case DRM_FORMAT_NV21:
100                 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
101                 break;
102         case DRM_FORMAT_NV16:
103         case DRM_FORMAT_NV61:
104                 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
105                 break;
106         case DRM_FORMAT_NV24:
107         case DRM_FORMAT_NV42:
108                 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
109                 break;
110         }
111
112 #define plane_reg_dump(sdev, splane, reg) \
113         dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
114                 splane->index, #reg, \
115                 lcdc_read(sdev, reg(splane->index)), \
116                 lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
117
118         plane_reg_dump(sdev, splane, LDBnBSIFR);
119         plane_reg_dump(sdev, splane, LDBnBSSZR);
120         plane_reg_dump(sdev, splane, LDBnBLOCR);
121         plane_reg_dump(sdev, splane, LDBnBSMWR);
122         plane_reg_dump(sdev, splane, LDBnBSAYR);
123         plane_reg_dump(sdev, splane, LDBnBSACR);
124
125         lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
126         dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
127                 "LDBCR", lcdc_read(sdev, LDBCR));
128
129         lcdc_write(sdev, LDBnBSIFR(splane->index), format);
130
131         lcdc_write(sdev, LDBnBSSZR(splane->index),
132                    (splane->crtc_h << LDBBSSZR_BVSS_SHIFT) |
133                    (splane->crtc_w << LDBBSSZR_BHSS_SHIFT));
134         lcdc_write(sdev, LDBnBLOCR(splane->index),
135                    (splane->crtc_y << LDBBLOCR_CVLC_SHIFT) |
136                    (splane->crtc_x << LDBBLOCR_CHLC_SHIFT));
137         lcdc_write(sdev, LDBnBSMWR(splane->index),
138                    fb->pitches[0] << LDBBSMWR_BSMW_SHIFT);
139
140         shmob_drm_plane_compute_base(splane, fb, splane->src_x, splane->src_y);
141
142         lcdc_write(sdev, LDBnBSAYR(splane->index), splane->dma[0]);
143         if (splane->format->yuv)
144                 lcdc_write(sdev, LDBnBSACR(splane->index), splane->dma[1]);
145
146         lcdc_write(sdev, LDBCR,
147                    LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
148         dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
149                 "LDBCR", lcdc_read(sdev, LDBCR));
150
151         plane_reg_dump(sdev, splane, LDBnBSIFR);
152         plane_reg_dump(sdev, splane, LDBnBSSZR);
153         plane_reg_dump(sdev, splane, LDBnBLOCR);
154         plane_reg_dump(sdev, splane, LDBnBSMWR);
155         plane_reg_dump(sdev, splane, LDBnBSAYR);
156         plane_reg_dump(sdev, splane, LDBnBSACR);
157 }
158
159 void shmob_drm_plane_setup(struct drm_plane *plane)
160 {
161         struct shmob_drm_plane *splane = to_shmob_plane(plane);
162
163         if (plane->fb == NULL)
164                 return;
165
166         __shmob_drm_plane_setup(splane, plane->fb);
167 }
168
169 static int
170 shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
171                        struct drm_framebuffer *fb, int crtc_x, int crtc_y,
172                        unsigned int crtc_w, unsigned int crtc_h,
173                        uint32_t src_x, uint32_t src_y,
174                        uint32_t src_w, uint32_t src_h,
175                        struct drm_modeset_acquire_ctx *ctx)
176 {
177         struct shmob_drm_plane *splane = to_shmob_plane(plane);
178         struct shmob_drm_device *sdev = plane->dev->dev_private;
179         const struct shmob_drm_format_info *format;
180
181         format = shmob_drm_format_info(fb->format->format);
182         if (format == NULL) {
183                 dev_dbg(sdev->dev, "update_plane: unsupported format %08x\n",
184                         fb->format->format);
185                 return -EINVAL;
186         }
187
188         if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
189                 dev_dbg(sdev->dev, "%s: scaling not supported\n", __func__);
190                 return -EINVAL;
191         }
192
193         splane->format = format;
194
195         splane->src_x = src_x >> 16;
196         splane->src_y = src_y >> 16;
197         splane->crtc_x = crtc_x;
198         splane->crtc_y = crtc_y;
199         splane->crtc_w = crtc_w;
200         splane->crtc_h = crtc_h;
201
202         __shmob_drm_plane_setup(splane, fb);
203         return 0;
204 }
205
206 static int shmob_drm_plane_disable(struct drm_plane *plane,
207                                    struct drm_modeset_acquire_ctx *ctx)
208 {
209         struct shmob_drm_plane *splane = to_shmob_plane(plane);
210         struct shmob_drm_device *sdev = plane->dev->dev_private;
211
212         splane->format = NULL;
213
214         lcdc_write(sdev, LDBnBSIFR(splane->index), 0);
215         return 0;
216 }
217
218 static void shmob_drm_plane_destroy(struct drm_plane *plane)
219 {
220         drm_plane_force_disable(plane);
221         drm_plane_cleanup(plane);
222 }
223
224 static const struct drm_plane_funcs shmob_drm_plane_funcs = {
225         .update_plane = shmob_drm_plane_update,
226         .disable_plane = shmob_drm_plane_disable,
227         .destroy = shmob_drm_plane_destroy,
228 };
229
230 static const uint32_t formats[] = {
231         DRM_FORMAT_RGB565,
232         DRM_FORMAT_RGB888,
233         DRM_FORMAT_ARGB8888,
234         DRM_FORMAT_NV12,
235         DRM_FORMAT_NV21,
236         DRM_FORMAT_NV16,
237         DRM_FORMAT_NV61,
238         DRM_FORMAT_NV24,
239         DRM_FORMAT_NV42,
240 };
241
242 int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
243 {
244         struct shmob_drm_plane *splane;
245         int ret;
246
247         splane = devm_kzalloc(sdev->dev, sizeof(*splane), GFP_KERNEL);
248         if (splane == NULL)
249                 return -ENOMEM;
250
251         splane->index = index;
252         splane->alpha = 255;
253
254         ret = drm_plane_init(sdev->ddev, &splane->plane, 1,
255                              &shmob_drm_plane_funcs, formats,
256                              ARRAY_SIZE(formats), false);
257
258         return ret;
259 }