tidss_drv.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
  4. * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
  5. */
  6. #include <linux/console.h>
  7. #include <linux/of.h>
  8. #include <linux/module.h>
  9. #include <linux/pm_runtime.h>
  10. #include <linux/aperture.h>
  11. #include <drm/clients/drm_client_setup.h>
  12. #include <drm/drm_atomic.h>
  13. #include <drm/drm_atomic_helper.h>
  14. #include <drm/drm_crtc.h>
  15. #include <drm/drm_drv.h>
  16. #include <drm/drm_fbdev_dma.h>
  17. #include <drm/drm_gem_dma_helper.h>
  18. #include <drm/drm_managed.h>
  19. #include <drm/drm_module.h>
  20. #include <drm/drm_probe_helper.h>
  21. #include "tidss_dispc.h"
  22. #include "tidss_drv.h"
  23. #include "tidss_kms.h"
  24. #include "tidss_irq.h"
  25. #include "tidss_oldi.h"
  26. /* Power management */
  27. int tidss_runtime_get(struct tidss_device *tidss)
  28. {
  29. int r;
  30. r = pm_runtime_resume_and_get(tidss->dev);
  31. WARN_ON(r < 0);
  32. return r;
  33. }
  34. void tidss_runtime_put(struct tidss_device *tidss)
  35. {
  36. int r;
  37. pm_runtime_mark_last_busy(tidss->dev);
  38. r = pm_runtime_put_autosuspend(tidss->dev);
  39. WARN_ON(r < 0);
  40. }
  41. static int __maybe_unused tidss_pm_runtime_suspend(struct device *dev)
  42. {
  43. struct tidss_device *tidss = dev_get_drvdata(dev);
  44. return dispc_runtime_suspend(tidss->dispc);
  45. }
  46. static int __maybe_unused tidss_pm_runtime_resume(struct device *dev)
  47. {
  48. struct tidss_device *tidss = dev_get_drvdata(dev);
  49. int r;
  50. r = dispc_runtime_resume(tidss->dispc);
  51. if (r)
  52. return r;
  53. return 0;
  54. }
  55. static int __maybe_unused tidss_suspend(struct device *dev)
  56. {
  57. struct tidss_device *tidss = dev_get_drvdata(dev);
  58. return drm_mode_config_helper_suspend(&tidss->ddev);
  59. }
  60. static int __maybe_unused tidss_resume(struct device *dev)
  61. {
  62. struct tidss_device *tidss = dev_get_drvdata(dev);
  63. return drm_mode_config_helper_resume(&tidss->ddev);
  64. }
  65. static __maybe_unused const struct dev_pm_ops tidss_pm_ops = {
  66. SET_SYSTEM_SLEEP_PM_OPS(tidss_suspend, tidss_resume)
  67. SET_RUNTIME_PM_OPS(tidss_pm_runtime_suspend, tidss_pm_runtime_resume, NULL)
  68. };
  69. /* DRM device Information */
  70. static void tidss_release(struct drm_device *ddev)
  71. {
  72. drm_kms_helper_poll_fini(ddev);
  73. }
  74. DEFINE_DRM_GEM_DMA_FOPS(tidss_fops);
  75. static const struct drm_driver tidss_driver = {
  76. .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
  77. .fops = &tidss_fops,
  78. .release = tidss_release,
  79. DRM_GEM_DMA_DRIVER_OPS_VMAP,
  80. DRM_FBDEV_DMA_DRIVER_OPS,
  81. .name = "tidss",
  82. .desc = "TI Keystone DSS",
  83. .major = 1,
  84. .minor = 0,
  85. };
  86. static int tidss_probe(struct platform_device *pdev)
  87. {
  88. struct device *dev = &pdev->dev;
  89. struct tidss_device *tidss;
  90. struct drm_device *ddev;
  91. int ret;
  92. int irq;
  93. tidss = devm_drm_dev_alloc(&pdev->dev, &tidss_driver,
  94. struct tidss_device, ddev);
  95. if (IS_ERR(tidss))
  96. return PTR_ERR(tidss);
  97. ddev = &tidss->ddev;
  98. tidss->dev = dev;
  99. tidss->feat = of_device_get_match_data(dev);
  100. platform_set_drvdata(pdev, tidss);
  101. spin_lock_init(&tidss->irq_lock);
  102. ret = dispc_init(tidss);
  103. if (ret) {
  104. dev_err(dev, "failed to initialize dispc: %d\n", ret);
  105. return ret;
  106. }
  107. ret = tidss_oldi_init(tidss);
  108. if (ret)
  109. return dev_err_probe(dev, ret, "failed to init OLDI\n");
  110. pm_runtime_enable(dev);
  111. pm_runtime_set_autosuspend_delay(dev, 1000);
  112. pm_runtime_use_autosuspend(dev);
  113. #ifndef CONFIG_PM
  114. /* If we don't have PM, we need to call resume manually */
  115. dispc_runtime_resume(tidss->dispc);
  116. #endif
  117. ret = tidss_modeset_init(tidss);
  118. if (ret < 0) {
  119. if (ret != -EPROBE_DEFER)
  120. dev_err(dev, "failed to init DRM/KMS (%d)\n", ret);
  121. goto err_runtime_suspend;
  122. }
  123. irq = platform_get_irq(pdev, 0);
  124. if (irq < 0) {
  125. ret = irq;
  126. goto err_runtime_suspend;
  127. }
  128. tidss->irq = irq;
  129. ret = tidss_irq_install(ddev, irq);
  130. if (ret) {
  131. dev_err(dev, "tidss_irq_install failed: %d\n", ret);
  132. goto err_runtime_suspend;
  133. }
  134. drm_kms_helper_poll_init(ddev);
  135. drm_mode_config_reset(ddev);
  136. ret = drm_dev_register(ddev, 0);
  137. if (ret) {
  138. dev_err(dev, "failed to register DRM device\n");
  139. goto err_irq_uninstall;
  140. }
  141. /* Remove possible early fb before setting up the fbdev */
  142. ret = aperture_remove_all_conflicting_devices(tidss_driver.name);
  143. if (ret)
  144. goto err_drm_dev_unreg;
  145. drm_client_setup(ddev, NULL);
  146. dev_dbg(dev, "%s done\n", __func__);
  147. return 0;
  148. err_drm_dev_unreg:
  149. drm_dev_unregister(ddev);
  150. err_irq_uninstall:
  151. tidss_irq_uninstall(ddev);
  152. err_runtime_suspend:
  153. #ifndef CONFIG_PM
  154. dispc_runtime_suspend(tidss->dispc);
  155. #endif
  156. pm_runtime_dont_use_autosuspend(dev);
  157. pm_runtime_disable(dev);
  158. tidss_oldi_deinit(tidss);
  159. return ret;
  160. }
  161. static void tidss_remove(struct platform_device *pdev)
  162. {
  163. struct device *dev = &pdev->dev;
  164. struct tidss_device *tidss = platform_get_drvdata(pdev);
  165. struct drm_device *ddev = &tidss->ddev;
  166. drm_dev_unregister(ddev);
  167. drm_atomic_helper_shutdown(ddev);
  168. tidss_irq_uninstall(ddev);
  169. #ifndef CONFIG_PM
  170. /* If we don't have PM, we need to call suspend manually */
  171. dispc_runtime_suspend(tidss->dispc);
  172. #endif
  173. pm_runtime_dont_use_autosuspend(dev);
  174. pm_runtime_disable(dev);
  175. tidss_oldi_deinit(tidss);
  176. /* devm allocated dispc goes away with the dev so mark it NULL */
  177. dispc_remove(tidss);
  178. dev_dbg(dev, "%s done\n", __func__);
  179. }
  180. static void tidss_shutdown(struct platform_device *pdev)
  181. {
  182. drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
  183. }
  184. static const struct of_device_id tidss_of_table[] = {
  185. { .compatible = "ti,k2g-dss", .data = &dispc_k2g_feats, },
  186. { .compatible = "ti,am625-dss", .data = &dispc_am625_feats, },
  187. { .compatible = "ti,am62a7-dss", .data = &dispc_am62a7_feats, },
  188. { .compatible = "ti,am62l-dss", .data = &dispc_am62l_feats, },
  189. { .compatible = "ti,am65x-dss", .data = &dispc_am65x_feats, },
  190. { .compatible = "ti,j721e-dss", .data = &dispc_j721e_feats, },
  191. { }
  192. };
  193. MODULE_DEVICE_TABLE(of, tidss_of_table);
  194. static struct platform_driver tidss_platform_driver = {
  195. .probe = tidss_probe,
  196. .remove = tidss_remove,
  197. .shutdown = tidss_shutdown,
  198. .driver = {
  199. .name = "tidss",
  200. .pm = pm_ptr(&tidss_pm_ops),
  201. .of_match_table = tidss_of_table,
  202. .suppress_bind_attrs = true,
  203. },
  204. };
  205. drm_module_platform_driver(tidss_platform_driver);
  206. MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
  207. MODULE_DESCRIPTION("TI Keystone DSS Driver");
  208. MODULE_LICENSE("GPL v2");