drm/exynos: use private plane for crtc
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / exynos / exynos_drm_plane.c
1 /*
2  * Copyright (C) 2011 Samsung Electronics Co.Ltd
3  * Authors: Joonyoung Shim <jy0922.shim@samsung.com>
4  *
5  * This program is free software; you can redistribute  it and/or modify it
6  * under  the terms of  the GNU General  Public License as published by the
7  * Free Software Foundation;  either version 2 of the  License, or (at your
8  * option) any later version.
9  *
10  */
11
12 #include "drmP.h"
13
14 #include "exynos_drm.h"
15 #include "exynos_drm_drv.h"
16 #include "exynos_drm_crtc.h"
17 #include "exynos_drm_encoder.h"
18
19 #define to_exynos_plane(x)      container_of(x, struct exynos_plane, base)
20
21 struct exynos_plane {
22         struct drm_plane                base;
23         struct exynos_drm_overlay       overlay;
24         bool                            enabled;
25 };
26
27 static const uint32_t formats[] = {
28         DRM_FORMAT_XRGB8888,
29         DRM_FORMAT_ARGB8888,
30         DRM_FORMAT_NV12,
31         DRM_FORMAT_NV12M,
32         DRM_FORMAT_NV12MT,
33 };
34
35 static int
36 exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
37                      struct drm_framebuffer *fb, int crtc_x, int crtc_y,
38                      unsigned int crtc_w, unsigned int crtc_h,
39                      uint32_t src_x, uint32_t src_y,
40                      uint32_t src_w, uint32_t src_h)
41 {
42         struct exynos_plane *exynos_plane = to_exynos_plane(plane);
43         struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
44         struct exynos_drm_crtc_pos pos;
45         int ret;
46
47         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
48
49         memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
50         pos.crtc_x = crtc_x;
51         pos.crtc_y = crtc_y;
52         pos.crtc_w = crtc_w;
53         pos.crtc_h = crtc_h;
54
55         /* considering 16.16 fixed point of source values */
56         pos.fb_x = src_x >> 16;
57         pos.fb_y = src_y >> 16;
58         pos.src_w = src_w >> 16;
59         pos.src_h = src_h >> 16;
60
61         ret = exynos_drm_overlay_update(overlay, fb, &crtc->mode, &pos);
62         if (ret < 0)
63                 return ret;
64
65         exynos_drm_fn_encoder(crtc, overlay,
66                         exynos_drm_encoder_crtc_mode_set);
67         exynos_drm_fn_encoder(crtc, &overlay->zpos,
68                         exynos_drm_encoder_crtc_plane_commit);
69
70         exynos_plane->enabled = true;
71
72         return 0;
73 }
74
75 static int exynos_disable_plane(struct drm_plane *plane)
76 {
77         struct exynos_plane *exynos_plane = to_exynos_plane(plane);
78         struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
79
80         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
81
82         if (!exynos_plane->enabled)
83                 return 0;
84
85         exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
86                         exynos_drm_encoder_crtc_disable);
87
88         exynos_plane->enabled = false;
89         exynos_plane->overlay.zpos = DEFAULT_ZPOS;
90
91         return 0;
92 }
93
94 static void exynos_plane_destroy(struct drm_plane *plane)
95 {
96         struct exynos_plane *exynos_plane = to_exynos_plane(plane);
97
98         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
99
100         exynos_disable_plane(plane);
101         drm_plane_cleanup(plane);
102         kfree(exynos_plane);
103 }
104
105 static struct drm_plane_funcs exynos_plane_funcs = {
106         .update_plane   = exynos_update_plane,
107         .disable_plane  = exynos_disable_plane,
108         .destroy        = exynos_plane_destroy,
109 };
110
111 struct drm_plane *exynos_plane_init(struct drm_device *dev,
112                                     unsigned int possible_crtcs, bool priv)
113 {
114         struct exynos_plane *exynos_plane;
115         int err;
116
117         exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
118         if (!exynos_plane) {
119                 DRM_ERROR("failed to allocate plane\n");
120                 return NULL;
121         }
122
123         exynos_plane->overlay.zpos = DEFAULT_ZPOS;
124
125         err = drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
126                               &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
127                               priv);
128         if (err) {
129                 DRM_ERROR("failed to initialize plane\n");
130                 kfree(exynos_plane);
131                 return NULL;
132         }
133
134         return &exynos_plane->base;
135 }
136
137 int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
138                                 struct drm_file *file_priv)
139 {
140         struct drm_exynos_plane_set_zpos *zpos_req = data;
141         struct drm_mode_object *obj;
142         struct drm_plane *plane;
143         struct exynos_plane *exynos_plane;
144         int ret = 0;
145
146         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
147
148         if (!drm_core_check_feature(dev, DRIVER_MODESET))
149                 return -EINVAL;
150
151         if (zpos_req->zpos < 0 || zpos_req->zpos >= MAX_PLANE) {
152                 if (zpos_req->zpos != DEFAULT_ZPOS) {
153                         DRM_ERROR("zpos not within limits\n");
154                         return -EINVAL;
155                 }
156         }
157
158         mutex_lock(&dev->mode_config.mutex);
159
160         obj = drm_mode_object_find(dev, zpos_req->plane_id,
161                         DRM_MODE_OBJECT_PLANE);
162         if (!obj) {
163                 DRM_DEBUG_KMS("Unknown plane ID %d\n",
164                               zpos_req->plane_id);
165                 ret = -EINVAL;
166                 goto out;
167         }
168
169         plane = obj_to_plane(obj);
170         exynos_plane = to_exynos_plane(plane);
171
172         exynos_plane->overlay.zpos = zpos_req->zpos;
173
174 out:
175         mutex_unlock(&dev->mode_config.mutex);
176         return ret;
177 }
178
179 struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_plane *plane)
180 {
181         struct exynos_plane *exynos_plane = to_exynos_plane(plane);
182
183         return &exynos_plane->overlay;
184 }