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