armada_output.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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_connector_unregister(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. /* Shouldn't this be a generic helper function? */
  61. int armada_drm_slave_encoder_mode_valid(struct drm_connector *conn,
  62. struct drm_display_mode *mode)
  63. {
  64. struct drm_encoder *encoder = armada_drm_connector_encoder(conn);
  65. int valid = MODE_BAD;
  66. if (encoder) {
  67. struct drm_encoder_slave *slave = to_encoder_slave(encoder);
  68. valid = slave->slave_funcs->mode_valid(encoder, mode);
  69. }
  70. return valid;
  71. }
  72. int armada_drm_slave_encoder_set_property(struct drm_connector *conn,
  73. struct drm_property *property, uint64_t value)
  74. {
  75. struct drm_encoder *encoder = armada_drm_connector_encoder(conn);
  76. int rc = -EINVAL;
  77. if (encoder) {
  78. struct drm_encoder_slave *slave = to_encoder_slave(encoder);
  79. rc = slave->slave_funcs->set_property(encoder, conn, property,
  80. value);
  81. }
  82. return rc;
  83. }
  84. int armada_output_create(struct drm_device *dev,
  85. const struct armada_output_type *type, const void *data)
  86. {
  87. struct armada_connector *dconn;
  88. int ret;
  89. dconn = kzalloc(sizeof(*dconn), GFP_KERNEL);
  90. if (!dconn)
  91. return -ENOMEM;
  92. dconn->type = type;
  93. ret = drm_connector_init(dev, &dconn->conn, &armada_drm_conn_funcs,
  94. type->connector_type);
  95. if (ret) {
  96. DRM_ERROR("unable to init connector\n");
  97. goto err_destroy_dconn;
  98. }
  99. ret = type->create(&dconn->conn, data);
  100. if (ret)
  101. goto err_conn;
  102. ret = drm_connector_register(&dconn->conn);
  103. if (ret)
  104. goto err_sysfs;
  105. return 0;
  106. err_sysfs:
  107. if (dconn->conn.encoder)
  108. dconn->conn.encoder->funcs->destroy(dconn->conn.encoder);
  109. err_conn:
  110. drm_connector_cleanup(&dconn->conn);
  111. err_destroy_dconn:
  112. kfree(dconn);
  113. return ret;
  114. }