]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/zte/zx_plane.c
Merge remote-tracking branches 'asoc/fix/nau8825', 'asoc/fix/rt5645', 'asoc/fix/tlv32...
[karo-tx-linux.git] / drivers / gpu / drm / zte / zx_plane.c
1 /*
2  * Copyright 2016 Linaro Ltd.
3  * Copyright 2016 ZTE Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  */
10
11 #include <drm/drm_atomic.h>
12 #include <drm/drm_atomic_helper.h>
13 #include <drm/drm_fb_cma_helper.h>
14 #include <drm/drm_gem_cma_helper.h>
15 #include <drm/drm_modeset_helper_vtables.h>
16 #include <drm/drm_plane_helper.h>
17 #include <drm/drmP.h>
18
19 #include "zx_drm_drv.h"
20 #include "zx_plane.h"
21 #include "zx_plane_regs.h"
22 #include "zx_vou.h"
23
24 struct zx_plane {
25         struct drm_plane plane;
26         void __iomem *layer;
27         void __iomem *csc;
28         void __iomem *hbsc;
29         void __iomem *rsz;
30 };
31
32 #define to_zx_plane(plane)      container_of(plane, struct zx_plane, plane)
33
34 static const uint32_t gl_formats[] = {
35         DRM_FORMAT_ARGB8888,
36         DRM_FORMAT_XRGB8888,
37         DRM_FORMAT_RGB888,
38         DRM_FORMAT_RGB565,
39         DRM_FORMAT_ARGB1555,
40         DRM_FORMAT_ARGB4444,
41 };
42
43 static int zx_gl_plane_atomic_check(struct drm_plane *plane,
44                                     struct drm_plane_state *plane_state)
45 {
46         struct drm_framebuffer *fb = plane_state->fb;
47         struct drm_crtc *crtc = plane_state->crtc;
48         struct drm_crtc_state *crtc_state;
49         struct drm_rect clip;
50
51         if (!crtc || !fb)
52                 return 0;
53
54         crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
55                                                         crtc);
56         if (WARN_ON(!crtc_state))
57                 return -EINVAL;
58
59         /* nothing to check when disabling or disabled */
60         if (!crtc_state->enable)
61                 return 0;
62
63         /* plane must be enabled */
64         if (!plane_state->crtc)
65                 return -EINVAL;
66
67         clip.x1 = 0;
68         clip.y1 = 0;
69         clip.x2 = crtc_state->adjusted_mode.hdisplay;
70         clip.y2 = crtc_state->adjusted_mode.vdisplay;
71
72         return drm_plane_helper_check_state(plane_state, &clip,
73                                             DRM_PLANE_HELPER_NO_SCALING,
74                                             DRM_PLANE_HELPER_NO_SCALING,
75                                             false, true);
76 }
77
78 static int zx_gl_get_fmt(uint32_t format)
79 {
80         switch (format) {
81         case DRM_FORMAT_ARGB8888:
82         case DRM_FORMAT_XRGB8888:
83                 return GL_FMT_ARGB8888;
84         case DRM_FORMAT_RGB888:
85                 return GL_FMT_RGB888;
86         case DRM_FORMAT_RGB565:
87                 return GL_FMT_RGB565;
88         case DRM_FORMAT_ARGB1555:
89                 return GL_FMT_ARGB1555;
90         case DRM_FORMAT_ARGB4444:
91                 return GL_FMT_ARGB4444;
92         default:
93                 WARN_ONCE(1, "invalid pixel format %d\n", format);
94                 return -EINVAL;
95         }
96 }
97
98 static inline void zx_gl_set_update(struct zx_plane *zplane)
99 {
100         void __iomem *layer = zplane->layer;
101
102         zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
103 }
104
105 static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
106 {
107         zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
108 }
109
110 void zx_plane_set_update(struct drm_plane *plane)
111 {
112         struct zx_plane *zplane = to_zx_plane(plane);
113
114         zx_gl_rsz_set_update(zplane);
115         zx_gl_set_update(zplane);
116 }
117
118 static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
119                             u32 dst_w, u32 dst_h)
120 {
121         void __iomem *rsz = zplane->rsz;
122
123         zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
124         zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
125
126         zx_gl_rsz_set_update(zplane);
127 }
128
129 static void zx_gl_plane_atomic_update(struct drm_plane *plane,
130                                       struct drm_plane_state *old_state)
131 {
132         struct zx_plane *zplane = to_zx_plane(plane);
133         struct drm_framebuffer *fb = plane->state->fb;
134         struct drm_gem_cma_object *cma_obj;
135         void __iomem *layer = zplane->layer;
136         void __iomem *csc = zplane->csc;
137         void __iomem *hbsc = zplane->hbsc;
138         u32 src_x, src_y, src_w, src_h;
139         u32 dst_x, dst_y, dst_w, dst_h;
140         unsigned int bpp;
141         uint32_t format;
142         dma_addr_t paddr;
143         u32 stride;
144         int fmt;
145
146         if (!fb)
147                 return;
148
149         format = fb->pixel_format;
150         stride = fb->pitches[0];
151
152         src_x = plane->state->src_x >> 16;
153         src_y = plane->state->src_y >> 16;
154         src_w = plane->state->src_w >> 16;
155         src_h = plane->state->src_h >> 16;
156
157         dst_x = plane->state->crtc_x;
158         dst_y = plane->state->crtc_y;
159         dst_w = plane->state->crtc_w;
160         dst_h = plane->state->crtc_h;
161
162         bpp = drm_format_plane_cpp(format, 0);
163
164         cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
165         paddr = cma_obj->paddr + fb->offsets[0];
166         paddr += src_y * stride + src_x * bpp / 8;
167         zx_writel(layer + GL_ADDR, paddr);
168
169         /* Set up source height/width register */
170         zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
171
172         /* Set up start position register */
173         zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
174
175         /* Set up end position register */
176         zx_writel(layer + GL_POS_END,
177                   GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
178
179         /* Set up stride register */
180         zx_writel(layer + GL_STRIDE, stride & 0xffff);
181
182         /* Set up graphic layer data format */
183         fmt = zx_gl_get_fmt(format);
184         if (fmt >= 0)
185                 zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
186                                fmt << GL_DATA_FMT_SHIFT);
187
188         /* Initialize global alpha with a sane value */
189         zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
190                        0xff << GL_GLOBAL_ALPHA_SHIFT);
191
192         /* Setup CSC for the GL */
193         if (dst_h > 720)
194                 zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
195                                CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
196         else
197                 zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
198                                CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
199         zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
200
201         /* Always use scaler since it exists (set for not bypass) */
202         zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
203                        GL_SCALER_BYPASS_MODE);
204
205         zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
206
207         /* Enable HBSC block */
208         zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
209
210         zx_gl_set_update(zplane);
211 }
212
213 static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
214         .atomic_check = zx_gl_plane_atomic_check,
215         .atomic_update = zx_gl_plane_atomic_update,
216 };
217
218 static void zx_plane_destroy(struct drm_plane *plane)
219 {
220         drm_plane_helper_disable(plane);
221         drm_plane_cleanup(plane);
222 }
223
224 static const struct drm_plane_funcs zx_plane_funcs = {
225         .update_plane = drm_atomic_helper_update_plane,
226         .disable_plane = drm_atomic_helper_disable_plane,
227         .destroy = zx_plane_destroy,
228         .reset = drm_atomic_helper_plane_reset,
229         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
230         .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
231 };
232
233 static void zx_plane_hbsc_init(struct zx_plane *zplane)
234 {
235         void __iomem *hbsc = zplane->hbsc;
236
237         /*
238          *  Initialize HBSC block with a sane configuration per recommedation
239          *  from ZTE BSP code.
240          */
241         zx_writel(hbsc + HBSC_SATURATION, 0x200);
242         zx_writel(hbsc + HBSC_HUE, 0x0);
243         zx_writel(hbsc + HBSC_BRIGHT, 0x0);
244         zx_writel(hbsc + HBSC_CONTRAST, 0x200);
245
246         zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
247         zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
248         zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
249 }
250
251 struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
252                                 struct zx_layer_data *data,
253                                 enum drm_plane_type type)
254 {
255         const struct drm_plane_helper_funcs *helper;
256         struct zx_plane *zplane;
257         struct drm_plane *plane;
258         const uint32_t *formats;
259         unsigned int format_count;
260         int ret;
261
262         zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
263         if (!zplane)
264                 return ERR_PTR(-ENOMEM);
265
266         plane = &zplane->plane;
267
268         zplane->layer = data->layer;
269         zplane->hbsc = data->hbsc;
270         zplane->csc = data->csc;
271         zplane->rsz = data->rsz;
272
273         zx_plane_hbsc_init(zplane);
274
275         switch (type) {
276         case DRM_PLANE_TYPE_PRIMARY:
277                 helper = &zx_gl_plane_helper_funcs;
278                 formats = gl_formats;
279                 format_count = ARRAY_SIZE(gl_formats);
280                 break;
281         case DRM_PLANE_TYPE_OVERLAY:
282                 /* TODO: add video layer (vl) support */
283                 break;
284         default:
285                 return ERR_PTR(-ENODEV);
286         }
287
288         ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
289                                        &zx_plane_funcs, formats, format_count,
290                                        type, NULL);
291         if (ret) {
292                 DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
293                 return ERR_PTR(ret);
294         }
295
296         drm_plane_helper_add(plane, helper);
297
298         return plane;
299 }