• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
armada_drm_slave_get_modes(struct drm_connector * conn)17 static 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 
armada_drm_slave_destroy(struct drm_encoder * enc)31 static 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 
45 static const struct drm_encoder_funcs armada_drm_slave_encoder_funcs = {
46 	.destroy	= armada_drm_slave_destroy,
47 };
48 
49 static 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 
55 static 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 
66 static int
armada_drm_conn_slave_create(struct drm_connector * conn,const void * data)67 armada_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 
129 static 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 
armada_drm_connector_slave_create(struct drm_device * dev,const struct armada_drm_slave_config * config)135 int 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