2 * Copyright (c) 2015 MediaTek Inc.
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,
173 DRM_PLANE_HELPER_NO_SCALING,
174 DRM_PLANE_HELPER_NO_SCALING,
175 true, true, &visible);
178 static void mtk_plane_atomic_update(struct drm_plane *plane,
179 struct drm_plane_state *old_state)
181 struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
182 struct drm_crtc *crtc = state->base.crtc;
183 struct drm_gem_object *gem;
184 struct mtk_drm_gem_obj *mtk_gem;
185 struct mtk_drm_plane *mtk_plane = to_mtk_plane(plane);
186 struct drm_rect dest = {
187 .x1 = state->base.crtc_x,
188 .y1 = state->base.crtc_y,
189 .x2 = state->base.crtc_x + state->base.crtc_w,
190 .y2 = state->base.crtc_y + state->base.crtc_h,
192 struct drm_rect clip = { 0, };
197 clip.x2 = state->base.crtc->state->mode.hdisplay;
198 clip.y2 = state->base.crtc->state->mode.vdisplay;
199 drm_rect_intersect(&dest, &clip);
201 gem = mtk_fb_get_gem_obj(state->base.fb);
202 mtk_gem = to_mtk_gem_obj(gem);
203 mtk_plane_enable(mtk_plane, true, mtk_gem->dma_addr, &dest);
206 static void mtk_plane_atomic_disable(struct drm_plane *plane,
207 struct drm_plane_state *old_state)
209 struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
211 state->pending.enable = false;
212 wmb(); /* Make sure the above parameter is set before update */
213 state->pending.dirty = true;
216 static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
217 .atomic_check = mtk_plane_atomic_check,
218 .atomic_update = mtk_plane_atomic_update,
219 .atomic_disable = mtk_plane_atomic_disable,
222 int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
223 unsigned long possible_crtcs, enum drm_plane_type type,
228 err = drm_universal_plane_init(dev, &mtk_plane->base, possible_crtcs,
229 &mtk_plane_funcs, formats,
230 ARRAY_SIZE(formats), type, NULL);
232 DRM_ERROR("failed to initialize plane\n");
236 drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs);
237 mtk_plane->idx = zpos;