amlogic: drm: don't call irq in crtc init stage
[platform/kernel/linux-amlogic.git] / drivers / amlogic / drm / meson_drv.c
1 /*
2  * drivers/amlogic/drm/meson_drv.c
3  *
4  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
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  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/mutex.h>
21 #include <linux/platform_device.h>
22 #include <linux/of_device.h>
23 #include <linux/of_graph.h>
24 #include <linux/component.h>
25
26 #include <drm/drmP.h>
27 #include <drm/drm_atomic.h>
28 #include <drm/drm_atomic_helper.h>
29 #include <drm/drm_flip_work.h>
30 #include <drm/drm_crtc_helper.h>
31 #include <drm/drm_plane_helper.h>
32 #include <drm/drm_gem_cma_helper.h>
33 #include <drm/drm_fb_cma_helper.h>
34 #include <drm/drm_rect.h>
35 #include <drm/drm_fb_helper.h>
36
37 #include "meson_fbdev.h"
38 #ifdef CONFIG_DRM_MESON_USE_ION
39 #include "meson_gem.h"
40 #include "meson_fb.h"
41 #endif
42 #include "meson_drv.h"
43 #include "meson_vpu_pipeline.h"
44
45
46 #define DRIVER_NAME "meson"
47 #define DRIVER_DESC "Amlogic Meson DRM driver"
48
49 static void am_meson_fb_output_poll_changed(struct drm_device *dev)
50 {
51 #ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
52         struct meson_drm *priv = dev->dev_private;
53
54         drm_fbdev_cma_hotplug_event(priv->fbdev);
55 #endif
56 }
57
58 static const struct drm_mode_config_funcs meson_mode_config_funcs = {
59         .output_poll_changed = am_meson_fb_output_poll_changed,
60         .atomic_check        = drm_atomic_helper_check,
61         .atomic_commit       = drm_atomic_helper_commit,
62 #ifdef CONFIG_DRM_MESON_USE_ION
63         .fb_create           = am_meson_fb_create,
64 #else
65         .fb_create           = drm_fb_cma_create,
66 #endif
67 };
68
69 int am_meson_register_crtc_funcs(struct drm_crtc *crtc,
70                                  const struct meson_crtc_funcs *crtc_funcs)
71 {
72         int pipe = drm_crtc_index(crtc);
73         struct meson_drm *priv = crtc->dev->dev_private;
74
75         if (pipe >= MESON_MAX_CRTC)
76                 return -EINVAL;
77
78         priv->crtc_funcs[pipe] = crtc_funcs;
79
80         return 0;
81 }
82 EXPORT_SYMBOL(am_meson_register_crtc_funcs);
83
84 void am_meson_unregister_crtc_funcs(struct drm_crtc *crtc)
85 {
86         int pipe = drm_crtc_index(crtc);
87         struct meson_drm *priv = crtc->dev->dev_private;
88
89         if (pipe >= MESON_MAX_CRTC)
90                 return;
91
92         priv->crtc_funcs[pipe] = NULL;
93 }
94 EXPORT_SYMBOL(am_meson_unregister_crtc_funcs);
95
96 static int am_meson_enable_vblank(struct drm_device *dev, unsigned int crtc)
97 {
98         return 0;
99 }
100
101 static void am_meson_disable_vblank(struct drm_device *dev, unsigned int crtc)
102 {
103 }
104
105 static void am_meson_load(struct drm_device *dev)
106 {
107 #if 0
108         struct meson_drm *priv = dev->dev_private;
109         struct drm_crtc *crtc = priv->crtc;
110         int pipe = drm_crtc_index(crtc);
111
112         if (priv->crtc_funcs[pipe] &&
113                 priv->crtc_funcs[pipe]->loader_protect)
114                 priv->crtc_funcs[pipe]->loader_protect(crtc, true);
115 #endif
116 }
117
118 #ifdef CONFIG_DRM_MESON_USE_ION
119 static const struct drm_ioctl_desc meson_ioctls[] = {
120         DRM_IOCTL_DEF_DRV(MESON_GEM_CREATE, am_meson_gem_create_ioctl,
121                 DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
122 };
123 #endif
124
125 static const struct file_operations fops = {
126         .owner          = THIS_MODULE,
127         .open           = drm_open,
128         .release        = drm_release,
129         .unlocked_ioctl = drm_ioctl,
130 #ifdef CONFIG_COMPAT
131         .compat_ioctl   = drm_compat_ioctl,
132 #endif
133         .poll           = drm_poll,
134         .read           = drm_read,
135         .llseek         = no_llseek,
136 #ifdef CONFIG_DRM_MESON_USE_ION
137         .mmap           = am_meson_gem_mmap,
138 #else
139         .mmap           = drm_gem_cma_mmap,
140 #endif
141 };
142
143 static struct drm_driver meson_driver = {
144         /*driver_features setting move to probe functions*/
145         .driver_features        = 0,
146         /* Vblank */
147         .enable_vblank          = am_meson_enable_vblank,
148         .disable_vblank         = am_meson_disable_vblank,
149         .get_vblank_counter     = drm_vblank_no_hw_counter,
150 #ifdef CONFIG_DEBUG_FS
151         .debugfs_init = meson_debugfs_init,
152         .debugfs_cleanup = meson_debugfs_cleanup,
153 #endif
154 #ifdef CONFIG_DRM_MESON_USE_ION
155         /* PRIME Ops */
156         .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
157         .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
158
159         .gem_prime_export       = drm_gem_prime_export,
160         .gem_prime_get_sg_table = am_meson_gem_prime_get_sg_table,
161
162         .gem_prime_import       = drm_gem_prime_import,
163         /*
164          * If gem_prime_import_sg_table is NULL,only buffer created
165          * by meson driver can be imported ok.
166          */
167         .gem_prime_import_sg_table = am_meson_gem_prime_import_sg_table,
168
169         .gem_prime_vmap         = am_meson_gem_prime_vmap,
170         .gem_prime_vunmap       = am_meson_gem_prime_vunmap,
171         .gem_prime_mmap         = am_meson_gem_prime_mmap,
172
173         /* GEM Ops */
174         .dumb_create                    = am_meson_gem_dumb_create,
175         .dumb_destroy           = am_meson_gem_dumb_destroy,
176         .dumb_map_offset                = am_meson_gem_dumb_map_offset,
177         .gem_free_object_unlocked       = am_meson_gem_object_free,
178         .gem_vm_ops                     = &drm_gem_cma_vm_ops,
179         .ioctls                 = meson_ioctls,
180         .num_ioctls             = ARRAY_SIZE(meson_ioctls),
181 #else
182         /* PRIME Ops */
183         .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
184         .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
185         .gem_prime_import       = drm_gem_prime_import,
186         .gem_prime_export       = drm_gem_prime_export,
187         .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
188         .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
189         .gem_prime_vmap         = drm_gem_cma_prime_vmap,
190         .gem_prime_vunmap       = drm_gem_cma_prime_vunmap,
191         .gem_prime_mmap         = drm_gem_cma_prime_mmap,
192
193         /* GEM Ops */
194         .dumb_create            = drm_gem_cma_dumb_create,
195         .dumb_destroy           = drm_gem_dumb_destroy,
196         .dumb_map_offset        = drm_gem_cma_dumb_map_offset,
197         .gem_free_object_unlocked = drm_gem_cma_free_object,
198         .gem_vm_ops             = &drm_gem_cma_vm_ops,
199 #endif
200
201         /* Misc */
202         .fops                   = &fops,
203         .name                   = DRIVER_NAME,
204         .desc                   = DRIVER_DESC,
205         .date                   = "20180321",
206         .major                  = 1,
207         .minor                  = 0,
208 };
209
210 static int am_meson_drm_bind(struct device *dev)
211 {
212         struct meson_drm *priv;
213         struct drm_device *drm;
214         struct platform_device *pdev = to_platform_device(dev);
215         int ret = 0;
216
217         meson_driver.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
218                 DRIVER_MODESET | DRIVER_PRIME |
219                 DRIVER_ATOMIC | DRIVER_IRQ_SHARED;
220
221         drm = drm_dev_alloc(&meson_driver, dev);
222         if (!drm)
223                 return -ENOMEM;
224
225         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
226         if (!priv) {
227                 ret = -ENOMEM;
228                 goto err_free1;
229         }
230         drm->dev_private = priv;
231         priv->drm = drm;
232         priv->dev = dev;
233         dev_set_drvdata(dev, priv);
234
235 #ifdef CONFIG_DRM_MESON_USE_ION
236         ret = am_meson_gem_create(priv);
237         if (ret)
238                 goto err_free2;
239 #endif
240
241         vpu_topology_init(pdev, priv);
242         meson_vpu_block_state_init(priv, priv->pipeline);
243
244         drm_mode_config_init(drm);
245
246         /* Try to bind all sub drivers. */
247         ret = component_bind_all(dev, drm);
248         if (ret)
249                 goto err_gem;
250         DRM_INFO("mode_config crtc number:%d\n", drm->mode_config.num_crtc);
251
252         ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
253         if (ret)
254                 goto err_unbind_all;
255
256         drm_mode_config_reset(drm);
257         drm->mode_config.max_width = 4096;
258         drm->mode_config.max_height = 4096;
259         drm->mode_config.funcs = &meson_mode_config_funcs;
260         drm->mode_config.allow_fb_modifiers = true;
261         /*
262          * enable drm irq mode.
263          * - with irq_enabled = true, we can use the vblank feature.
264          */
265         drm->irq_enabled = true;
266
267         drm_kms_helper_poll_init(drm);
268
269         am_meson_load(drm);
270
271 #ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
272         ret = am_meson_drm_fbdev_init(drm);
273         if (ret)
274                 goto err_poll_fini;
275 #endif
276         ret = drm_dev_register(drm, 0);
277         if (ret)
278                 goto err_fbdev_fini;
279
280         return 0;
281
282
283 err_fbdev_fini:
284 #ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
285         am_meson_drm_fbdev_fini(drm);
286 err_poll_fini:
287 #endif
288         drm_kms_helper_poll_fini(drm);
289         drm->irq_enabled = false;
290         drm_vblank_cleanup(drm);
291 err_unbind_all:
292         component_unbind_all(dev, drm);
293 err_gem:
294         drm_mode_config_cleanup(drm);
295 #ifdef CONFIG_DRM_MESON_USE_ION
296         am_meson_gem_cleanup(drm->dev_private);
297 err_free2:
298 #endif
299         drm->dev_private = NULL;
300         dev_set_drvdata(dev, NULL);
301 err_free1:
302         drm_dev_unref(drm);
303
304         return ret;
305 }
306
307 static void am_meson_drm_unbind(struct device *dev)
308 {
309         struct drm_device *drm = dev_get_drvdata(dev);
310
311         drm_dev_unregister(drm);
312 #ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
313         am_meson_drm_fbdev_fini(drm);
314 #endif
315         drm_kms_helper_poll_fini(drm);
316         drm->irq_enabled = false;
317         drm_vblank_cleanup(drm);
318         component_unbind_all(dev, drm);
319         drm_mode_config_cleanup(drm);
320 #ifdef CONFIG_DRM_MESON_USE_ION
321         am_meson_gem_cleanup(drm->dev_private);
322 #endif
323         drm->dev_private = NULL;
324         dev_set_drvdata(dev, NULL);
325         drm_dev_unref(drm);
326 }
327
328 static int compare_of(struct device *dev, void *data)
329 {
330         struct device_node *np = data;
331
332         return dev->of_node == np;
333 }
334
335 static void am_meson_add_endpoints(struct device *dev,
336                                    struct component_match **match,
337                                    struct device_node *port)
338 {
339         struct device_node *ep, *remote;
340
341         for_each_child_of_node(port, ep) {
342                 remote = of_graph_get_remote_port_parent(ep);
343                 if (!remote || !of_device_is_available(remote)) {
344                         of_node_put(remote);
345                         continue;
346                 } else if (!of_device_is_available(remote->parent)) {
347                         of_node_put(remote);
348                         continue;
349                 }
350                 component_match_add(dev, match, compare_of, remote);
351                 of_node_put(remote);
352         }
353 }
354
355 static const struct component_master_ops am_meson_drm_ops = {
356         .bind = am_meson_drm_bind,
357         .unbind = am_meson_drm_unbind,
358 };
359
360 static bool am_meson_drv_use_osd(void)
361 {
362         struct device_node *node;
363         const  char *str;
364         int ret;
365
366         node = of_find_node_by_path("/meson-fb");
367         if (node) {
368                 ret = of_property_read_string(node, "status", &str);
369                 if (ret) {
370                         DRM_INFO("get 'status' failed:%d\n", ret);
371                         return false;
372                 }
373
374                 if (strcmp(str, "okay") && strcmp(str, "ok")) {
375                         DRM_INFO("device %s status is %s\n",
376                                 node->name, str);
377                 } else {
378                         DRM_INFO("device %s status is %s\n",
379                                 node->name, str);
380                         return true;
381                 }
382         }
383         return false;
384 }
385
386 static int am_meson_drv_probe_prune(struct platform_device *pdev)
387 {
388         struct device *dev = &pdev->dev;
389         struct meson_drm *priv;
390         struct drm_device *drm;
391         int ret;
392
393         /*driver_features reset to DRIVER_GEM | DRIVER_PRIME, for prune drm*/
394         meson_driver.driver_features = DRIVER_GEM | DRIVER_PRIME;
395
396         drm = drm_dev_alloc(&meson_driver, dev);
397         if (!drm)
398                 return -ENOMEM;
399
400         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
401         if (!priv) {
402                 ret = -ENOMEM;
403                 goto err_free1;
404         }
405         drm->dev_private = priv;
406         priv->drm = drm;
407         priv->dev = dev;
408
409         platform_set_drvdata(pdev, priv);
410
411 #ifdef CONFIG_DRM_MESON_USE_ION
412         ret = am_meson_gem_create(priv);
413         if (ret)
414                 goto err_free2;
415 #endif
416
417         ret = drm_dev_register(drm, 0);
418         if (ret)
419                 goto err_gem;
420
421         return 0;
422
423 err_gem:
424 #ifdef CONFIG_DRM_MESON_USE_ION
425         am_meson_gem_cleanup(drm->dev_private);
426 err_free2:
427 #endif
428         drm->dev_private = NULL;
429         platform_set_drvdata(pdev, NULL);
430 err_free1:
431         drm_dev_unref(drm);
432         return ret;
433 }
434
435 static int am_meson_drv_remove_prune(struct platform_device *pdev)
436 {
437         struct drm_device *drm = platform_get_drvdata(pdev);
438
439         drm_dev_unregister(drm);
440 #ifdef CONFIG_DRM_MESON_USE_ION
441         am_meson_gem_cleanup(drm->dev_private);
442 #endif
443         drm->dev_private = NULL;
444         platform_set_drvdata(pdev, NULL);
445         drm_dev_unref(drm);
446
447         return 0;
448 }
449
450 static int am_meson_drv_probe(struct platform_device *pdev)
451 {
452         struct device *dev = &pdev->dev;
453         struct device_node *np = dev->of_node;
454         struct device_node *port;
455         struct component_match *match = NULL;
456         int i;
457
458         if (am_meson_drv_use_osd())
459                 return am_meson_drv_probe_prune(pdev);
460
461         if (!np)
462                 return -ENODEV;
463
464         /*
465          * Bind the crtc ports first, so that
466          * drm_of_find_possible_crtcs called from encoder .bind callbacks
467          * works as expected.
468          */
469         for (i = 0;; i++) {
470                 port = of_parse_phandle(np, "ports", i);
471                 if (!port)
472                         break;
473
474                 if (!of_device_is_available(port->parent)) {
475                         of_node_put(port);
476                         continue;
477                 }
478
479                 component_match_add(dev, &match, compare_of, port->parent);
480                 of_node_put(port);
481         }
482
483         if (i == 0) {
484                 dev_err(dev, "missing 'ports' property.\n");
485                 return -ENODEV;
486         }
487
488         if (!match) {
489                 dev_err(dev, "No available vout found for display-subsystem.\n");
490                 return -ENODEV;
491         }
492
493         /*
494          * For each bound crtc, bind the encoders attached to its
495          * remote endpoint.
496          */
497         for (i = 0;; i++) {
498                 port = of_parse_phandle(np, "ports", i);
499                 if (!port)
500                         break;
501
502                 if (!of_device_is_available(port->parent)) {
503                         of_node_put(port);
504                         continue;
505                 }
506
507                 am_meson_add_endpoints(dev, &match, port);
508                 of_node_put(port);
509         }
510
511         return component_master_add_with_match(dev, &am_meson_drm_ops, match);
512 }
513
514 static int am_meson_drv_remove(struct platform_device *pdev)
515 {
516         if (am_meson_drv_use_osd())
517                 return am_meson_drv_remove_prune(pdev);
518
519         component_master_del(&pdev->dev, &am_meson_drm_ops);
520         return 0;
521 }
522
523 static const struct of_device_id am_meson_drm_dt_match[] = {
524         { .compatible = "amlogic,drm-subsystem" },
525         {}
526 };
527 MODULE_DEVICE_TABLE(of, am_meson_drm_dt_match);
528
529 static struct platform_driver am_meson_drm_platform_driver = {
530         .probe      = am_meson_drv_probe,
531         .remove     = am_meson_drv_remove,
532         .driver     = {
533                 .owner  = THIS_MODULE,
534                 .name   = DRIVER_NAME,
535                 .of_match_table = am_meson_drm_dt_match,
536         },
537 };
538
539 module_platform_driver(am_meson_drm_platform_driver);
540
541 MODULE_AUTHOR("Jasper St. Pierre <jstpierre@mecheye.net>");
542 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
543 MODULE_AUTHOR("MultiMedia Amlogic <multimedia-sh@amlogic.com>");
544 MODULE_DESCRIPTION(DRIVER_DESC);
545 MODULE_LICENSE("GPL");