]> Git Repo - linux.git/blob - drivers/gpu/drm/mediatek/mtk_drm_plane.c
Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[linux.git] / drivers / gpu / drm / mediatek / mtk_drm_plane.c
1 /*
2  * Copyright (c) 2015 MediaTek Inc.
3  * Author: CK Hu <[email protected]>
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                                              DRM_PLANE_HELPER_NO_SCALING,
174                                              DRM_PLANE_HELPER_NO_SCALING,
175                                              true, true, &visible);
176 }
177
178 static void mtk_plane_atomic_update(struct drm_plane *plane,
179                                     struct drm_plane_state *old_state)
180 {
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,
191         };
192         struct drm_rect clip = { 0, };
193
194         if (!crtc)
195                 return;
196
197         clip.x2 = state->base.crtc->state->mode.hdisplay;
198         clip.y2 = state->base.crtc->state->mode.vdisplay;
199         drm_rect_intersect(&dest, &clip);
200
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);
204 }
205
206 static void mtk_plane_atomic_disable(struct drm_plane *plane,
207                                      struct drm_plane_state *old_state)
208 {
209         struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
210
211         state->pending.enable = false;
212         wmb(); /* Make sure the above parameter is set before update */
213         state->pending.dirty = true;
214 }
215
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,
220 };
221
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,
224                    unsigned int zpos)
225 {
226         int err;
227
228         err = drm_universal_plane_init(dev, &mtk_plane->base, possible_crtcs,
229                                        &mtk_plane_funcs, formats,
230                                        ARRAY_SIZE(formats), type, NULL);
231         if (err) {
232                 DRM_ERROR("failed to initialize plane\n");
233                 return err;
234         }
235
236         drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs);
237         mtk_plane->idx = zpos;
238
239         return 0;
240 }
This page took 0.047515 seconds and 4 git commands to generate.