]>
Commit | Line | Data |
---|---|---|
79e53945 JB |
1 | /* |
2 | * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> | |
f899fc64 | 3 | * Copyright (c) 2007, 2010 Intel Corporation |
79e53945 JB |
4 | * Jesse Barnes <jesse.barnes@intel.com> |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a | |
7 | * copy of this software and associated documentation files (the "Software"), | |
8 | * to deal in the Software without restriction, including without limitation | |
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
10 | * and/or sell copies of the Software, and to permit persons to whom the | |
11 | * Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice (including the next | |
14 | * paragraph) shall be included in all copies or substantial portions of the | |
15 | * Software. | |
16 | * | |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
23 | * DEALINGS IN THE SOFTWARE. | |
24 | */ | |
25 | ||
26 | #include <linux/i2c.h> | |
ec7f29ff JN |
27 | #include <linux/slab.h> |
28 | ||
1c21348d | 29 | #include <drm/drm_atomic_helper.h> |
e0dac65e | 30 | #include <drm/drm_edid.h> |
ec7f29ff | 31 | |
0ba0e9e1 | 32 | #include "i915_drv.h" |
ec7f29ff JN |
33 | #include "intel_connector.h" |
34 | #include "intel_drv.h" | |
79e53945 | 35 | |
1c21348d JN |
36 | int intel_connector_init(struct intel_connector *connector) |
37 | { | |
38 | struct intel_digital_connector_state *conn_state; | |
39 | ||
40 | /* | |
41 | * Allocate enough memory to hold intel_digital_connector_state, | |
42 | * This might be a few bytes too many, but for connectors that don't | |
43 | * need it we'll free the state and allocate a smaller one on the first | |
44 | * successful commit anyway. | |
45 | */ | |
46 | conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL); | |
47 | if (!conn_state) | |
48 | return -ENOMEM; | |
49 | ||
50 | __drm_atomic_helper_connector_reset(&connector->base, | |
51 | &conn_state->base); | |
52 | ||
53 | return 0; | |
54 | } | |
55 | ||
56 | struct intel_connector *intel_connector_alloc(void) | |
57 | { | |
58 | struct intel_connector *connector; | |
59 | ||
60 | connector = kzalloc(sizeof(*connector), GFP_KERNEL); | |
61 | if (!connector) | |
62 | return NULL; | |
63 | ||
64 | if (intel_connector_init(connector) < 0) { | |
65 | kfree(connector); | |
66 | return NULL; | |
67 | } | |
68 | ||
69 | return connector; | |
70 | } | |
71 | ||
72 | /* | |
73 | * Free the bits allocated by intel_connector_alloc. | |
74 | * This should only be used after intel_connector_alloc has returned | |
75 | * successfully, and before drm_connector_init returns successfully. | |
76 | * Otherwise the destroy callbacks for the connector and the state should | |
77 | * take care of proper cleanup/free (see intel_connector_destroy). | |
78 | */ | |
79 | void intel_connector_free(struct intel_connector *connector) | |
80 | { | |
81 | kfree(to_intel_digital_connector_state(connector->base.state)); | |
82 | kfree(connector); | |
83 | } | |
84 | ||
85 | /* | |
86 | * Connector type independent destroy hook for drm_connector_funcs. | |
87 | */ | |
88 | void intel_connector_destroy(struct drm_connector *connector) | |
89 | { | |
90 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
91 | ||
92 | kfree(intel_connector->detect_edid); | |
93 | ||
9055aac7 R |
94 | intel_hdcp_cleanup(intel_connector); |
95 | ||
1c21348d JN |
96 | if (!IS_ERR_OR_NULL(intel_connector->edid)) |
97 | kfree(intel_connector->edid); | |
98 | ||
99 | intel_panel_fini(&intel_connector->panel); | |
100 | ||
101 | drm_connector_cleanup(connector); | |
79a47cd3 LP |
102 | |
103 | if (intel_connector->port) | |
104 | drm_dp_mst_put_port_malloc(intel_connector->port); | |
105 | ||
1c21348d JN |
106 | kfree(connector); |
107 | } | |
108 | ||
109 | int intel_connector_register(struct drm_connector *connector) | |
110 | { | |
111 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
112 | int ret; | |
113 | ||
114 | ret = intel_backlight_device_register(intel_connector); | |
115 | if (ret) | |
116 | goto err; | |
117 | ||
41c43f9e CW |
118 | if (i915_inject_load_failure()) { |
119 | ret = -EFAULT; | |
120 | goto err_backlight; | |
121 | } | |
122 | ||
1c21348d JN |
123 | return 0; |
124 | ||
41c43f9e CW |
125 | err_backlight: |
126 | intel_backlight_device_unregister(intel_connector); | |
1c21348d JN |
127 | err: |
128 | return ret; | |
129 | } | |
130 | ||
131 | void intel_connector_unregister(struct drm_connector *connector) | |
132 | { | |
133 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
134 | ||
135 | intel_backlight_device_unregister(intel_connector); | |
136 | } | |
137 | ||
138 | void intel_connector_attach_encoder(struct intel_connector *connector, | |
139 | struct intel_encoder *encoder) | |
140 | { | |
141 | connector->encoder = encoder; | |
142 | drm_connector_attach_encoder(&connector->base, &encoder->base); | |
143 | } | |
144 | ||
145 | /* | |
146 | * Simple connector->get_hw_state implementation for encoders that support only | |
147 | * one connector and no cloning and hence the encoder state determines the state | |
148 | * of the connector. | |
149 | */ | |
150 | bool intel_connector_get_hw_state(struct intel_connector *connector) | |
151 | { | |
152 | enum pipe pipe = 0; | |
153 | struct intel_encoder *encoder = connector->encoder; | |
154 | ||
155 | return encoder->get_hw_state(encoder, &pipe); | |
156 | } | |
157 | ||
046c9bca JN |
158 | enum pipe intel_connector_get_pipe(struct intel_connector *connector) |
159 | { | |
160 | struct drm_device *dev = connector->base.dev; | |
161 | ||
162 | WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); | |
163 | ||
164 | if (!connector->base.state->crtc) | |
165 | return INVALID_PIPE; | |
166 | ||
167 | return to_intel_crtc(connector->base.state->crtc)->pipe; | |
168 | } | |
169 | ||
4eab8136 JN |
170 | /** |
171 | * intel_connector_update_modes - update connector from edid | |
172 | * @connector: DRM connector device to use | |
173 | * @edid: previously read EDID information | |
174 | */ | |
175 | int intel_connector_update_modes(struct drm_connector *connector, | |
176 | struct edid *edid) | |
177 | { | |
178 | int ret; | |
179 | ||
c555f023 | 180 | drm_connector_update_edid_property(connector, edid); |
4eab8136 | 181 | ret = drm_add_edid_modes(connector, edid); |
4eab8136 JN |
182 | |
183 | return ret; | |
184 | } | |
185 | ||
79e53945 JB |
186 | /** |
187 | * intel_ddc_get_modes - get modelist from monitor | |
188 | * @connector: DRM connector device to use | |
335af9a2 | 189 | * @adapter: i2c adapter |
79e53945 JB |
190 | * |
191 | * Fetch the EDID information from @connector using the DDC bus. | |
192 | */ | |
335af9a2 ZW |
193 | int intel_ddc_get_modes(struct drm_connector *connector, |
194 | struct i2c_adapter *adapter) | |
79e53945 JB |
195 | { |
196 | struct edid *edid; | |
ebda95a9 | 197 | int ret; |
79e53945 | 198 | |
335af9a2 | 199 | edid = drm_get_edid(connector, adapter); |
4eab8136 JN |
200 | if (!edid) |
201 | return 0; | |
79e53945 | 202 | |
ebda95a9 JN |
203 | ret = intel_connector_update_modes(connector, edid); |
204 | kfree(edid); | |
205 | ||
206 | return ret; | |
79e53945 | 207 | } |
e953fd7b | 208 | |
4a67d391 | 209 | static const struct drm_prop_enum_list force_audio_names[] = { |
ff5f4b05 SV |
210 | { HDMI_AUDIO_OFF_DVI, "force-dvi" }, |
211 | { HDMI_AUDIO_OFF, "off" }, | |
212 | { HDMI_AUDIO_AUTO, "auto" }, | |
213 | { HDMI_AUDIO_ON, "on" }, | |
3f43c48d CW |
214 | }; |
215 | ||
216 | void | |
217 | intel_attach_force_audio_property(struct drm_connector *connector) | |
218 | { | |
219 | struct drm_device *dev = connector->dev; | |
fac5e23e | 220 | struct drm_i915_private *dev_priv = to_i915(dev); |
3f43c48d | 221 | struct drm_property *prop; |
3f43c48d CW |
222 | |
223 | prop = dev_priv->force_audio_property; | |
224 | if (prop == NULL) { | |
4a67d391 | 225 | prop = drm_property_create_enum(dev, 0, |
3f43c48d | 226 | "audio", |
4a67d391 | 227 | force_audio_names, |
3f43c48d CW |
228 | ARRAY_SIZE(force_audio_names)); |
229 | if (prop == NULL) | |
230 | return; | |
231 | ||
3f43c48d CW |
232 | dev_priv->force_audio_property = prop; |
233 | } | |
662595df | 234 | drm_object_attach_property(&connector->base, prop, 0); |
3f43c48d CW |
235 | } |
236 | ||
4a67d391 | 237 | static const struct drm_prop_enum_list broadcast_rgb_names[] = { |
55bc60db VS |
238 | { INTEL_BROADCAST_RGB_AUTO, "Automatic" }, |
239 | { INTEL_BROADCAST_RGB_FULL, "Full" }, | |
240 | { INTEL_BROADCAST_RGB_LIMITED, "Limited 16:235" }, | |
e953fd7b CW |
241 | }; |
242 | ||
243 | void | |
244 | intel_attach_broadcast_rgb_property(struct drm_connector *connector) | |
245 | { | |
246 | struct drm_device *dev = connector->dev; | |
fac5e23e | 247 | struct drm_i915_private *dev_priv = to_i915(dev); |
e953fd7b | 248 | struct drm_property *prop; |
e953fd7b CW |
249 | |
250 | prop = dev_priv->broadcast_rgb_property; | |
251 | if (prop == NULL) { | |
4a67d391 | 252 | prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, |
e953fd7b | 253 | "Broadcast RGB", |
4a67d391 | 254 | broadcast_rgb_names, |
e953fd7b CW |
255 | ARRAY_SIZE(broadcast_rgb_names)); |
256 | if (prop == NULL) | |
257 | return; | |
258 | ||
e953fd7b CW |
259 | dev_priv->broadcast_rgb_property = prop; |
260 | } | |
261 | ||
662595df | 262 | drm_object_attach_property(&connector->base, prop, 0); |
e953fd7b | 263 | } |
7949dd47 VS |
264 | |
265 | void | |
266 | intel_attach_aspect_ratio_property(struct drm_connector *connector) | |
267 | { | |
268 | if (!drm_mode_create_aspect_ratio_property(connector->dev)) | |
269 | drm_object_attach_property(&connector->base, | |
270 | connector->dev->mode_config.aspect_ratio_property, | |
271 | DRM_MODE_PICTURE_ASPECT_NONE); | |
272 | } | |
2f146b78 US |
273 | |
274 | void | |
275 | intel_attach_colorspace_property(struct drm_connector *connector) | |
276 | { | |
277 | if (!drm_mode_create_colorspace_property(connector)) | |
278 | drm_object_attach_property(&connector->base, | |
279 | connector->colorspace_property, 0); | |
280 | } |