dt-bindings: mailbox: Add Amlogic Meson MHU Bindings
[deliverable/linux.git] / drivers / gpu / drm / mediatek / mtk_drm_plane.c
1 /*
2 * Copyright (c) 2015 MediaTek Inc.
3 * Author: CK Hu <ck.hu@mediatek.com>
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 * 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.
13 */
14
15 #include <drm/drmP.h>
16 #include <drm/drm_atomic.h>
17 #include <drm/drm_atomic_helper.h>
18 #include <drm/drm_plane_helper.h>
19
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"
26
27 static const u32 formats[] = {
28 DRM_FORMAT_XRGB8888,
29 DRM_FORMAT_ARGB8888,
30 DRM_FORMAT_RGB565,
31 };
32
33 static void mtk_plane_enable(struct mtk_drm_plane *mtk_plane, bool enable,
34 dma_addr_t addr, struct drm_rect *dest)
35 {
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;
39 int x, y;
40
41 if (WARN_ON(!plane->state || (enable && !plane->state->fb)))
42 return;
43
44 if (plane->state->fb) {
45 pitch = plane->state->fb->pitches[0];
46 format = plane->state->fb->pixel_format;
47 } else {
48 pitch = 0;
49 format = DRM_FORMAT_RGBA8888;
50 }
51
52 x = plane->state->crtc_x;
53 y = plane->state->crtc_y;
54
55 if (x < 0) {
56 addr -= x * 4;
57 x = 0;
58 }
59
60 if (y < 0) {
61 addr -= y * pitch;
62 y = 0;
63 }
64
65 state->pending.enable = enable;
66 state->pending.pitch = pitch;
67 state->pending.format = format;
68 state->pending.addr = addr;
69 state->pending.x = x;
70 state->pending.y = y;
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;
75 }
76
77 static void mtk_plane_reset(struct drm_plane *plane)
78 {
79 struct mtk_plane_state *state;
80
81 if (plane->state) {
82 if (plane->state->fb)
83 drm_framebuffer_unreference(plane->state->fb);
84
85 state = to_mtk_plane_state(plane->state);
86 memset(state, 0, sizeof(*state));
87 } else {
88 state = kzalloc(sizeof(*state), GFP_KERNEL);
89 if (!state)
90 return;
91 plane->state = &state->base;
92 }
93
94 state->base.plane = plane;
95 state->pending.format = DRM_FORMAT_RGB565;
96 }
97
98 static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
99 {
100 struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
101 struct mtk_plane_state *state;
102
103 state = kzalloc(sizeof(*state), GFP_KERNEL);
104 if (!state)
105 return NULL;
106
107 __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
108
109 WARN_ON(state->base.plane != plane);
110
111 state->pending = old_state->pending;
112
113 return &state->base;
114 }
115
116 static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
117 struct drm_plane_state *state)
118 {
119 __drm_atomic_helper_plane_destroy_state(state);
120 kfree(to_mtk_plane_state(state));
121 }
122
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,
130 };
131
132 static int mtk_plane_atomic_check(struct drm_plane *plane,
133 struct drm_plane_state *state)
134 {
135 struct drm_framebuffer *fb = state->fb;
136 struct drm_crtc_state *crtc_state;
137 bool visible;
138 struct drm_rect dest = {
139 .x1 = state->crtc_x,
140 .y1 = state->crtc_y,
141 .x2 = state->crtc_x + state->crtc_w,
142 .y2 = state->crtc_y + state->crtc_h,
143 };
144 struct drm_rect src = {
145 /* 16.16 fixed point */
146 .x1 = state->src_x,
147 .y1 = state->src_y,
148 .x2 = state->src_x + state->src_w,
149 .y2 = state->src_y + state->src_h,
150 };
151 struct drm_rect clip = { 0, };
152
153 if (!fb)
154 return 0;
155
156 if (!mtk_fb_get_gem_obj(fb)) {
157 DRM_DEBUG_KMS("buffer is null\n");
158 return -EFAULT;
159 }
160
161 if (!state->crtc)
162 return 0;
163
164 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
165 if (IS_ERR(crtc_state))
166 return PTR_ERR(crtc_state);
167
168 clip.x2 = crtc_state->mode.hdisplay;
169 clip.y2 = crtc_state->mode.vdisplay;
170
171 return drm_plane_helper_check_update(plane, state->crtc, fb,
172 &src, &dest, &clip,
173 state->rotation,
174 DRM_PLANE_HELPER_NO_SCALING,
175 DRM_PLANE_HELPER_NO_SCALING,
176 true, true, &visible);
177 }
178
179 static void mtk_plane_atomic_update(struct drm_plane *plane,
180 struct drm_plane_state *old_state)
181 {
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,
192 };
193 struct drm_rect clip = { 0, };
194
195 if (!crtc)
196 return;
197
198 clip.x2 = state->base.crtc->state->mode.hdisplay;
199 clip.y2 = state->base.crtc->state->mode.vdisplay;
200 drm_rect_intersect(&dest, &clip);
201
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);
205 }
206
207 static void mtk_plane_atomic_disable(struct drm_plane *plane,
208 struct drm_plane_state *old_state)
209 {
210 struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
211
212 state->pending.enable = false;
213 wmb(); /* Make sure the above parameter is set before update */
214 state->pending.dirty = true;
215 }
216
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,
221 };
222
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,
225 unsigned int zpos)
226 {
227 int err;
228
229 err = drm_universal_plane_init(dev, &mtk_plane->base, possible_crtcs,
230 &mtk_plane_funcs, formats,
231 ARRAY_SIZE(formats), type, NULL);
232 if (err) {
233 DRM_ERROR("failed to initialize plane\n");
234 return err;
235 }
236
237 drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs);
238 mtk_plane->idx = zpos;
239
240 return 0;
241 }
This page took 0.082162 seconds and 5 git commands to generate.