vs_drv.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
  4. */
  5. #include <linux/of_graph.h>
  6. #include <linux/component.h>
  7. #include <linux/iommu.h>
  8. #include <linux/version.h>
  9. #include <drm/drm_of.h>
  10. #include <drm/drm_crtc.h>
  11. #include <drm/drm_crtc_helper.h>
  12. #include <drm/drm_probe_helper.h>
  13. #include <drm/drm_fb_helper.h>
  14. #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
  15. #include <drm/drm_drv.h>
  16. #include <drm/drm_file.h>
  17. #include <drm/drm_prime.h>
  18. #include <drm/drm_vblank.h>
  19. #include <drm/drm_ioctl.h>
  20. #include <drm/drm_fourcc.h>
  21. #include <drm/drm_debugfs.h>
  22. #endif
  23. #include "vs_drv.h"
  24. #include "vs_fb.h"
  25. #include "vs_gem.h"
  26. #include "vs_plane.h"
  27. #include "vs_crtc.h"
  28. #include "vs_simple_enc.h"
  29. #include "vs_dc.h"
  30. #include "vs_virtual.h"
  31. #include "dw_mipi_dsi.h"
  32. #include "dw_hdmi_light.h"
  33. #define DRV_NAME "vs-drm"
  34. #define DRV_DESC "VeriSilicon DRM driver"
  35. #define DRV_DATE "20191101"
  36. #define DRV_MAJOR 1
  37. #define DRV_MINOR 0
  38. static bool has_iommu = true;
  39. static struct platform_driver vs_drm_platform_driver;
  40. static const struct file_operations fops = {
  41. .owner = THIS_MODULE,
  42. .open = drm_open,
  43. .release = drm_release,
  44. .unlocked_ioctl = drm_ioctl,
  45. .compat_ioctl = drm_compat_ioctl,
  46. .poll = drm_poll,
  47. .read = drm_read,
  48. .mmap = vs_gem_mmap,
  49. };
  50. #ifdef CONFIG_DEBUG_FS
  51. static int vs_debugfs_planes_show(struct seq_file *s, void *data)
  52. {
  53. struct drm_info_node *node = (struct drm_info_node *)s->private;
  54. struct drm_device *dev = node->minor->dev;
  55. struct drm_plane *plane;
  56. list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
  57. struct drm_plane_state *state = plane->state;
  58. struct vs_plane_state *plane_state = to_vs_plane_state(state);
  59. seq_printf(s, "plane[%u]: %s\n", plane->base.id, plane->name);
  60. seq_printf(s, "\tcrtc = %s\n", state->crtc ?
  61. state->crtc->name : "(null)");
  62. seq_printf(s, "\tcrtc id = %u\n", state->crtc ?
  63. state->crtc->base.id : 0);
  64. seq_printf(s, "\tcrtc-pos = " DRM_RECT_FMT "\n",
  65. DRM_RECT_ARG(&plane_state->status.dest));
  66. seq_printf(s, "\tsrc-pos = " DRM_RECT_FP_FMT "\n",
  67. DRM_RECT_FP_ARG(&plane_state->status.src));
  68. seq_printf(s, "\tformat = %s\n", state->fb ?
  69. plane_state->status.format_name.str : "(null)");
  70. seq_printf(s, "\trotation = 0x%x\n", state->rotation);
  71. seq_printf(s, "\ttiling = %u\n",
  72. plane_state->status.tile_mode);
  73. seq_puts(s, "\n");
  74. }
  75. return 0;
  76. }
  77. static struct drm_info_list vs_debugfs_list[] = {
  78. { "planes", vs_debugfs_planes_show, 0, NULL },
  79. };
  80. #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
  81. static void vs_debugfs_init(struct drm_minor *minor)
  82. {
  83. drm_debugfs_create_files(vs_debugfs_list,
  84. ARRAY_SIZE(vs_debugfs_list),
  85. minor->debugfs_root, minor);
  86. }
  87. #else
  88. static int vs_debugfs_init(struct drm_minor *minor)
  89. {
  90. struct drm_device *dev = minor->dev;
  91. int ret;
  92. ret = drm_debugfs_create_files(vs_debugfs_list,
  93. ARRAY_SIZE(vs_debugfs_list),
  94. minor->debugfs_root, minor);
  95. if (ret)
  96. dev_err(dev->dev, "could not install vs_debugfs_list.\n");
  97. return ret;
  98. }
  99. #endif
  100. #endif
  101. static struct drm_driver vs_drm_driver = {
  102. .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
  103. .lastclose = drm_fb_helper_lastclose,
  104. .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
  105. .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
  106. .gem_prime_import = vs_gem_prime_import,
  107. .gem_prime_import_sg_table = vs_gem_prime_import_sg_table,
  108. .gem_prime_mmap = vs_gem_prime_mmap,
  109. .dumb_create = vs_gem_dumb_create,
  110. #ifdef CONFIG_DEBUG_FS
  111. .debugfs_init = vs_debugfs_init,
  112. #endif
  113. .fops = &fops,
  114. .name = DRV_NAME,
  115. .desc = DRV_DESC,
  116. .date = DRV_DATE,
  117. .major = DRV_MAJOR,
  118. .minor = DRV_MINOR,
  119. };
  120. int vs_drm_iommu_attach_device(struct drm_device *drm_dev,
  121. struct device *dev)
  122. {
  123. struct vs_drm_private *priv = drm_dev->dev_private;
  124. int ret;
  125. if (!has_iommu)
  126. return 0;
  127. if (!priv->domain) {
  128. priv->domain = iommu_get_domain_for_dev(dev);
  129. if (IS_ERR(priv->domain))
  130. return PTR_ERR(priv->domain);
  131. priv->dma_dev = dev;
  132. }
  133. ret = iommu_attach_device(priv->domain, dev);
  134. if (ret) {
  135. DRM_DEV_ERROR(dev, "Failed to attach iommu device\n");
  136. return ret;
  137. }
  138. return 0;
  139. }
  140. void vs_drm_iommu_detach_device(struct drm_device *drm_dev,
  141. struct device *dev)
  142. {
  143. struct vs_drm_private *priv = drm_dev->dev_private;
  144. if (!has_iommu)
  145. return;
  146. iommu_detach_device(priv->domain, dev);
  147. if (priv->dma_dev == dev)
  148. priv->dma_dev = drm_dev->dev;
  149. }
  150. void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
  151. unsigned int alignment)
  152. {
  153. struct vs_drm_private *priv = drm_dev->dev_private;
  154. if (alignment > priv->pitch_alignment)
  155. priv->pitch_alignment = alignment;
  156. }
  157. static int vs_drm_bind(struct device *dev)
  158. {
  159. struct drm_device *drm_dev;
  160. struct vs_drm_private *priv;
  161. int ret;
  162. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
  163. #ifdef CONFIG_VERISILICON_MMU
  164. static u64 dma_mask = DMA_BIT_MASK(40);
  165. #else
  166. static u64 dma_mask = DMA_BIT_MASK(32);
  167. #endif
  168. #else
  169. static u64 dma_mask = DMA_40BIT_MASK;
  170. #endif
  171. drm_dev = drm_dev_alloc(&vs_drm_driver, dev);
  172. if (IS_ERR(drm_dev))
  173. return PTR_ERR(drm_dev);
  174. dev_set_drvdata(dev, drm_dev);
  175. priv = devm_kzalloc(drm_dev->dev, sizeof(struct vs_drm_private),
  176. GFP_KERNEL);
  177. if (!priv) {
  178. ret = -ENOMEM;
  179. goto err_put_dev;
  180. }
  181. priv->pitch_alignment = 64;
  182. priv->dma_dev = drm_dev->dev;
  183. priv->dma_dev->coherent_dma_mask = dma_mask;
  184. drm_dev->dev_private = priv;
  185. drm_mode_config_init(drm_dev);
  186. /* Now try and bind all our sub-components */
  187. ret = component_bind_all(dev, drm_dev);
  188. if (ret)
  189. goto err_mode;
  190. vs_mode_config_init(drm_dev);
  191. ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
  192. if (ret)
  193. goto err_bind;
  194. drm_mode_config_reset(drm_dev);
  195. drm_dev->irq_enabled = true;
  196. drm_kms_helper_poll_init(drm_dev);
  197. ret = drm_dev_register(drm_dev, 0);
  198. if (ret)
  199. goto err_helper;
  200. drm_fbdev_generic_setup(drm_dev, 32);
  201. return 0;
  202. err_helper:
  203. drm_kms_helper_poll_fini(drm_dev);
  204. err_bind:
  205. component_unbind_all(drm_dev->dev, drm_dev);
  206. err_mode:
  207. drm_mode_config_cleanup(drm_dev);
  208. if (priv->domain)
  209. iommu_domain_free(priv->domain);
  210. err_put_dev:
  211. drm_dev->dev_private = NULL;
  212. dev_set_drvdata(dev, NULL);
  213. drm_dev_put(drm_dev);
  214. return ret;
  215. }
  216. static void vs_drm_unbind(struct device *dev)
  217. {
  218. struct drm_device *drm_dev = dev_get_drvdata(dev);
  219. struct vs_drm_private *priv = drm_dev->dev_private;
  220. drm_dev_unregister(drm_dev);
  221. drm_kms_helper_poll_fini(drm_dev);
  222. component_unbind_all(drm_dev->dev, drm_dev);
  223. drm_mode_config_cleanup(drm_dev);
  224. if (priv->domain) {
  225. iommu_domain_free(priv->domain);
  226. priv->domain = NULL;
  227. }
  228. drm_dev->dev_private = NULL;
  229. dev_set_drvdata(dev, NULL);
  230. drm_dev_put(drm_dev);
  231. }
  232. static const struct component_master_ops vs_drm_ops = {
  233. .bind = vs_drm_bind,
  234. .unbind = vs_drm_unbind,
  235. };
  236. static struct platform_driver *drm_sub_drivers[] = {
  237. /* put display control driver at start */
  238. &dc_platform_driver,
  239. /* connector */
  240. /* bridge */
  241. #ifdef CONFIG_VERISILICON_DW_MIPI_DSI
  242. &dw_mipi_dsi_driver,
  243. #endif
  244. #ifdef CONFIG_VERISILICON_DW_HDMI_LIGHT
  245. &dw_hdmi_light_platform_driver,
  246. #endif
  247. /* encoder */
  248. &simple_encoder_driver,
  249. #ifdef CONFIG_VERISILICON_VIRTUAL_DISPLAY
  250. &virtual_display_platform_driver,
  251. #endif
  252. };
  253. #define NUM_DRM_DRIVERS \
  254. (sizeof(drm_sub_drivers) / sizeof(struct platform_driver *))
  255. static int compare_dev(struct device *dev, void *data)
  256. {
  257. return dev == (struct device *)data;
  258. }
  259. static struct component_match *vs_drm_match_add(struct device *dev)
  260. {
  261. struct component_match *match = NULL;
  262. int i;
  263. for (i = 0; i < NUM_DRM_DRIVERS; ++i) {
  264. struct platform_driver *drv = drm_sub_drivers[i];
  265. struct device *p = NULL, *d;
  266. while ((d = platform_find_device_by_driver(p, &drv->driver))) {
  267. put_device(p);
  268. component_match_add(dev, &match, compare_dev, d);
  269. p = d;
  270. }
  271. put_device(p);
  272. }
  273. return match ?: ERR_PTR(-ENODEV);
  274. }
  275. static int vs_drm_platform_of_probe(struct device *dev)
  276. {
  277. struct device_node *np = dev->of_node;
  278. struct device_node *port;
  279. bool found = false;
  280. int i;
  281. if (!np)
  282. return -ENODEV;
  283. for (i = 0;; i++) {
  284. struct device_node *iommu;
  285. port = of_parse_phandle(np, "ports", i);
  286. if (!port)
  287. break;
  288. if (!of_device_is_available(port->parent)) {
  289. of_node_put(port);
  290. continue;
  291. }
  292. iommu = of_parse_phandle(port->parent, "iommus", 0);
  293. /*
  294. * if there is a crtc not support iommu, force set all
  295. * crtc use non-iommu buffer.
  296. */
  297. if (!iommu || !of_device_is_available(iommu->parent))
  298. has_iommu = false;
  299. found = true;
  300. of_node_put(iommu);
  301. of_node_put(port);
  302. }
  303. if (i == 0) {
  304. DRM_DEV_ERROR(dev, "missing 'ports' property\n");
  305. return -ENODEV;
  306. }
  307. if (!found) {
  308. DRM_DEV_ERROR(dev, "No available DC found.\n");
  309. return -ENODEV;
  310. }
  311. return 0;
  312. }
  313. static int vs_drm_platform_probe(struct platform_device *pdev)
  314. {
  315. struct device *dev = &pdev->dev;
  316. struct component_match *match;
  317. int ret;
  318. ret = vs_drm_platform_of_probe(dev);
  319. if (ret)
  320. return ret;
  321. match = vs_drm_match_add(dev);
  322. if (IS_ERR(match))
  323. return PTR_ERR(match);
  324. return component_master_add_with_match(dev, &vs_drm_ops, match);
  325. }
  326. static int vs_drm_platform_remove(struct platform_device *pdev)
  327. {
  328. component_master_del(&pdev->dev, &vs_drm_ops);
  329. return 0;
  330. }
  331. #ifdef CONFIG_PM_SLEEP
  332. static int vs_drm_suspend(struct device *dev)
  333. {
  334. struct drm_device *drm = dev_get_drvdata(dev);
  335. return drm_mode_config_helper_suspend(drm);
  336. }
  337. static int vs_drm_resume(struct device *dev)
  338. {
  339. struct drm_device *drm = dev_get_drvdata(dev);
  340. return drm_mode_config_helper_resume(drm);
  341. }
  342. #endif
  343. static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend, vs_drm_resume);
  344. static const struct of_device_id vs_drm_dt_ids[] = {
  345. { .compatible = "verisilicon,display-subsystem", },
  346. { /* sentinel */ },
  347. };
  348. MODULE_DEVICE_TABLE(of, vs_drm_dt_ids);
  349. static struct platform_driver vs_drm_platform_driver = {
  350. .probe = vs_drm_platform_probe,
  351. .remove = vs_drm_platform_remove,
  352. .driver = {
  353. .name = DRV_NAME,
  354. .of_match_table = vs_drm_dt_ids,
  355. .pm = &vs_drm_pm_ops,
  356. },
  357. };
  358. static int __init vs_drm_init(void)
  359. {
  360. int ret;
  361. ret = platform_register_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
  362. if (ret)
  363. return ret;
  364. ret = platform_driver_register(&vs_drm_platform_driver);
  365. if (ret)
  366. platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
  367. return ret;
  368. }
  369. static void __exit vs_drm_fini(void)
  370. {
  371. platform_driver_unregister(&vs_drm_platform_driver);
  372. platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
  373. }
  374. module_init(vs_drm_init);
  375. module_exit(vs_drm_fini);
  376. MODULE_DESCRIPTION("VeriSilicon DRM Driver");
  377. MODULE_LICENSE("GPL v2");