1/* 2 * Copyright (C) 2012 Russell King 3 * Rewritten from the dovefb driver, and Armada510 manuals. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9#include <drm/drmP.h> 10#include <drm/drm_crtc_helper.h> 11#include <drm/drm_edid.h> 12#include <drm/drm_encoder_slave.h> 13#include "armada_drm.h" 14#include "armada_output.h" 15#include "armada_slave.h" 16 17static int armada_drm_slave_get_modes(struct drm_connector *conn) 18{ 19 struct drm_encoder *enc = armada_drm_connector_encoder(conn); 20 int count = 0; 21 22 if (enc) { 23 struct drm_encoder_slave *slave = to_encoder_slave(enc); 24 25 count = slave->slave_funcs->get_modes(enc, conn); 26 } 27 28 return count; 29} 30 31static void armada_drm_slave_destroy(struct drm_encoder *enc) 32{ 33 struct drm_encoder_slave *slave = to_encoder_slave(enc); 34 struct i2c_client *client = drm_i2c_encoder_get_client(enc); 35 36 if (slave->slave_funcs) 37 slave->slave_funcs->destroy(enc); 38 if (client) 39 i2c_put_adapter(client->adapter); 40 41 drm_encoder_cleanup(&slave->base); 42 kfree(slave); 43} 44 45static const struct drm_encoder_funcs armada_drm_slave_encoder_funcs = { 46 .destroy = armada_drm_slave_destroy, 47}; 48 49static const struct drm_connector_helper_funcs armada_drm_slave_helper_funcs = { 50 .get_modes = armada_drm_slave_get_modes, 51 .mode_valid = armada_drm_slave_encoder_mode_valid, 52 .best_encoder = armada_drm_connector_encoder, 53}; 54 55static const struct drm_encoder_helper_funcs drm_slave_encoder_helpers = { 56 .dpms = drm_i2c_encoder_dpms, 57 .save = drm_i2c_encoder_save, 58 .restore = drm_i2c_encoder_restore, 59 .mode_fixup = drm_i2c_encoder_mode_fixup, 60 .prepare = drm_i2c_encoder_prepare, 61 .commit = drm_i2c_encoder_commit, 62 .mode_set = drm_i2c_encoder_mode_set, 63 .detect = drm_i2c_encoder_detect, 64}; 65 66static int 67armada_drm_conn_slave_create(struct drm_connector *conn, const void *data) 68{ 69 const struct armada_drm_slave_config *config = data; 70 struct drm_encoder_slave *slave; 71 struct i2c_adapter *adap; 72 int ret; 73 74 conn->interlace_allowed = config->interlace_allowed; 75 conn->doublescan_allowed = config->doublescan_allowed; 76 conn->polled = config->polled; 77 78 drm_connector_helper_add(conn, &armada_drm_slave_helper_funcs); 79 80 slave = kzalloc(sizeof(*slave), GFP_KERNEL); 81 if (!slave) 82 return -ENOMEM; 83 84 slave->base.possible_crtcs = config->crtcs; 85 86 adap = i2c_get_adapter(config->i2c_adapter_id); 87 if (!adap) { 88 kfree(slave); 89 return -EPROBE_DEFER; 90 } 91 92 ret = drm_encoder_init(conn->dev, &slave->base, 93 &armada_drm_slave_encoder_funcs, 94 DRM_MODE_ENCODER_TMDS); 95 if (ret) { 96 DRM_ERROR("unable to init encoder\n"); 97 i2c_put_adapter(adap); 98 kfree(slave); 99 return ret; 100 } 101 102 ret = drm_i2c_encoder_init(conn->dev, slave, adap, &config->info); 103 i2c_put_adapter(adap); 104 if (ret) { 105 DRM_ERROR("unable to init encoder slave\n"); 106 armada_drm_slave_destroy(&slave->base); 107 return ret; 108 } 109 110 drm_encoder_helper_add(&slave->base, &drm_slave_encoder_helpers); 111 112 ret = slave->slave_funcs->create_resources(&slave->base, conn); 113 if (ret) { 114 armada_drm_slave_destroy(&slave->base); 115 return ret; 116 } 117 118 ret = drm_mode_connector_attach_encoder(conn, &slave->base); 119 if (ret) { 120 armada_drm_slave_destroy(&slave->base); 121 return ret; 122 } 123 124 conn->encoder = &slave->base; 125 126 return ret; 127} 128 129static const struct armada_output_type armada_drm_conn_slave = { 130 .connector_type = DRM_MODE_CONNECTOR_HDMIA, 131 .create = armada_drm_conn_slave_create, 132 .set_property = armada_drm_slave_encoder_set_property, 133}; 134 135int armada_drm_connector_slave_create(struct drm_device *dev, 136 const struct armada_drm_slave_config *config) 137{ 138 return armada_output_create(dev, &armada_drm_conn_slave, config); 139} 140