2 * Copyright (c) 2015 MediaTek Inc.
3 * Author: CK Hu <ck.hu@mediatek.com>
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.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <drm/drm_atomic.h>
17 #include <drm/drm_atomic_helper.h>
18 #include <drm/drm_plane_helper.h>
20 #include "mtk_drm_crtc.h"
21 #include "mtk_drm_ddp_comp.h"
22 #include "mtk_drm_drv.h"
23 #include "mtk_drm_fb.h"
24 #include "mtk_drm_gem.h"
25 #include "mtk_drm_plane.h"
27 static const u32 formats
[] = {
33 static void mtk_plane_enable(struct mtk_drm_plane
*mtk_plane
, bool enable
,
34 dma_addr_t addr
, struct drm_rect
*dest
)
36 struct drm_plane
*plane
= &mtk_plane
->base
;
37 struct mtk_plane_state
*state
= to_mtk_plane_state(plane
->state
);
38 unsigned int pitch
, format
;
41 if (WARN_ON(!plane
->state
|| (enable
&& !plane
->state
->fb
)))
44 if (plane
->state
->fb
) {
45 pitch
= plane
->state
->fb
->pitches
[0];
46 format
= plane
->state
->fb
->pixel_format
;
49 format
= DRM_FORMAT_RGBA8888
;
52 x
= plane
->state
->crtc_x
;
53 y
= plane
->state
->crtc_y
;
65 state
->pending
.enable
= enable
;
66 state
->pending
.pitch
= pitch
;
67 state
->pending
.format
= format
;
68 state
->pending
.addr
= addr
;
71 state
->pending
.width
= dest
->x2
- dest
->x1
;
72 state
->pending
.height
= dest
->y2
- dest
->y1
;
73 wmb(); /* Make sure the above parameters are set before update */
74 state
->pending
.dirty
= true;
77 static void mtk_plane_reset(struct drm_plane
*plane
)
79 struct mtk_plane_state
*state
;
83 drm_framebuffer_unreference(plane
->state
->fb
);
85 state
= to_mtk_plane_state(plane
->state
);
86 memset(state
, 0, sizeof(*state
));
88 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
91 plane
->state
= &state
->base
;
94 state
->base
.plane
= plane
;
95 state
->pending
.format
= DRM_FORMAT_RGB565
;
98 static struct drm_plane_state
*mtk_plane_duplicate_state(struct drm_plane
*plane
)
100 struct mtk_plane_state
*old_state
= to_mtk_plane_state(plane
->state
);
101 struct mtk_plane_state
*state
;
103 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
107 __drm_atomic_helper_plane_duplicate_state(plane
, &state
->base
);
109 WARN_ON(state
->base
.plane
!= plane
);
111 state
->pending
= old_state
->pending
;
116 static void mtk_drm_plane_destroy_state(struct drm_plane
*plane
,
117 struct drm_plane_state
*state
)
119 __drm_atomic_helper_plane_destroy_state(state
);
120 kfree(to_mtk_plane_state(state
));
123 static const struct drm_plane_funcs mtk_plane_funcs
= {
124 .update_plane
= drm_atomic_helper_update_plane
,
125 .disable_plane
= drm_atomic_helper_disable_plane
,
126 .destroy
= drm_plane_cleanup
,
127 .reset
= mtk_plane_reset
,
128 .atomic_duplicate_state
= mtk_plane_duplicate_state
,
129 .atomic_destroy_state
= mtk_drm_plane_destroy_state
,
132 static int mtk_plane_atomic_check(struct drm_plane
*plane
,
133 struct drm_plane_state
*state
)
135 struct drm_framebuffer
*fb
= state
->fb
;
136 struct drm_crtc_state
*crtc_state
;
138 struct drm_rect dest
= {
141 .x2
= state
->crtc_x
+ state
->crtc_w
,
142 .y2
= state
->crtc_y
+ state
->crtc_h
,
144 struct drm_rect src
= {
145 /* 16.16 fixed point */
148 .x2
= state
->src_x
+ state
->src_w
,
149 .y2
= state
->src_y
+ state
->src_h
,
151 struct drm_rect clip
= { 0, };
156 if (!mtk_fb_get_gem_obj(fb
)) {
157 DRM_DEBUG_KMS("buffer is null\n");
164 crtc_state
= drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
165 if (IS_ERR(crtc_state
))
166 return PTR_ERR(crtc_state
);
168 clip
.x2
= crtc_state
->mode
.hdisplay
;
169 clip
.y2
= crtc_state
->mode
.vdisplay
;
171 return drm_plane_helper_check_update(plane
, state
->crtc
, fb
,
174 DRM_PLANE_HELPER_NO_SCALING
,
175 DRM_PLANE_HELPER_NO_SCALING
,
176 true, true, &visible
);
179 static void mtk_plane_atomic_update(struct drm_plane
*plane
,
180 struct drm_plane_state
*old_state
)
182 struct mtk_plane_state
*state
= to_mtk_plane_state(plane
->state
);
183 struct drm_crtc
*crtc
= state
->base
.crtc
;
184 struct drm_gem_object
*gem
;
185 struct mtk_drm_gem_obj
*mtk_gem
;
186 struct mtk_drm_plane
*mtk_plane
= to_mtk_plane(plane
);
187 struct drm_rect dest
= {
188 .x1
= state
->base
.crtc_x
,
189 .y1
= state
->base
.crtc_y
,
190 .x2
= state
->base
.crtc_x
+ state
->base
.crtc_w
,
191 .y2
= state
->base
.crtc_y
+ state
->base
.crtc_h
,
193 struct drm_rect clip
= { 0, };
198 clip
.x2
= state
->base
.crtc
->state
->mode
.hdisplay
;
199 clip
.y2
= state
->base
.crtc
->state
->mode
.vdisplay
;
200 drm_rect_intersect(&dest
, &clip
);
202 gem
= mtk_fb_get_gem_obj(state
->base
.fb
);
203 mtk_gem
= to_mtk_gem_obj(gem
);
204 mtk_plane_enable(mtk_plane
, true, mtk_gem
->dma_addr
, &dest
);
207 static void mtk_plane_atomic_disable(struct drm_plane
*plane
,
208 struct drm_plane_state
*old_state
)
210 struct mtk_plane_state
*state
= to_mtk_plane_state(plane
->state
);
212 state
->pending
.enable
= false;
213 wmb(); /* Make sure the above parameter is set before update */
214 state
->pending
.dirty
= true;
217 static const struct drm_plane_helper_funcs mtk_plane_helper_funcs
= {
218 .atomic_check
= mtk_plane_atomic_check
,
219 .atomic_update
= mtk_plane_atomic_update
,
220 .atomic_disable
= mtk_plane_atomic_disable
,
223 int mtk_plane_init(struct drm_device
*dev
, struct mtk_drm_plane
*mtk_plane
,
224 unsigned long possible_crtcs
, enum drm_plane_type type
,
229 err
= drm_universal_plane_init(dev
, &mtk_plane
->base
, possible_crtcs
,
230 &mtk_plane_funcs
, formats
,
231 ARRAY_SIZE(formats
), type
, NULL
);
233 DRM_ERROR("failed to initialize plane\n");
237 drm_plane_helper_add(&mtk_plane
->base
, &mtk_plane_helper_funcs
);
238 mtk_plane
->idx
= zpos
;