deeeab3afe8f74758a5fa10a8629f4b58f7af89f
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / rockchip / rockchip_drm_fb.c
1 /*
2  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3  * Author:Mark Yao <mark.yao@rock-chips.com>
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
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 <linux/kernel.h>
16 #include <drm/drm.h>
17 #include <drm/drmP.h>
18 #include <drm/drm_atomic.h>
19 #include <drm/drm_fb_helper.h>
20 #include <drm/drm_crtc_helper.h>
21 #include <linux/memblock.h>
22 #include <linux/iommu.h>
23
24 #include "rockchip_drm_drv.h"
25 #include "rockchip_drm_gem.h"
26
27 #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
28
29 struct rockchip_drm_fb {
30         struct drm_framebuffer fb;
31         dma_addr_t dma_addr[ROCKCHIP_MAX_FB_BUFFER];
32         struct drm_gem_object *obj[ROCKCHIP_MAX_FB_BUFFER];
33         struct rockchip_logo *logo;
34 };
35
36 dma_addr_t rockchip_fb_get_dma_addr(struct drm_framebuffer *fb,
37                                     unsigned int plane)
38 {
39         struct rockchip_drm_fb *rk_fb = to_rockchip_fb(fb);
40
41         if (WARN_ON(plane >= ROCKCHIP_MAX_FB_BUFFER))
42                 return 0;
43
44         return rk_fb->dma_addr[plane];
45 }
46
47 static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb)
48 {
49         struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
50         struct rockchip_drm_private *private = fb->dev->dev_private;
51         struct drm_gem_object *obj;
52         int i;
53
54         for (i = 0; i < ROCKCHIP_MAX_FB_BUFFER; i++) {
55                 obj = rockchip_fb->obj[i];
56                 if (obj)
57                         drm_gem_object_unreference_unlocked(obj);
58         }
59
60 #ifndef MODULE
61         if (rockchip_fb->logo) {
62                 struct rockchip_logo *logo = rockchip_fb->logo;
63
64                 if (!--logo->count) {
65                         void *start = phys_to_virt(logo->start);
66                         void *end = phys_to_virt(logo->size);
67
68                         if (private && private->domain) {
69                                 iommu_unmap(private->domain, logo->dma_addr,
70                                             logo->size);
71                                 drm_mm_remove_node(&logo->mm);
72                         } else {
73                                 dma_unmap_sg(fb->dev->dev, logo->sgt->sgl,
74                                              logo->sgt->nents, DMA_TO_DEVICE);
75                         }
76                         sg_free_table(logo->sgt);
77                         memblock_free(logo->start, logo->size);
78                         free_reserved_area(start, end, -1, "drm_logo");
79                 }
80         }
81 #else
82         WARN_ON(rockchip_fb->logo);
83 #endif
84
85         drm_framebuffer_cleanup(fb);
86         kfree(rockchip_fb);
87 }
88
89 static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb,
90                                          struct drm_file *file_priv,
91                                          unsigned int *handle)
92 {
93         struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
94
95         return drm_gem_handle_create(file_priv,
96                                      rockchip_fb->obj[0], handle);
97 }
98
99 static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
100         .destroy        = rockchip_drm_fb_destroy,
101         .create_handle  = rockchip_drm_fb_create_handle,
102 };
103
104 struct drm_framebuffer *
105 rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd,
106                   struct drm_gem_object **obj, struct rockchip_logo *logo,
107                   unsigned int num_planes)
108 {
109         struct rockchip_drm_fb *rockchip_fb;
110         struct rockchip_gem_object *rk_obj;
111         int ret = 0;
112         int i;
113
114         rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL);
115         if (!rockchip_fb)
116                 return ERR_PTR(-ENOMEM);
117
118         drm_helper_mode_fill_fb_struct(&rockchip_fb->fb, mode_cmd);
119
120         ret = drm_framebuffer_init(dev, &rockchip_fb->fb,
121                                    &rockchip_drm_fb_funcs);
122         if (ret) {
123                 dev_err(dev->dev, "Failed to initialize framebuffer: %d\n",
124                         ret);
125                 goto err_free_fb;
126         }
127
128         if (obj) {
129                 for (i = 0; i < num_planes; i++)
130                         rockchip_fb->obj[i] = obj[i];
131
132                 for (i = 0; i < num_planes; i++) {
133                         rk_obj = to_rockchip_obj(obj[i]);
134                         rockchip_fb->dma_addr[i] = rk_obj->dma_addr;
135                 }
136 #ifndef MODULE
137         } else if (logo) {
138                 rockchip_fb->dma_addr[0] = logo->dma_addr;
139                 rockchip_fb->logo = logo;
140                 logo->count++;
141 #endif
142         } else {
143                 ret = -EINVAL;
144                 dev_err(dev->dev, "Failed to find available buffer\n");
145                 goto err_deinit_drm_fb;
146         }
147
148         return &rockchip_fb->fb;
149
150 err_deinit_drm_fb:
151         drm_framebuffer_cleanup(&rockchip_fb->fb);
152 err_free_fb:
153         kfree(rockchip_fb);
154         return ERR_PTR(ret);
155 }
156
157 static struct drm_framebuffer *
158 rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
159                         struct drm_mode_fb_cmd2 *mode_cmd)
160 {
161         struct drm_framebuffer *fb;
162         struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER];
163         struct drm_gem_object *obj;
164         unsigned int hsub;
165         unsigned int vsub;
166         int num_planes;
167         int ret;
168         int i;
169
170         hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
171         vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
172         num_planes = min(drm_format_num_planes(mode_cmd->pixel_format),
173                          ROCKCHIP_MAX_FB_BUFFER);
174
175         for (i = 0; i < num_planes; i++) {
176                 unsigned int width = mode_cmd->width / (i ? hsub : 1);
177                 unsigned int height = mode_cmd->height / (i ? vsub : 1);
178                 unsigned int min_size;
179                 unsigned int bpp =
180                         drm_format_plane_bpp(mode_cmd->pixel_format, i);
181
182                 obj = drm_gem_object_lookup(dev, file_priv,
183                                             mode_cmd->handles[i]);
184                 if (!obj) {
185                         dev_err(dev->dev, "Failed to lookup GEM object\n");
186                         ret = -ENXIO;
187                         goto err_gem_object_unreference;
188                 }
189
190                 min_size = (height - 1) * mode_cmd->pitches[i] +
191                         mode_cmd->offsets[i] + roundup(width * bpp, 8) / 8;
192                 if (obj->size < min_size) {
193                         drm_gem_object_unreference_unlocked(obj);
194                         ret = -EINVAL;
195                         goto err_gem_object_unreference;
196                 }
197                 objs[i] = obj;
198         }
199
200         fb = rockchip_fb_alloc(dev, mode_cmd, objs, NULL, i);
201         if (IS_ERR(fb)) {
202                 ret = PTR_ERR(fb);
203                 goto err_gem_object_unreference;
204         }
205
206         return fb;
207
208 err_gem_object_unreference:
209         for (i--; i >= 0; i--)
210                 drm_gem_object_unreference_unlocked(objs[i]);
211         return ERR_PTR(ret);
212 }
213
214 static void rockchip_drm_output_poll_changed(struct drm_device *dev)
215 {
216         struct rockchip_drm_private *private = dev->dev_private;
217         struct drm_fb_helper *fb_helper = private->fbdev_helper;
218
219         if (fb_helper)
220                 drm_fb_helper_hotplug_event(fb_helper);
221 }
222
223 static void rockchip_crtc_wait_for_update(struct drm_crtc *crtc)
224 {
225         struct rockchip_drm_private *priv = crtc->dev->dev_private;
226         int pipe = drm_crtc_index(crtc);
227         const struct rockchip_crtc_funcs *crtc_funcs = priv->crtc_funcs[pipe];
228
229         if (crtc_funcs && crtc_funcs->wait_for_update)
230                 crtc_funcs->wait_for_update(crtc);
231 }
232
233 /*
234  * We can't use drm_atomic_helper_wait_for_vblanks() because rk3288 and rk3066
235  * have hardware counters for neither vblanks nor scanlines, which results in
236  * a race where:
237  *                              | <-- HW vsync irq and reg take effect
238  *             plane_commit --> |
239  *      get_vblank and wait --> |
240  *                              | <-- handle_vblank, vblank->count + 1
241  *               cleanup_fb --> |
242  *              iommu crash --> |
243  *                              | <-- HW vsync irq and reg take effect
244  *
245  * This function is equivalent but uses rockchip_crtc_wait_for_update() instead
246  * of waiting for vblank_count to change.
247  */
248 static void
249 rockchip_atomic_wait_for_complete(struct drm_device *dev, struct drm_atomic_state *old_state)
250 {
251         struct drm_crtc_state *old_crtc_state;
252         struct drm_crtc *crtc;
253         int i, ret;
254
255         for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
256                 /* No one cares about the old state, so abuse it for tracking
257                  * and store whether we hold a vblank reference (and should do a
258                  * vblank wait) in the ->enable boolean.
259                  */
260                 old_crtc_state->enable = false;
261
262                 if (!crtc->state->active)
263                         continue;
264
265                 if (!drm_atomic_helper_framebuffer_changed(dev,
266                                 old_state, crtc))
267                         continue;
268
269                 ret = drm_crtc_vblank_get(crtc);
270                 if (ret != 0)
271                         continue;
272
273                 old_crtc_state->enable = true;
274         }
275
276         for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
277                 if (!old_crtc_state->enable)
278                         continue;
279
280                 rockchip_crtc_wait_for_update(crtc);
281                 drm_crtc_vblank_put(crtc);
282         }
283 }
284
285 static void
286 rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit)
287 {
288         struct drm_atomic_state *state = commit->state;
289         struct drm_device *dev = commit->dev;
290
291         /*
292          * TODO: do fence wait here.
293          */
294
295         /*
296          * Rockchip crtc support runtime PM, can't update display planes
297          * when crtc is disabled.
298          *
299          * drm_atomic_helper_commit comments detail that:
300          *     For drivers supporting runtime PM the recommended sequence is
301          *
302          *     drm_atomic_helper_commit_modeset_disables(dev, state);
303          *
304          *     drm_atomic_helper_commit_modeset_enables(dev, state);
305          *
306          *     drm_atomic_helper_commit_planes(dev, state, true);
307          *
308          * See the kerneldoc entries for these three functions for more details.
309          */
310         drm_atomic_helper_commit_modeset_disables(dev, state);
311
312         drm_atomic_helper_commit_modeset_enables(dev, state);
313
314         drm_atomic_helper_commit_planes(dev, state, true);
315
316         rockchip_atomic_wait_for_complete(dev, state);
317
318         drm_atomic_helper_cleanup_planes(dev, state);
319
320         drm_atomic_state_free(state);
321 }
322
323 void rockchip_drm_atomic_work(struct work_struct *work)
324 {
325         struct rockchip_atomic_commit *commit = container_of(work,
326                                         struct rockchip_atomic_commit, work);
327
328         rockchip_atomic_commit_complete(commit);
329 }
330
331 int rockchip_drm_atomic_commit(struct drm_device *dev,
332                                struct drm_atomic_state *state,
333                                bool async)
334 {
335         struct rockchip_drm_private *private = dev->dev_private;
336         struct rockchip_atomic_commit *commit = &private->commit;
337         int ret;
338
339         ret = drm_atomic_helper_prepare_planes(dev, state);
340         if (ret)
341                 return ret;
342
343         /* serialize outstanding asynchronous commits */
344         mutex_lock(&commit->lock);
345         flush_work(&commit->work);
346
347         drm_atomic_helper_swap_state(dev, state);
348
349         commit->dev = dev;
350         commit->state = state;
351
352         if (async)
353                 schedule_work(&commit->work);
354         else
355                 rockchip_atomic_commit_complete(commit);
356
357         mutex_unlock(&commit->lock);
358
359         return 0;
360 }
361
362 static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
363         .fb_create = rockchip_user_fb_create,
364         .output_poll_changed = rockchip_drm_output_poll_changed,
365         .atomic_check = drm_atomic_helper_check,
366         .atomic_commit = rockchip_drm_atomic_commit,
367 };
368
369 struct drm_framebuffer *
370 rockchip_drm_framebuffer_init(struct drm_device *dev,
371                               struct drm_mode_fb_cmd2 *mode_cmd,
372                               struct drm_gem_object *obj)
373 {
374         struct drm_framebuffer *fb;
375
376         fb = rockchip_fb_alloc(dev, mode_cmd, &obj, NULL, 1);
377         if (IS_ERR(fb))
378                 return NULL;
379
380         return fb;
381 }
382
383 void rockchip_drm_mode_config_init(struct drm_device *dev)
384 {
385         dev->mode_config.min_width = 0;
386         dev->mode_config.min_height = 0;
387
388         /*
389          * set max width and height as default value(4096x4096).
390          * this value would be used to check framebuffer size limitation
391          * at drm_mode_addfb().
392          */
393         dev->mode_config.max_width = 4096;
394         dev->mode_config.max_height = 4096;
395
396         dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
397 }