2 * Copyright 2016 Linaro Ltd.
3 * Copyright 2016 ZTE Corporation.
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.
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>
19 #include "zx_drm_drv.h"
21 #include "zx_plane_regs.h"
25 struct drm_plane plane
;
32 #define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
34 static const uint32_t gl_formats
[] = {
43 static int zx_gl_plane_atomic_check(struct drm_plane
*plane
,
44 struct drm_plane_state
*plane_state
)
46 struct drm_framebuffer
*fb
= plane_state
->fb
;
47 struct drm_crtc
*crtc
= plane_state
->crtc
;
48 struct drm_crtc_state
*crtc_state
;
54 crtc_state
= drm_atomic_get_existing_crtc_state(plane_state
->state
,
56 if (WARN_ON(!crtc_state
))
59 /* nothing to check when disabling or disabled */
60 if (!crtc_state
->enable
)
63 /* plane must be enabled */
64 if (!plane_state
->crtc
)
69 clip
.x2
= crtc_state
->adjusted_mode
.hdisplay
;
70 clip
.y2
= crtc_state
->adjusted_mode
.vdisplay
;
72 return drm_plane_helper_check_state(plane_state
, &clip
,
73 DRM_PLANE_HELPER_NO_SCALING
,
74 DRM_PLANE_HELPER_NO_SCALING
,
78 static int zx_gl_get_fmt(uint32_t format
)
81 case DRM_FORMAT_ARGB8888
:
82 case DRM_FORMAT_XRGB8888
:
83 return GL_FMT_ARGB8888
;
84 case DRM_FORMAT_RGB888
:
86 case DRM_FORMAT_RGB565
:
88 case DRM_FORMAT_ARGB1555
:
89 return GL_FMT_ARGB1555
;
90 case DRM_FORMAT_ARGB4444
:
91 return GL_FMT_ARGB4444
;
93 WARN_ONCE(1, "invalid pixel format %d\n", format
);
98 static inline void zx_gl_set_update(struct zx_plane
*zplane
)
100 void __iomem
*layer
= zplane
->layer
;
102 zx_writel_mask(layer
+ GL_CTRL0
, GL_UPDATE
, GL_UPDATE
);
105 static inline void zx_gl_rsz_set_update(struct zx_plane
*zplane
)
107 zx_writel(zplane
->rsz
+ RSZ_ENABLE_CFG
, 1);
110 void zx_plane_set_update(struct drm_plane
*plane
)
112 struct zx_plane
*zplane
= to_zx_plane(plane
);
114 zx_gl_rsz_set_update(zplane
);
115 zx_gl_set_update(zplane
);
118 static void zx_gl_rsz_setup(struct zx_plane
*zplane
, u32 src_w
, u32 src_h
,
119 u32 dst_w
, u32 dst_h
)
121 void __iomem
*rsz
= zplane
->rsz
;
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));
126 zx_gl_rsz_set_update(zplane
);
129 static void zx_gl_plane_atomic_update(struct drm_plane
*plane
,
130 struct drm_plane_state
*old_state
)
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
;
149 format
= fb
->format
->format
;
150 stride
= fb
->pitches
[0];
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;
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
;
162 bpp
= fb
->format
->cpp
[0];
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
);
169 /* Set up source height/width register */
170 zx_writel(layer
+ GL_SRC_SIZE
, GL_SRC_W(src_w
) | GL_SRC_H(src_h
));
172 /* Set up start position register */
173 zx_writel(layer
+ GL_POS_START
, GL_POS_X(dst_x
) | GL_POS_Y(dst_y
));
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
));
179 /* Set up stride register */
180 zx_writel(layer
+ GL_STRIDE
, stride
& 0xffff);
182 /* Set up graphic layer data format */
183 fmt
= zx_gl_get_fmt(format
);
185 zx_writel_mask(layer
+ GL_CTRL1
, GL_DATA_FMT_MASK
,
186 fmt
<< GL_DATA_FMT_SHIFT
);
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
);
192 /* Setup CSC for the GL */
194 zx_writel_mask(csc
+ CSC_CTRL0
, CSC_COV_MODE_MASK
,
195 CSC_BT709_IMAGE_RGB2YCBCR
<< CSC_COV_MODE_SHIFT
);
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
);
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
);
205 zx_gl_rsz_setup(zplane
, src_w
, src_h
, dst_w
, dst_h
);
207 /* Enable HBSC block */
208 zx_writel_mask(hbsc
+ HBSC_CTRL0
, HBSC_CTRL_EN
, HBSC_CTRL_EN
);
210 zx_gl_set_update(zplane
);
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
,
218 static void zx_plane_destroy(struct drm_plane
*plane
)
220 drm_plane_helper_disable(plane
);
221 drm_plane_cleanup(plane
);
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
,
233 static void zx_plane_hbsc_init(struct zx_plane
*zplane
)
235 void __iomem
*hbsc
= zplane
->hbsc
;
238 * Initialize HBSC block with a sane configuration per recommedation
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);
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);
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
)
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
;
262 zplane
= devm_kzalloc(dev
, sizeof(*zplane
), GFP_KERNEL
);
264 return ERR_PTR(-ENOMEM
);
266 plane
= &zplane
->plane
;
268 zplane
->layer
= data
->layer
;
269 zplane
->hbsc
= data
->hbsc
;
270 zplane
->csc
= data
->csc
;
271 zplane
->rsz
= data
->rsz
;
273 zx_plane_hbsc_init(zplane
);
276 case DRM_PLANE_TYPE_PRIMARY
:
277 helper
= &zx_gl_plane_helper_funcs
;
278 formats
= gl_formats
;
279 format_count
= ARRAY_SIZE(gl_formats
);
281 case DRM_PLANE_TYPE_OVERLAY
:
282 /* TODO: add video layer (vl) support */
285 return ERR_PTR(-ENODEV
);
288 ret
= drm_universal_plane_init(drm
, plane
, VOU_CRTC_MASK
,
289 &zx_plane_funcs
, formats
, format_count
,
292 DRM_DEV_ERROR(dev
, "failed to init universal plane: %d\n", ret
);
296 drm_plane_helper_add(plane
, helper
);