123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- /*
- * Copyright (C) 2012 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <drm/drmP.h>
- #include <drm/drm_crtc_helper.h>
- #include <drm/drm_edid.h>
- #include <drm/drm_encoder_slave.h>
- #include "armada_output.h"
- #include "armada_drm.h"
- struct armada_connector {
- struct drm_connector conn;
- const struct armada_output_type *type;
- };
- #define drm_to_armada_conn(c) container_of(c, struct armada_connector, conn)
- struct drm_encoder *armada_drm_connector_encoder(struct drm_connector *conn)
- {
- struct drm_encoder *enc = conn->encoder;
- return enc ? enc : drm_encoder_find(conn->dev, conn->encoder_ids[0]);
- }
- static enum drm_connector_status armada_drm_connector_detect(
- struct drm_connector *conn, bool force)
- {
- struct armada_connector *dconn = drm_to_armada_conn(conn);
- enum drm_connector_status status = connector_status_disconnected;
- if (dconn->type->detect) {
- status = dconn->type->detect(conn, force);
- } else {
- struct drm_encoder *enc = armada_drm_connector_encoder(conn);
- if (enc)
- status = encoder_helper_funcs(enc)->detect(enc, conn);
- }
- return status;
- }
- static void armada_drm_connector_destroy(struct drm_connector *conn)
- {
- struct armada_connector *dconn = drm_to_armada_conn(conn);
- drm_connector_unregister(conn);
- drm_connector_cleanup(conn);
- kfree(dconn);
- }
- static int armada_drm_connector_set_property(struct drm_connector *conn,
- struct drm_property *property, uint64_t value)
- {
- struct armada_connector *dconn = drm_to_armada_conn(conn);
- if (!dconn->type->set_property)
- return -EINVAL;
- return dconn->type->set_property(conn, property, value);
- }
- static const struct drm_connector_funcs armada_drm_conn_funcs = {
- .dpms = drm_helper_connector_dpms,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .detect = armada_drm_connector_detect,
- .destroy = armada_drm_connector_destroy,
- .set_property = armada_drm_connector_set_property,
- };
- /* Shouldn't this be a generic helper function? */
- int armada_drm_slave_encoder_mode_valid(struct drm_connector *conn,
- struct drm_display_mode *mode)
- {
- struct drm_encoder *encoder = armada_drm_connector_encoder(conn);
- int valid = MODE_BAD;
- if (encoder) {
- struct drm_encoder_slave *slave = to_encoder_slave(encoder);
- valid = slave->slave_funcs->mode_valid(encoder, mode);
- }
- return valid;
- }
- int armada_drm_slave_encoder_set_property(struct drm_connector *conn,
- struct drm_property *property, uint64_t value)
- {
- struct drm_encoder *encoder = armada_drm_connector_encoder(conn);
- int rc = -EINVAL;
- if (encoder) {
- struct drm_encoder_slave *slave = to_encoder_slave(encoder);
- rc = slave->slave_funcs->set_property(encoder, conn, property,
- value);
- }
- return rc;
- }
- int armada_output_create(struct drm_device *dev,
- const struct armada_output_type *type, const void *data)
- {
- struct armada_connector *dconn;
- int ret;
- dconn = kzalloc(sizeof(*dconn), GFP_KERNEL);
- if (!dconn)
- return -ENOMEM;
- dconn->type = type;
- ret = drm_connector_init(dev, &dconn->conn, &armada_drm_conn_funcs,
- type->connector_type);
- if (ret) {
- DRM_ERROR("unable to init connector\n");
- goto err_destroy_dconn;
- }
- ret = type->create(&dconn->conn, data);
- if (ret)
- goto err_conn;
- ret = drm_connector_register(&dconn->conn);
- if (ret)
- goto err_sysfs;
- return 0;
- err_sysfs:
- if (dconn->conn.encoder)
- dconn->conn.encoder->funcs->destroy(dconn->conn.encoder);
- err_conn:
- drm_connector_cleanup(&dconn->conn);
- err_destroy_dconn:
- kfree(dconn);
- return ret;
- }
|