2 * drivers/amlogic/drm/meson_drv.c
4 * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
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.
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
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>
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>
37 #include "meson_fbdev.h"
38 #ifdef CONFIG_DRM_MESON_USE_ION
39 #include "meson_gem.h"
42 #include "meson_drv.h"
43 #include "meson_vpu_pipeline.h"
46 #define DRIVER_NAME "meson"
47 #define DRIVER_DESC "Amlogic Meson DRM driver"
49 static void am_meson_fb_output_poll_changed(struct drm_device *dev)
51 #ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
52 struct meson_drm *priv = dev->dev_private;
54 drm_fbdev_cma_hotplug_event(priv->fbdev);
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,
65 .fb_create = drm_fb_cma_create,
69 int am_meson_register_crtc_funcs(struct drm_crtc *crtc,
70 const struct meson_crtc_funcs *crtc_funcs)
72 int pipe = drm_crtc_index(crtc);
73 struct meson_drm *priv = crtc->dev->dev_private;
75 if (pipe >= MESON_MAX_CRTC)
78 priv->crtc_funcs[pipe] = crtc_funcs;
82 EXPORT_SYMBOL(am_meson_register_crtc_funcs);
84 void am_meson_unregister_crtc_funcs(struct drm_crtc *crtc)
86 int pipe = drm_crtc_index(crtc);
87 struct meson_drm *priv = crtc->dev->dev_private;
89 if (pipe >= MESON_MAX_CRTC)
92 priv->crtc_funcs[pipe] = NULL;
94 EXPORT_SYMBOL(am_meson_unregister_crtc_funcs);
96 static int am_meson_enable_vblank(struct drm_device *dev, unsigned int crtc)
101 static void am_meson_disable_vblank(struct drm_device *dev, unsigned int crtc)
105 static void am_meson_load(struct drm_device *dev)
108 struct meson_drm *priv = dev->dev_private;
109 struct drm_crtc *crtc = priv->crtc;
110 int pipe = drm_crtc_index(crtc);
112 if (priv->crtc_funcs[pipe] &&
113 priv->crtc_funcs[pipe]->loader_protect)
114 priv->crtc_funcs[pipe]->loader_protect(crtc, true);
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),
125 static const struct file_operations fops = {
126 .owner = THIS_MODULE,
128 .release = drm_release,
129 .unlocked_ioctl = drm_ioctl,
131 .compat_ioctl = drm_compat_ioctl,
136 #ifdef CONFIG_DRM_MESON_USE_ION
137 .mmap = am_meson_gem_mmap,
139 .mmap = drm_gem_cma_mmap,
143 static struct drm_driver meson_driver = {
144 /*driver_features setting move to probe functions*/
145 .driver_features = 0,
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,
154 #ifdef CONFIG_DRM_MESON_USE_ION
156 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
157 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
159 .gem_prime_export = drm_gem_prime_export,
160 .gem_prime_get_sg_table = am_meson_gem_prime_get_sg_table,
162 .gem_prime_import = drm_gem_prime_import,
164 * If gem_prime_import_sg_table is NULL,only buffer created
165 * by meson driver can be imported ok.
167 .gem_prime_import_sg_table = am_meson_gem_prime_import_sg_table,
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,
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),
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,
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,
210 static int am_meson_drm_bind(struct device *dev)
212 struct meson_drm *priv;
213 struct drm_device *drm;
214 struct platform_device *pdev = to_platform_device(dev);
217 meson_driver.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
218 DRIVER_MODESET | DRIVER_PRIME |
219 DRIVER_ATOMIC | DRIVER_IRQ_SHARED;
221 drm = drm_dev_alloc(&meson_driver, dev);
225 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
230 drm->dev_private = priv;
233 dev_set_drvdata(dev, priv);
235 #ifdef CONFIG_DRM_MESON_USE_ION
236 ret = am_meson_gem_create(priv);
241 vpu_topology_init(pdev, priv);
242 meson_vpu_block_state_init(priv, priv->pipeline);
244 drm_mode_config_init(drm);
246 /* Try to bind all sub drivers. */
247 ret = component_bind_all(dev, drm);
250 DRM_INFO("mode_config crtc number:%d\n", drm->mode_config.num_crtc);
252 ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
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;
262 * enable drm irq mode.
263 * - with irq_enabled = true, we can use the vblank feature.
265 drm->irq_enabled = true;
267 drm_kms_helper_poll_init(drm);
271 #ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
272 ret = am_meson_drm_fbdev_init(drm);
276 ret = drm_dev_register(drm, 0);
284 #ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
285 am_meson_drm_fbdev_fini(drm);
288 drm_kms_helper_poll_fini(drm);
289 drm->irq_enabled = false;
290 drm_vblank_cleanup(drm);
292 component_unbind_all(dev, drm);
294 drm_mode_config_cleanup(drm);
295 #ifdef CONFIG_DRM_MESON_USE_ION
296 am_meson_gem_cleanup(drm->dev_private);
299 drm->dev_private = NULL;
300 dev_set_drvdata(dev, NULL);
307 static void am_meson_drm_unbind(struct device *dev)
309 struct drm_device *drm = dev_get_drvdata(dev);
311 drm_dev_unregister(drm);
312 #ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
313 am_meson_drm_fbdev_fini(drm);
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);
323 drm->dev_private = NULL;
324 dev_set_drvdata(dev, NULL);
328 static int compare_of(struct device *dev, void *data)
330 struct device_node *np = data;
332 return dev->of_node == np;
335 static void am_meson_add_endpoints(struct device *dev,
336 struct component_match **match,
337 struct device_node *port)
339 struct device_node *ep, *remote;
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)) {
346 } else if (!of_device_is_available(remote->parent)) {
350 component_match_add(dev, match, compare_of, remote);
355 static const struct component_master_ops am_meson_drm_ops = {
356 .bind = am_meson_drm_bind,
357 .unbind = am_meson_drm_unbind,
360 static bool am_meson_drv_use_osd(void)
362 struct device_node *node;
366 node = of_find_node_by_path("/meson-fb");
368 ret = of_property_read_string(node, "status", &str);
370 DRM_INFO("get 'status' failed:%d\n", ret);
374 if (strcmp(str, "okay") && strcmp(str, "ok")) {
375 DRM_INFO("device %s status is %s\n",
378 DRM_INFO("device %s status is %s\n",
386 static int am_meson_drv_probe_prune(struct platform_device *pdev)
388 struct device *dev = &pdev->dev;
389 struct meson_drm *priv;
390 struct drm_device *drm;
393 /*driver_features reset to DRIVER_GEM | DRIVER_PRIME, for prune drm*/
394 meson_driver.driver_features = DRIVER_GEM | DRIVER_PRIME;
396 drm = drm_dev_alloc(&meson_driver, dev);
400 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
405 drm->dev_private = priv;
409 platform_set_drvdata(pdev, priv);
411 #ifdef CONFIG_DRM_MESON_USE_ION
412 ret = am_meson_gem_create(priv);
417 ret = drm_dev_register(drm, 0);
424 #ifdef CONFIG_DRM_MESON_USE_ION
425 am_meson_gem_cleanup(drm->dev_private);
428 drm->dev_private = NULL;
429 platform_set_drvdata(pdev, NULL);
435 static int am_meson_drv_remove_prune(struct platform_device *pdev)
437 struct drm_device *drm = platform_get_drvdata(pdev);
439 drm_dev_unregister(drm);
440 #ifdef CONFIG_DRM_MESON_USE_ION
441 am_meson_gem_cleanup(drm->dev_private);
443 drm->dev_private = NULL;
444 platform_set_drvdata(pdev, NULL);
450 static int am_meson_drv_probe(struct platform_device *pdev)
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;
458 if (am_meson_drv_use_osd())
459 return am_meson_drv_probe_prune(pdev);
465 * Bind the crtc ports first, so that
466 * drm_of_find_possible_crtcs called from encoder .bind callbacks
470 port = of_parse_phandle(np, "ports", i);
474 if (!of_device_is_available(port->parent)) {
479 component_match_add(dev, &match, compare_of, port->parent);
484 dev_err(dev, "missing 'ports' property.\n");
489 dev_err(dev, "No available vout found for display-subsystem.\n");
494 * For each bound crtc, bind the encoders attached to its
498 port = of_parse_phandle(np, "ports", i);
502 if (!of_device_is_available(port->parent)) {
507 am_meson_add_endpoints(dev, &match, port);
511 return component_master_add_with_match(dev, &am_meson_drm_ops, match);
514 static int am_meson_drv_remove(struct platform_device *pdev)
516 if (am_meson_drv_use_osd())
517 return am_meson_drv_remove_prune(pdev);
519 component_master_del(&pdev->dev, &am_meson_drm_ops);
523 static const struct of_device_id am_meson_drm_dt_match[] = {
524 { .compatible = "amlogic,drm-subsystem" },
527 MODULE_DEVICE_TABLE(of, am_meson_drm_dt_match);
529 static struct platform_driver am_meson_drm_platform_driver = {
530 .probe = am_meson_drv_probe,
531 .remove = am_meson_drv_remove,
533 .owner = THIS_MODULE,
535 .of_match_table = am_meson_drm_dt_match,
539 module_platform_driver(am_meson_drm_platform_driver);
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");