vkms_output.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include "vkms_config.h"
  3. #include "vkms_connector.h"
  4. #include "vkms_drv.h"
  5. #include <drm/drm_managed.h>
  6. #include <drm/drm_print.h>
  7. int vkms_output_init(struct vkms_device *vkmsdev)
  8. {
  9. struct drm_device *dev = &vkmsdev->drm;
  10. struct vkms_config_plane *plane_cfg;
  11. struct vkms_config_crtc *crtc_cfg;
  12. struct vkms_config_encoder *encoder_cfg;
  13. struct vkms_config_connector *connector_cfg;
  14. int ret;
  15. int writeback;
  16. if (!vkms_config_is_valid(vkmsdev->config))
  17. return -EINVAL;
  18. vkms_config_for_each_plane(vkmsdev->config, plane_cfg) {
  19. plane_cfg->plane = vkms_plane_init(vkmsdev, plane_cfg);
  20. if (IS_ERR(plane_cfg->plane)) {
  21. DRM_DEV_ERROR(dev->dev, "Failed to init vkms plane\n");
  22. return PTR_ERR(plane_cfg->plane);
  23. }
  24. }
  25. vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
  26. struct vkms_config_plane *primary, *cursor;
  27. primary = vkms_config_crtc_primary_plane(vkmsdev->config, crtc_cfg);
  28. cursor = vkms_config_crtc_cursor_plane(vkmsdev->config, crtc_cfg);
  29. crtc_cfg->crtc = vkms_crtc_init(dev, &primary->plane->base,
  30. cursor ? &cursor->plane->base : NULL);
  31. if (IS_ERR(crtc_cfg->crtc)) {
  32. DRM_ERROR("Failed to allocate CRTC\n");
  33. return PTR_ERR(crtc_cfg->crtc);
  34. }
  35. /* Initialize the writeback component */
  36. if (vkms_config_crtc_get_writeback(crtc_cfg)) {
  37. writeback = vkms_enable_writeback_connector(vkmsdev, crtc_cfg->crtc);
  38. if (writeback)
  39. DRM_ERROR("Failed to init writeback connector\n");
  40. }
  41. }
  42. vkms_config_for_each_plane(vkmsdev->config, plane_cfg) {
  43. struct vkms_config_crtc *possible_crtc;
  44. unsigned long idx = 0;
  45. vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) {
  46. plane_cfg->plane->base.possible_crtcs |=
  47. drm_crtc_mask(&possible_crtc->crtc->crtc);
  48. }
  49. }
  50. vkms_config_for_each_encoder(vkmsdev->config, encoder_cfg) {
  51. struct vkms_config_crtc *possible_crtc;
  52. unsigned long idx = 0;
  53. encoder_cfg->encoder = drmm_kzalloc(dev, sizeof(*encoder_cfg->encoder), GFP_KERNEL);
  54. if (!encoder_cfg->encoder) {
  55. DRM_ERROR("Failed to allocate encoder\n");
  56. return -ENOMEM;
  57. }
  58. ret = drmm_encoder_init(dev, encoder_cfg->encoder, NULL,
  59. DRM_MODE_ENCODER_VIRTUAL, NULL);
  60. if (ret) {
  61. DRM_ERROR("Failed to init encoder\n");
  62. return ret;
  63. }
  64. encoder_cfg->encoder->possible_clones |=
  65. drm_encoder_mask(encoder_cfg->encoder);
  66. vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) {
  67. encoder_cfg->encoder->possible_crtcs |=
  68. drm_crtc_mask(&possible_crtc->crtc->crtc);
  69. if (vkms_config_crtc_get_writeback(possible_crtc)) {
  70. struct drm_encoder *wb_encoder =
  71. &possible_crtc->crtc->wb_encoder;
  72. encoder_cfg->encoder->possible_clones |=
  73. drm_encoder_mask(wb_encoder);
  74. wb_encoder->possible_clones |=
  75. drm_encoder_mask(encoder_cfg->encoder);
  76. }
  77. }
  78. }
  79. vkms_config_for_each_connector(vkmsdev->config, connector_cfg) {
  80. struct vkms_config_encoder *possible_encoder;
  81. unsigned long idx = 0;
  82. connector_cfg->connector = vkms_connector_init(vkmsdev);
  83. if (IS_ERR(connector_cfg->connector)) {
  84. DRM_ERROR("Failed to init connector\n");
  85. return PTR_ERR(connector_cfg->connector);
  86. }
  87. vkms_config_connector_for_each_possible_encoder(connector_cfg,
  88. idx,
  89. possible_encoder) {
  90. ret = drm_connector_attach_encoder(&connector_cfg->connector->base,
  91. possible_encoder->encoder);
  92. if (ret) {
  93. DRM_ERROR("Failed to attach connector to encoder\n");
  94. return ret;
  95. }
  96. }
  97. }
  98. drm_mode_config_reset(dev);
  99. return 0;
  100. }