1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <drm/drmP.h>
19#include <drm/drm_crtc.h>
20#include <drm/drm_crtc_helper.h>
21#include <drm/drm_encoder_slave.h>
22
23#include <linux/device.h>
24
25#include "xilinx_drm_drv.h"
26#include "xilinx_drm_connector.h"
27
28struct xilinx_drm_connector {
29 struct drm_connector base;
30 struct drm_encoder *encoder;
31};
32
33struct xilinx_drm_connector_type {
34 const char *name;
35 const int type;
36};
37
38#define to_xilinx_connector(x) \
39 container_of(x, struct xilinx_drm_connector, base)
40
41
42static int xilinx_drm_connector_get_modes(struct drm_connector *base_connector)
43{
44 struct xilinx_drm_connector *connector =
45 to_xilinx_connector(base_connector);
46 struct drm_encoder *encoder = connector->encoder;
47 struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
48 const struct drm_encoder_slave_funcs *encoder_sfuncs =
49 encoder_slave->slave_funcs;
50 int count = 0;
51
52 if (encoder_sfuncs->get_modes)
53 count = encoder_sfuncs->get_modes(encoder, base_connector);
54
55 return count;
56}
57
58
59static int xilinx_drm_connector_mode_valid(struct drm_connector *base_connector,
60 struct drm_display_mode *mode)
61{
62 struct xilinx_drm_connector *connector =
63 to_xilinx_connector(base_connector);
64 struct drm_encoder *encoder = connector->encoder;
65 struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
66 const struct drm_encoder_slave_funcs *encoder_sfuncs =
67 encoder_slave->slave_funcs;
68 int ret = MODE_OK;
69
70 if (encoder_sfuncs->mode_valid)
71 ret = encoder_sfuncs->mode_valid(encoder, mode);
72
73 return ret;
74}
75
76
77static struct drm_encoder *
78xilinx_drm_connector_best_encoder(struct drm_connector *base_connector)
79{
80 struct xilinx_drm_connector *connector =
81 to_xilinx_connector(base_connector);
82
83 return connector->encoder;
84}
85
86static struct drm_connector_helper_funcs xilinx_drm_connector_helper_funcs = {
87 .get_modes = xilinx_drm_connector_get_modes,
88 .mode_valid = xilinx_drm_connector_mode_valid,
89 .best_encoder = xilinx_drm_connector_best_encoder,
90};
91
92static enum drm_connector_status
93xilinx_drm_connector_detect(struct drm_connector *base_connector, bool force)
94{
95 struct xilinx_drm_connector *connector =
96 to_xilinx_connector(base_connector);
97 enum drm_connector_status status = connector_status_unknown;
98 struct drm_encoder *encoder = connector->encoder;
99 struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
100 const struct drm_encoder_slave_funcs *encoder_sfuncs =
101 encoder_slave->slave_funcs;
102
103 if (encoder_sfuncs->detect)
104 status = encoder_sfuncs->detect(encoder, base_connector);
105
106
107 if (force && (status != connector_status_connected))
108 status = encoder_sfuncs->detect(encoder, base_connector);
109
110 DRM_DEBUG_KMS("status: %d\n", status);
111
112 return status;
113}
114
115
116void xilinx_drm_connector_destroy(struct drm_connector *base_connector)
117{
118 drm_connector_unregister(base_connector);
119 drm_connector_cleanup(base_connector);
120}
121
122static struct drm_connector_funcs xilinx_drm_connector_funcs = {
123 .dpms = drm_helper_connector_dpms,
124 .fill_modes = drm_helper_probe_single_connector_modes,
125 .detect = xilinx_drm_connector_detect,
126 .destroy = xilinx_drm_connector_destroy,
127};
128
129static const struct xilinx_drm_connector_type connector_types[] = {
130 { "HDMIA", DRM_MODE_CONNECTOR_HDMIA },
131 { "DisplayPort", DRM_MODE_CONNECTOR_DisplayPort },
132};
133
134
135struct drm_connector *
136xilinx_drm_connector_create(struct drm_device *drm,
137 struct drm_encoder *base_encoder, int id)
138{
139 struct xilinx_drm_connector *connector;
140 const char *string;
141 int type = DRM_MODE_CONNECTOR_Unknown;
142 int i, ret;
143
144 connector = devm_kzalloc(drm->dev, sizeof(*connector), GFP_KERNEL);
145 if (!connector)
146 return ERR_PTR(-ENOMEM);
147
148 connector->base.polled = DRM_CONNECTOR_POLL_HPD |
149 DRM_CONNECTOR_POLL_CONNECT |
150 DRM_CONNECTOR_POLL_DISCONNECT;
151
152 ret = of_property_read_string_index(drm->dev->of_node,
153 "xlnx,connector-type", id, &string);
154 if (ret < 0) {
155 dev_err(drm->dev, "No connector type in DT\n");
156 return ERR_PTR(ret);
157 }
158
159 for (i = 0; i < ARRAY_SIZE(connector_types); i++)
160 if (strcmp(connector_types[i].name, string) == 0) {
161 type = connector_types[i].type;
162 break;
163 }
164
165 if (type == DRM_MODE_CONNECTOR_Unknown) {
166 dev_err(drm->dev, "Unknown connector type in DT\n");
167 return ERR_PTR(-EINVAL);
168 }
169
170 ret = drm_connector_init(drm, &connector->base,
171 &xilinx_drm_connector_funcs, type);
172 if (ret) {
173 DRM_ERROR("failed to initialize connector\n");
174 return ERR_PTR(ret);
175 }
176
177 drm_connector_helper_add(&connector->base,
178 &xilinx_drm_connector_helper_funcs);
179
180
181 ret = drm_connector_register(&connector->base);
182 if (ret) {
183 DRM_ERROR("failed to register a connector\n");
184 goto err_register;
185 }
186
187
188 ret = drm_mode_connector_attach_encoder(&connector->base, base_encoder);
189 if (ret) {
190 DRM_ERROR("failed to attach connector to encoder\n");
191 goto err_attach;
192 }
193 connector->encoder = base_encoder;
194 connector->base.dpms = DRM_MODE_DPMS_OFF;
195
196 return &connector->base;
197
198err_attach:
199 drm_connector_unregister(&connector->base);
200err_register:
201 drm_connector_cleanup(&connector->base);
202 return ERR_PTR(ret);
203}
204