armada_output.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Copyright (C) 2012 Russell King
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. */
  8. #include <drm/drmP.h>
  9. #include <drm/drm_crtc_helper.h>
  10. #include <drm/drm_edid.h>
  11. #include <drm/drm_encoder_slave.h>
  12. #include "armada_output.h"
  13. #include "armada_drm.h"
  14. struct armada_connector {
  15. struct drm_connector conn;
  16. const struct armada_output_type *type;
  17. };
  18. #define drm_to_armada_conn(c) container_of(c, struct armada_connector, conn)
  19. struct drm_encoder *armada_drm_connector_encoder(struct drm_connector *conn)
  20. {
  21. struct drm_encoder *enc = conn->encoder;
  22. return enc ? enc : drm_encoder_find(conn->dev, conn->encoder_ids[0]);
  23. }
  24. static enum drm_connector_status armada_drm_connector_detect(
  25. struct drm_connector *conn, bool force)
  26. {
  27. struct armada_connector *dconn = drm_to_armada_conn(conn);
  28. enum drm_connector_status status = connector_status_disconnected;
  29. if (dconn->type->detect) {
  30. status = dconn->type->detect(conn, force);
  31. } else {
  32. struct drm_encoder *enc = armada_drm_connector_encoder(conn);
  33. if (enc)
  34. status = encoder_helper_funcs(enc)->detect(enc, conn);
  35. }
  36. return status;
  37. }
  38. static void armada_drm_connector_destroy(struct drm_connector *conn)
  39. {
  40. struct armada_connector *dconn = drm_to_armada_conn(conn);
  41. drm_sysfs_connector_remove(conn);
  42. drm_connector_cleanup(conn);
  43. kfree(dconn);
  44. }
  45. static int armada_drm_connector_set_property(struct drm_connector *conn,
  46. struct drm_property *property, uint64_t value)
  47. {
  48. struct armada_connector *dconn = drm_to_armada_conn(conn);
  49. if (!dconn->type->set_property)
  50. return -EINVAL;
  51. return dconn->type->set_property(conn, property, value);
  52. }
  53. static const struct drm_connector_funcs armada_drm_conn_funcs = {
  54. .dpms = drm_helper_connector_dpms,
  55. .fill_modes = drm_helper_probe_single_connector_modes,
  56. .detect = armada_drm_connector_detect,
  57. .destroy = armada_drm_connector_destroy,
  58. .set_property = armada_drm_connector_set_property,
  59. };
  60. void armada_drm_encoder_prepare(struct drm_encoder *encoder)
  61. {
  62. encoder_helper_funcs(encoder)->dpms(encoder, DRM_MODE_DPMS_OFF);
  63. }
  64. void armada_drm_encoder_commit(struct drm_encoder *encoder)
  65. {
  66. encoder_helper_funcs(encoder)->dpms(encoder, DRM_MODE_DPMS_ON);
  67. }
  68. bool armada_drm_encoder_mode_fixup(struct drm_encoder *encoder,
  69. const struct drm_display_mode *mode, struct drm_display_mode *adjusted)
  70. {
  71. return true;
  72. }
  73. /* Shouldn't this be a generic helper function? */
  74. int armada_drm_slave_encoder_mode_valid(struct drm_connector *conn,
  75. struct drm_display_mode *mode)
  76. {
  77. struct drm_encoder *encoder = armada_drm_connector_encoder(conn);
  78. int valid = MODE_BAD;
  79. if (encoder) {
  80. struct drm_encoder_slave *slave = to_encoder_slave(encoder);
  81. valid = slave->slave_funcs->mode_valid(encoder, mode);
  82. }
  83. return valid;
  84. }
  85. int armada_drm_slave_encoder_set_property(struct drm_connector *conn,
  86. struct drm_property *property, uint64_t value)
  87. {
  88. struct drm_encoder *encoder = armada_drm_connector_encoder(conn);
  89. int rc = -EINVAL;
  90. if (encoder) {
  91. struct drm_encoder_slave *slave = to_encoder_slave(encoder);
  92. rc = slave->slave_funcs->set_property(encoder, conn, property,
  93. value);
  94. }
  95. return rc;
  96. }
  97. int armada_output_create(struct drm_device *dev,
  98. const struct armada_output_type *type, const void *data)
  99. {
  100. struct armada_connector *dconn;
  101. int ret;
  102. dconn = kzalloc(sizeof(*dconn), GFP_KERNEL);
  103. if (!dconn)
  104. return -ENOMEM;
  105. dconn->type = type;
  106. ret = drm_connector_init(dev, &dconn->conn, &armada_drm_conn_funcs,
  107. type->connector_type);
  108. if (ret) {
  109. DRM_ERROR("unable to init connector\n");
  110. goto err_destroy_dconn;
  111. }
  112. ret = type->create(&dconn->conn, data);
  113. if (ret)
  114. goto err_conn;
  115. ret = drm_sysfs_connector_add(&dconn->conn);
  116. if (ret)
  117. goto err_sysfs;
  118. return 0;
  119. err_sysfs:
  120. if (dconn->conn.encoder)
  121. dconn->conn.encoder->funcs->destroy(dconn->conn.encoder);
  122. err_conn:
  123. drm_connector_cleanup(&dconn->conn);
  124. err_destroy_dconn:
  125. kfree(dconn);
  126. return ret;
  127. }