c83da72344ae144d7a261a594a475bcd43a2bedf
[cascardo/linux.git] / drivers / gpu / drm / fsl-dcu / fsl_dcu_drm_plane.c
1 /*
2  * Copyright 2015 Freescale Semiconductor, Inc.
3  *
4  * Freescale DCU drm device driver
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <linux/regmap.h>
13
14 #include <drm/drmP.h>
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_crtc.h>
17 #include <drm/drm_crtc_helper.h>
18 #include <drm/drm_fb_cma_helper.h>
19 #include <drm/drm_gem_cma_helper.h>
20 #include <drm/drm_plane_helper.h>
21
22 #include "fsl_dcu_drm_drv.h"
23 #include "fsl_dcu_drm_plane.h"
24
25 static int fsl_dcu_drm_plane_index(struct drm_plane *plane)
26 {
27         struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
28         unsigned int total_layer = fsl_dev->soc->total_layer;
29         unsigned int index;
30
31         index = drm_plane_index(plane);
32         if (index < total_layer)
33                 return total_layer - index - 1;
34
35         dev_err(fsl_dev->dev, "No more layer left\n");
36         return -EINVAL;
37 }
38
39 static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
40                                           struct drm_plane_state *state)
41 {
42         struct drm_framebuffer *fb = state->fb;
43
44         if (!state->fb || !state->crtc)
45                 return 0;
46
47         switch (fb->pixel_format) {
48         case DRM_FORMAT_RGB565:
49         case DRM_FORMAT_RGB888:
50         case DRM_FORMAT_ARGB8888:
51         case DRM_FORMAT_BGRA4444:
52         case DRM_FORMAT_ARGB1555:
53         case DRM_FORMAT_YUV422:
54                 return 0;
55         default:
56                 return -EINVAL;
57         }
58 }
59
60 static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
61                                              struct drm_plane_state *old_state)
62 {
63         struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
64         unsigned int value;
65         int index, ret;
66
67         index = fsl_dcu_drm_plane_index(plane);
68         if (index < 0)
69                 return;
70
71         ret = regmap_read(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), &value);
72         if (ret)
73                 dev_err(fsl_dev->dev, "read DCU_INT_MASK failed\n");
74         value &= ~DCU_LAYER_EN;
75         ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), value);
76         if (ret)
77                 dev_err(fsl_dev->dev, "set DCU register failed\n");
78 }
79
80 static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
81                                             struct drm_plane_state *old_state)
82
83 {
84         struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
85         struct drm_plane_state *state = plane->state;
86         struct drm_framebuffer *fb = plane->state->fb;
87         struct drm_gem_cma_object *gem;
88         unsigned int alpha, bpp;
89         int index, ret;
90
91         if (!fb)
92                 return;
93
94         index = fsl_dcu_drm_plane_index(plane);
95         if (index < 0)
96                 return;
97
98         gem = drm_fb_cma_get_gem_obj(fb, 0);
99
100         switch (fb->pixel_format) {
101         case DRM_FORMAT_RGB565:
102                 bpp = FSL_DCU_RGB565;
103                 alpha = 0xff;
104                 break;
105         case DRM_FORMAT_RGB888:
106                 bpp = FSL_DCU_RGB888;
107                 alpha = 0xff;
108                 break;
109         case DRM_FORMAT_ARGB8888:
110                 bpp = FSL_DCU_ARGB8888;
111                 alpha = 0xff;
112                 break;
113         case DRM_FORMAT_BGRA4444:
114                 bpp = FSL_DCU_ARGB4444;
115                 alpha = 0xff;
116                 break;
117         case DRM_FORMAT_ARGB1555:
118                 bpp = FSL_DCU_ARGB1555;
119                 alpha = 0xff;
120                 break;
121         case DRM_FORMAT_YUV422:
122                 bpp = FSL_DCU_YUV422;
123                 alpha = 0xff;
124                 break;
125         default:
126                 return;
127         }
128
129         ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 1),
130                            DCU_LAYER_HEIGHT(state->crtc_h) |
131                            DCU_LAYER_WIDTH(state->crtc_w));
132         if (ret)
133                 goto set_failed;
134         ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 2),
135                            DCU_LAYER_POSY(state->crtc_y) |
136                            DCU_LAYER_POSX(state->crtc_x));
137         if (ret)
138                 goto set_failed;
139         ret = regmap_write(fsl_dev->regmap,
140                            DCU_CTRLDESCLN(index, 3), gem->paddr);
141         if (ret)
142                 goto set_failed;
143         ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4),
144                            DCU_LAYER_EN |
145                            DCU_LAYER_TRANS(alpha) |
146                            DCU_LAYER_BPP(bpp) |
147                            DCU_LAYER_AB(0));
148         if (ret)
149                 goto set_failed;
150         ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 5),
151                            DCU_LAYER_CKMAX_R(0xFF) |
152                            DCU_LAYER_CKMAX_G(0xFF) |
153                            DCU_LAYER_CKMAX_B(0xFF));
154         if (ret)
155                 goto set_failed;
156         ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 6),
157                            DCU_LAYER_CKMIN_R(0) |
158                            DCU_LAYER_CKMIN_G(0) |
159                            DCU_LAYER_CKMIN_B(0));
160         if (ret)
161                 goto set_failed;
162         ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 7), 0);
163         if (ret)
164                 goto set_failed;
165         ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 8),
166                            DCU_LAYER_FG_FCOLOR(0));
167         if (ret)
168                 goto set_failed;
169         ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 9),
170                            DCU_LAYER_BG_BCOLOR(0));
171         if (ret)
172                 goto set_failed;
173         if (!strcmp(fsl_dev->soc->name, "ls1021a")) {
174                 ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 10),
175                                    DCU_LAYER_POST_SKIP(0) |
176                                    DCU_LAYER_PRE_SKIP(0));
177                 if (ret)
178                         goto set_failed;
179         }
180         ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
181                                  DCU_MODE_DCU_MODE_MASK,
182                                  DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
183         if (ret)
184                 goto set_failed;
185         ret = regmap_write(fsl_dev->regmap,
186                            DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
187         if (ret)
188                 goto set_failed;
189         return;
190
191 set_failed:
192         dev_err(fsl_dev->dev, "set DCU register failed\n");
193 }
194
195 static void
196 fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
197                              const struct drm_plane_state *new_state)
198 {
199 }
200
201 static int
202 fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,
203                              const struct drm_plane_state *new_state)
204 {
205         return 0;
206 }
207
208 static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {
209         .atomic_check = fsl_dcu_drm_plane_atomic_check,
210         .atomic_disable = fsl_dcu_drm_plane_atomic_disable,
211         .atomic_update = fsl_dcu_drm_plane_atomic_update,
212         .cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
213         .prepare_fb = fsl_dcu_drm_plane_prepare_fb,
214 };
215
216 static void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
217 {
218         drm_plane_cleanup(plane);
219 }
220
221 static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
222         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
223         .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
224         .destroy = fsl_dcu_drm_plane_destroy,
225         .disable_plane = drm_atomic_helper_disable_plane,
226         .reset = drm_atomic_helper_plane_reset,
227         .update_plane = drm_atomic_helper_update_plane,
228 };
229
230 static const u32 fsl_dcu_drm_plane_formats[] = {
231         DRM_FORMAT_RGB565,
232         DRM_FORMAT_RGB888,
233         DRM_FORMAT_ARGB8888,
234         DRM_FORMAT_ARGB4444,
235         DRM_FORMAT_ARGB1555,
236         DRM_FORMAT_YUV422,
237 };
238
239 struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
240 {
241         struct drm_plane *primary;
242         int ret;
243
244         primary = kzalloc(sizeof(*primary), GFP_KERNEL);
245         if (!primary) {
246                 DRM_DEBUG_KMS("Failed to allocate primary plane\n");
247                 return NULL;
248         }
249
250         /* possible_crtc's will be filled in later by crtc_init */
251         ret = drm_universal_plane_init(dev, primary, 0,
252                                        &fsl_dcu_drm_plane_funcs,
253                                        fsl_dcu_drm_plane_formats,
254                                        ARRAY_SIZE(fsl_dcu_drm_plane_formats),
255                                        DRM_PLANE_TYPE_PRIMARY, NULL);
256         if (ret) {
257                 kfree(primary);
258                 primary = NULL;
259         }
260         drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
261
262         return primary;
263 }