1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <drm/drmP.h>
21#include <drm/drm_crtc.h>
22#include <drm/drm_crtc_helper.h>
23#include <drm/drm_encoder_slave.h>
24
25#include <linux/device.h>
26
27#include "xylon_connector.h"
28#include "xylon_drv.h"
29
30struct xylon_drm_connector {
31 struct drm_connector base;
32 struct drm_encoder *encoder;
33};
34
35#define to_xylon_connector(x) container_of(x, struct xylon_drm_connector, base)
36
37static int xylon_drm_connector_get_modes(struct drm_connector *base_connector)
38{
39 struct xylon_drm_connector *connector =
40 to_xylon_connector(base_connector);
41 struct drm_encoder *encoder = connector->encoder;
42 struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
43 struct drm_encoder_slave_funcs *encoder_sfuncs =
44 encoder_slave->slave_funcs;
45 int count = 0;
46
47 if (encoder_sfuncs->get_modes)
48 count = encoder_sfuncs->get_modes(encoder, base_connector);
49
50 return count;
51}
52
53static int xylon_drm_connector_mode_valid(struct drm_connector *base_connector,
54 struct drm_display_mode *mode)
55{
56 struct xylon_drm_connector *connector =
57 to_xylon_connector(base_connector);
58 struct drm_encoder *encoder = connector->encoder;
59 struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
60 struct drm_encoder_slave_funcs *encoder_sfuncs =
61 encoder_slave->slave_funcs;
62 int ret = MODE_OK;
63
64 if (encoder_sfuncs->mode_valid)
65 ret = encoder_sfuncs->mode_valid(encoder, mode);
66
67 return ret;
68}
69
70static struct drm_encoder *
71xylon_drm_connector_best_encoder(struct drm_connector *base_connector)
72{
73 struct xylon_drm_connector *connector =
74 to_xylon_connector(base_connector);
75
76 return connector->encoder;
77}
78
79static struct drm_connector_helper_funcs xylon_drm_connector_helper_funcs = {
80 .get_modes = xylon_drm_connector_get_modes,
81 .mode_valid = xylon_drm_connector_mode_valid,
82 .best_encoder = xylon_drm_connector_best_encoder,
83};
84
85static enum drm_connector_status
86xylon_drm_connector_detect(struct drm_connector *base_connector, bool force)
87{
88 struct xylon_drm_connector *connector =
89 to_xylon_connector(base_connector);
90 enum drm_connector_status status = connector_status_unknown;
91 struct drm_encoder *encoder = connector->encoder;
92 struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
93 struct drm_encoder_slave_funcs *encoder_sfuncs =
94 encoder_slave->slave_funcs;
95
96 if (encoder_sfuncs->detect)
97 status = encoder_sfuncs->detect(encoder, base_connector);
98
99 if (force && (status != connector_status_connected))
100 status = encoder_sfuncs->detect(encoder, base_connector);
101
102 return status;
103}
104
105static void xylon_drm_connector_destroy(struct drm_connector *base_connector)
106{
107 drm_connector_unregister(base_connector);
108 drm_connector_cleanup(base_connector);
109}
110
111static struct drm_connector_funcs xylon_drm_connector_funcs = {
112 .dpms = drm_helper_connector_dpms,
113 .fill_modes = drm_helper_probe_single_connector_modes,
114 .detect = xylon_drm_connector_detect,
115 .destroy = xylon_drm_connector_destroy,
116};
117
118struct drm_connector *
119xylon_drm_connector_create(struct drm_device *dev,
120 struct drm_encoder *base_encoder)
121{
122 struct xylon_drm_connector *connector;
123 int ret;
124
125 connector = devm_kzalloc(dev->dev, sizeof(*connector), GFP_KERNEL);
126 if (!connector)
127 return ERR_PTR(-ENOMEM);
128
129 connector->base.encoder = base_encoder;
130 connector->base.polled = DRM_CONNECTOR_POLL_CONNECT |
131 DRM_CONNECTOR_POLL_DISCONNECT;
132
133 ret = drm_connector_init(dev, &connector->base,
134 &xylon_drm_connector_funcs,
135 DRM_MODE_CONNECTOR_HDMIA);
136 if (ret) {
137 DRM_ERROR("failed initialize connector\n");
138 return ERR_PTR(ret);
139 }
140
141 drm_connector_helper_add(&connector->base,
142 &xylon_drm_connector_helper_funcs);
143
144 ret = drm_connector_register(&connector->base);
145 if (ret) {
146 DRM_ERROR("failed register encoder connector\n");
147 goto err_register;
148 }
149
150 ret = drm_mode_connector_attach_encoder(&connector->base, base_encoder);
151 if (ret) {
152 DRM_ERROR("failed attach encoder connector\n");
153 goto err_attach;
154 }
155 connector->encoder = base_encoder;
156
157 return &connector->base;
158
159err_attach:
160 drm_connector_unregister(&connector->base);
161err_register:
162 drm_connector_cleanup(&connector->base);
163 return ERR_PTR(ret);
164}
165