Commit | Line | Data |
---|---|---|
96f60e37 RK |
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 | ||
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 | ||
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 | |
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 | ||
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 | } |