fe32195fb249fa8d9175b5f5cce47ce5235a1f04
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / rockchip / rockchip_drm_plane.c
1 /*
2  * Copyright (C) ROCKCHIP, Inc.
3  * Author:yzq<yzq@rock-chips.com>
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13
14 #include <drm/drmP.h>
15
16 #include <drm/rockchip_drm.h>
17 #include "rockchip_drm_drv.h"
18 #include "rockchip_drm_encoder.h"
19 #include "rockchip_drm_fb.h"
20 #include "rockchip_drm_gem.h"
21
22 #define to_rockchip_plane(x)    container_of(x, struct rockchip_plane, base)
23
24 struct rockchip_plane {
25         struct drm_plane                base;
26         struct rockchip_drm_overlay     overlay;
27         bool                            enabled;
28 };
29
30 static const uint32_t formats[] = {
31         DRM_FORMAT_XRGB8888,
32         DRM_FORMAT_ARGB8888,
33         DRM_FORMAT_NV12,
34         DRM_FORMAT_NV12MT,
35 };
36
37 /*
38  * This function is to get X or Y size shown via screen. This needs length and
39  * start position of CRTC.
40  *
41  *      <--- length --->
42  * CRTC ----------------
43  *      ^ start        ^ end
44  *
45  * There are six cases from a to f.
46  *
47  *             <----- SCREEN ----->
48  *             0                 last
49  *   ----------|------------------|----------
50  * CRTCs
51  * a -------
52  *        b -------
53  *        c --------------------------
54  *                 d --------
55  *                           e -------
56  *                                  f -------
57  */
58 static int rockchip_plane_get_size(int start, unsigned length, unsigned last)
59 {
60         int end = start + length;
61         int size = 0;
62
63         if (start <= 0) {
64                 if (end > 0)
65                         size = min_t(unsigned, end, last);
66         } else if (start <= last) {
67                 size = min_t(unsigned, last - start, length);
68         }
69
70         return size;
71 }
72
73 int rockchip_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
74                           struct drm_framebuffer *fb, int crtc_x, int crtc_y,
75                           unsigned int crtc_w, unsigned int crtc_h,
76                           uint32_t src_x, uint32_t src_y,
77                           uint32_t src_w, uint32_t src_h)
78 {
79         struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
80         struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
81         unsigned int actual_w;
82         unsigned int actual_h;
83         int nr;
84         int i;
85
86         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
87
88         nr = rockchip_drm_fb_get_buf_cnt(fb);
89         for (i = 0; i < nr; i++) {
90                 struct rockchip_drm_gem_buf *buffer = rockchip_drm_fb_buffer(fb, i);
91
92                 if (!buffer) {
93                         DRM_LOG_KMS("buffer is null\n");
94                         return -EFAULT;
95                 }
96
97                 overlay->dma_addr[i] = buffer->dma_addr;
98
99                 DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
100                                 i, (unsigned long)overlay->dma_addr[i]);
101         }
102
103         actual_w = rockchip_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay);
104         actual_h = rockchip_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay);
105
106         if (crtc_x < 0) {
107                 if (actual_w)
108                         src_x -= crtc_x;
109                 crtc_x = 0;
110         }
111
112         if (crtc_y < 0) {
113                 if (actual_h)
114                         src_y -= crtc_y;
115                 crtc_y = 0;
116         }
117
118         /* set drm framebuffer data. */
119         overlay->fb_x = src_x;
120         overlay->fb_y = src_y;
121         overlay->fb_width = fb->width;
122         overlay->fb_height = fb->height;
123         overlay->src_width = src_w;
124         overlay->src_height = src_h;
125         overlay->bpp = fb->bits_per_pixel;
126         overlay->pitch = fb->pitches[0];
127         overlay->pixel_format = fb->pixel_format;
128
129         /* set overlay range to be displayed. */
130         overlay->crtc_x = crtc_x;
131         overlay->crtc_y = crtc_y;
132         overlay->crtc_width = actual_w;
133         overlay->crtc_height = actual_h;
134
135         /* set drm mode data. */
136         overlay->mode_width = crtc->mode.hdisplay;
137         overlay->mode_height = crtc->mode.vdisplay;
138         overlay->refresh = crtc->mode.vrefresh;
139         overlay->pixclock = crtc->mode.clock*1000;
140         overlay->scan_flag = crtc->mode.flags;
141
142 //      printk("--->yzq %s crtc->mode->refresh =%d \n",__func__,crtc->mode.vrefresh);
143         DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
144                         overlay->crtc_x, overlay->crtc_y,
145                         overlay->crtc_width, overlay->crtc_height);
146
147         rockchip_drm_fn_encoder(crtc, overlay, rockchip_drm_encoder_plane_mode_set);
148
149         return 0;
150 }
151
152 void rockchip_plane_commit(struct drm_plane *plane)
153 {
154         struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
155         struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
156
157         rockchip_drm_fn_encoder(plane->crtc, &overlay->zpos,
158                         rockchip_drm_encoder_plane_commit);
159 }
160
161 void rockchip_plane_dpms(struct drm_plane *plane, int mode)
162 {
163         struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
164         struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
165
166         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
167
168         if (mode == DRM_MODE_DPMS_ON) {
169                 if (rockchip_plane->enabled)
170                         return;
171
172                 rockchip_drm_fn_encoder(plane->crtc, &overlay->zpos,
173                                 rockchip_drm_encoder_plane_enable);
174
175                 rockchip_plane->enabled = true;
176         } else {
177                 if (!rockchip_plane->enabled)
178                         return;
179
180                 rockchip_drm_fn_encoder(plane->crtc, &overlay->zpos,
181                                 rockchip_drm_encoder_plane_disable);
182
183                 rockchip_plane->enabled = false;
184         }
185 }
186
187 static int
188 rockchip_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
189                      struct drm_framebuffer *fb, int crtc_x, int crtc_y,
190                      unsigned int crtc_w, unsigned int crtc_h,
191                      uint32_t src_x, uint32_t src_y,
192                      uint32_t src_w, uint32_t src_h)
193 {
194         int ret;
195
196         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
197
198         ret = rockchip_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
199                         crtc_w, crtc_h, src_x >> 16, src_y >> 16,
200                         src_w >> 16, src_h >> 16);
201         if (ret < 0)
202                 return ret;
203
204         plane->crtc = crtc;
205
206         rockchip_plane_commit(plane);
207         rockchip_plane_dpms(plane, DRM_MODE_DPMS_ON);
208
209         return 0;
210 }
211
212 static int rockchip_disable_plane(struct drm_plane *plane)
213 {
214         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
215
216         rockchip_plane_dpms(plane, DRM_MODE_DPMS_OFF);
217
218         return 0;
219 }
220
221 static void rockchip_plane_destroy(struct drm_plane *plane)
222 {
223         struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
224
225         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
226
227         rockchip_disable_plane(plane);
228         drm_plane_cleanup(plane);
229         kfree(rockchip_plane);
230 }
231
232 static int rockchip_plane_set_property(struct drm_plane *plane,
233                                      struct drm_property *property,
234                                      uint64_t val)
235 {
236         struct drm_device *dev = plane->dev;
237         struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
238         struct rockchip_drm_private *dev_priv = dev->dev_private;
239
240         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
241
242         if (property == dev_priv->plane_zpos_property) {
243                 rockchip_plane->overlay.zpos = val;
244                 return 0;
245         }
246
247         return -EINVAL;
248 }
249
250 static struct drm_plane_funcs rockchip_plane_funcs = {
251         .update_plane   = rockchip_update_plane,
252         .disable_plane  = rockchip_disable_plane,
253         .destroy        = rockchip_plane_destroy,
254         .set_property   = rockchip_plane_set_property,
255 };
256
257 static void rockchip_plane_attach_zpos_property(struct drm_plane *plane)
258 {
259         struct drm_device *dev = plane->dev;
260         struct rockchip_drm_private *dev_priv = dev->dev_private;
261         struct drm_property *prop;
262
263         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
264
265         prop = dev_priv->plane_zpos_property;
266         if (!prop) {
267                 prop = drm_property_create_range(dev, 0, "zpos", 0,
268                                                  MAX_PLANE - 1);
269                 if (!prop)
270                         return;
271
272                 dev_priv->plane_zpos_property = prop;
273         }
274
275         drm_object_attach_property(&plane->base, prop, 0);
276 }
277
278 struct drm_plane *rockchip_plane_init(struct drm_device *dev,
279                                     unsigned int possible_crtcs, bool priv)
280 {
281         struct rockchip_plane *rockchip_plane;
282         int err;
283
284         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
285
286         rockchip_plane = kzalloc(sizeof(struct rockchip_plane), GFP_KERNEL);
287         if (!rockchip_plane) {
288                 DRM_ERROR("failed to allocate plane\n");
289                 return NULL;
290         }
291
292         err = drm_plane_init(dev, &rockchip_plane->base, possible_crtcs,
293                               &rockchip_plane_funcs, formats, ARRAY_SIZE(formats),
294                               priv);
295         if (err) {
296                 DRM_ERROR("failed to initialize plane\n");
297                 kfree(rockchip_plane);
298                 return NULL;
299         }
300
301         if (priv)
302                 rockchip_plane->overlay.zpos = DEFAULT_ZPOS;
303         else
304                 rockchip_plane_attach_zpos_property(&rockchip_plane->base);
305
306         return &rockchip_plane->base;
307 }