1*98dc320aSriastradh /*	$NetBSD: nouveau_connector.c,v 1.7 2021/12/19 10:49:21 riastradh Exp $	*/
29d5db0c2Sriastradh 
3cb459498Sriastradh /*
4cb459498Sriastradh  * Copyright (C) 2008 Maarten Maathuis.
5cb459498Sriastradh  * All Rights Reserved.
6cb459498Sriastradh  *
7cb459498Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining
8cb459498Sriastradh  * a copy of this software and associated documentation files (the
9cb459498Sriastradh  * "Software"), to deal in the Software without restriction, including
10cb459498Sriastradh  * without limitation the rights to use, copy, modify, merge, publish,
11cb459498Sriastradh  * distribute, sublicense, and/or sell copies of the Software, and to
12cb459498Sriastradh  * permit persons to whom the Software is furnished to do so, subject to
13cb459498Sriastradh  * the following conditions:
14cb459498Sriastradh  *
15cb459498Sriastradh  * The above copyright notice and this permission notice (including the
16cb459498Sriastradh  * next paragraph) shall be included in all copies or substantial
17cb459498Sriastradh  * portions of the Software.
18cb459498Sriastradh  *
19cb459498Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20cb459498Sriastradh  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21cb459498Sriastradh  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22cb459498Sriastradh  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
23cb459498Sriastradh  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24cb459498Sriastradh  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25cb459498Sriastradh  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26cb459498Sriastradh  *
27cb459498Sriastradh  */
28cb459498Sriastradh 
299d5db0c2Sriastradh #include <sys/cdefs.h>
30*98dc320aSriastradh __KERNEL_RCSID(0, "$NetBSD: nouveau_connector.c,v 1.7 2021/12/19 10:49:21 riastradh Exp $");
319d5db0c2Sriastradh 
32cb459498Sriastradh #include <acpi/button.h>
33cb459498Sriastradh 
34cb459498Sriastradh #include <linux/pm_runtime.h>
35677dec6eSriastradh #include <linux/vga_switcheroo.h>
36cb459498Sriastradh 
37677dec6eSriastradh #include <drm/drm_atomic_helper.h>
38cb459498Sriastradh #include <drm/drm_edid.h>
39cb459498Sriastradh #include <drm/drm_crtc_helper.h>
40677dec6eSriastradh #include <drm/drm_probe_helper.h>
41677dec6eSriastradh #include <drm/drm_atomic.h>
42cb459498Sriastradh 
43cb459498Sriastradh #include "nouveau_reg.h"
44677dec6eSriastradh #include "nouveau_drv.h"
45cb459498Sriastradh #include "dispnv04/hw.h"
46cb459498Sriastradh #include "nouveau_acpi.h"
47cb459498Sriastradh 
48cb459498Sriastradh #include "nouveau_display.h"
49cb459498Sriastradh #include "nouveau_connector.h"
50cb459498Sriastradh #include "nouveau_encoder.h"
51cb459498Sriastradh #include "nouveau_crtc.h"
52cb459498Sriastradh 
53677dec6eSriastradh #include <nvif/class.h>
54677dec6eSriastradh #include <nvif/cl0046.h>
554e59feabSriastradh #include <nvif/event.h>
56cb459498Sriastradh 
57677dec6eSriastradh struct drm_display_mode *
nouveau_conn_native_mode(struct drm_connector * connector)58677dec6eSriastradh nouveau_conn_native_mode(struct drm_connector *connector)
59677dec6eSriastradh {
60677dec6eSriastradh 	const struct drm_connector_helper_funcs *helper = connector->helper_private;
61677dec6eSriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
62677dec6eSriastradh 	struct drm_device *dev = connector->dev;
63677dec6eSriastradh 	struct drm_display_mode *mode, *largest = NULL;
64677dec6eSriastradh 	int high_w = 0, high_h = 0, high_v = 0;
65677dec6eSriastradh 
66677dec6eSriastradh 	list_for_each_entry(mode, &connector->probed_modes, head) {
67677dec6eSriastradh 		mode->vrefresh = drm_mode_vrefresh(mode);
68677dec6eSriastradh 		if (helper->mode_valid(connector, mode) != MODE_OK ||
69677dec6eSriastradh 		    (mode->flags & DRM_MODE_FLAG_INTERLACE))
70677dec6eSriastradh 			continue;
71677dec6eSriastradh 
72677dec6eSriastradh 		/* Use preferred mode if there is one.. */
73677dec6eSriastradh 		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
74677dec6eSriastradh 			NV_DEBUG(drm, "native mode from preferred\n");
75677dec6eSriastradh 			return drm_mode_duplicate(dev, mode);
76677dec6eSriastradh 		}
77677dec6eSriastradh 
78677dec6eSriastradh 		/* Otherwise, take the resolution with the largest width, then
79677dec6eSriastradh 		 * height, then vertical refresh
80677dec6eSriastradh 		 */
81677dec6eSriastradh 		if (mode->hdisplay < high_w)
82677dec6eSriastradh 			continue;
83677dec6eSriastradh 
84677dec6eSriastradh 		if (mode->hdisplay == high_w && mode->vdisplay < high_h)
85677dec6eSriastradh 			continue;
86677dec6eSriastradh 
87677dec6eSriastradh 		if (mode->hdisplay == high_w && mode->vdisplay == high_h &&
88677dec6eSriastradh 		    mode->vrefresh < high_v)
89677dec6eSriastradh 			continue;
90677dec6eSriastradh 
91677dec6eSriastradh 		high_w = mode->hdisplay;
92677dec6eSriastradh 		high_h = mode->vdisplay;
93677dec6eSriastradh 		high_v = mode->vrefresh;
94677dec6eSriastradh 		largest = mode;
95677dec6eSriastradh 	}
96677dec6eSriastradh 
97677dec6eSriastradh 	NV_DEBUG(drm, "native mode from largest: %dx%d@%d\n",
98677dec6eSriastradh 		      high_w, high_h, high_v);
99677dec6eSriastradh 	return largest ? drm_mode_duplicate(dev, largest) : NULL;
100677dec6eSriastradh }
101677dec6eSriastradh 
102677dec6eSriastradh int
nouveau_conn_atomic_get_property(struct drm_connector * connector,const struct drm_connector_state * state,struct drm_property * property,u64 * val)103677dec6eSriastradh nouveau_conn_atomic_get_property(struct drm_connector *connector,
104677dec6eSriastradh 				 const struct drm_connector_state *state,
105677dec6eSriastradh 				 struct drm_property *property, u64 *val)
106677dec6eSriastradh {
107*98dc320aSriastradh 	const struct nouveau_conn_atom *asyc = nouveau_conn_atom_const(state);
108677dec6eSriastradh 	struct nouveau_display *disp = nouveau_display(connector->dev);
109677dec6eSriastradh 	struct drm_device *dev = connector->dev;
110677dec6eSriastradh 
111677dec6eSriastradh 	if (property == dev->mode_config.scaling_mode_property)
112677dec6eSriastradh 		*val = asyc->scaler.mode;
113677dec6eSriastradh 	else if (property == disp->underscan_property)
114677dec6eSriastradh 		*val = asyc->scaler.underscan.mode;
115677dec6eSriastradh 	else if (property == disp->underscan_hborder_property)
116677dec6eSriastradh 		*val = asyc->scaler.underscan.hborder;
117677dec6eSriastradh 	else if (property == disp->underscan_vborder_property)
118677dec6eSriastradh 		*val = asyc->scaler.underscan.vborder;
119677dec6eSriastradh 	else if (property == disp->dithering_mode)
120677dec6eSriastradh 		*val = asyc->dither.mode;
121677dec6eSriastradh 	else if (property == disp->dithering_depth)
122677dec6eSriastradh 		*val = asyc->dither.depth;
123677dec6eSriastradh 	else if (property == disp->vibrant_hue_property)
124677dec6eSriastradh 		*val = asyc->procamp.vibrant_hue;
125677dec6eSriastradh 	else if (property == disp->color_vibrance_property)
126677dec6eSriastradh 		*val = asyc->procamp.color_vibrance;
127677dec6eSriastradh 	else
128677dec6eSriastradh 		return -EINVAL;
129677dec6eSriastradh 
130677dec6eSriastradh 	return 0;
131677dec6eSriastradh }
132677dec6eSriastradh 
133677dec6eSriastradh int
nouveau_conn_atomic_set_property(struct drm_connector * connector,struct drm_connector_state * state,struct drm_property * property,u64 val)134677dec6eSriastradh nouveau_conn_atomic_set_property(struct drm_connector *connector,
135677dec6eSriastradh 				 struct drm_connector_state *state,
136677dec6eSriastradh 				 struct drm_property *property, u64 val)
137677dec6eSriastradh {
138677dec6eSriastradh 	struct drm_device *dev = connector->dev;
139677dec6eSriastradh 	struct nouveau_conn_atom *asyc = nouveau_conn_atom(state);
140677dec6eSriastradh 	struct nouveau_display *disp = nouveau_display(dev);
141677dec6eSriastradh 
142677dec6eSriastradh 	if (property == dev->mode_config.scaling_mode_property) {
143677dec6eSriastradh 		switch (val) {
144677dec6eSriastradh 		case DRM_MODE_SCALE_NONE:
145677dec6eSriastradh 			/* We allow 'None' for EDID modes, even on a fixed
146677dec6eSriastradh 			 * panel (some exist with support for lower refresh
147677dec6eSriastradh 			 * rates, which people might want to use for power-
148677dec6eSriastradh 			 * saving purposes).
149677dec6eSriastradh 			 *
150677dec6eSriastradh 			 * Non-EDID modes will force the use of GPU scaling
151677dec6eSriastradh 			 * to the native mode regardless of this setting.
152677dec6eSriastradh 			 */
153677dec6eSriastradh 			switch (connector->connector_type) {
154677dec6eSriastradh 			case DRM_MODE_CONNECTOR_LVDS:
155677dec6eSriastradh 			case DRM_MODE_CONNECTOR_eDP:
156677dec6eSriastradh 				/* ... except prior to G80, where the code
157677dec6eSriastradh 				 * doesn't support such things.
158677dec6eSriastradh 				 */
159677dec6eSriastradh 				if (disp->disp.object.oclass < NV50_DISP)
160677dec6eSriastradh 					return -EINVAL;
161677dec6eSriastradh 				break;
162677dec6eSriastradh 			default:
163677dec6eSriastradh 				break;
164677dec6eSriastradh 			}
165677dec6eSriastradh 		case DRM_MODE_SCALE_FULLSCREEN:
166677dec6eSriastradh 		case DRM_MODE_SCALE_CENTER:
167677dec6eSriastradh 		case DRM_MODE_SCALE_ASPECT:
168677dec6eSriastradh 			break;
169677dec6eSriastradh 		default:
170677dec6eSriastradh 			return -EINVAL;
171677dec6eSriastradh 		}
172677dec6eSriastradh 
173677dec6eSriastradh 		if (asyc->scaler.mode != val) {
174677dec6eSriastradh 			asyc->scaler.mode = val;
175677dec6eSriastradh 			asyc->set.scaler = true;
176677dec6eSriastradh 		}
177677dec6eSriastradh 	} else
178677dec6eSriastradh 	if (property == disp->underscan_property) {
179677dec6eSriastradh 		if (asyc->scaler.underscan.mode != val) {
180677dec6eSriastradh 			asyc->scaler.underscan.mode = val;
181677dec6eSriastradh 			asyc->set.scaler = true;
182677dec6eSriastradh 		}
183677dec6eSriastradh 	} else
184677dec6eSriastradh 	if (property == disp->underscan_hborder_property) {
185677dec6eSriastradh 		if (asyc->scaler.underscan.hborder != val) {
186677dec6eSriastradh 			asyc->scaler.underscan.hborder = val;
187677dec6eSriastradh 			asyc->set.scaler = true;
188677dec6eSriastradh 		}
189677dec6eSriastradh 	} else
190677dec6eSriastradh 	if (property == disp->underscan_vborder_property) {
191677dec6eSriastradh 		if (asyc->scaler.underscan.vborder != val) {
192677dec6eSriastradh 			asyc->scaler.underscan.vborder = val;
193677dec6eSriastradh 			asyc->set.scaler = true;
194677dec6eSriastradh 		}
195677dec6eSriastradh 	} else
196677dec6eSriastradh 	if (property == disp->dithering_mode) {
197677dec6eSriastradh 		if (asyc->dither.mode != val) {
198677dec6eSriastradh 			asyc->dither.mode = val;
199677dec6eSriastradh 			asyc->set.dither = true;
200677dec6eSriastradh 		}
201677dec6eSriastradh 	} else
202677dec6eSriastradh 	if (property == disp->dithering_depth) {
203677dec6eSriastradh 		if (asyc->dither.mode != val) {
204677dec6eSriastradh 			asyc->dither.depth = val;
205677dec6eSriastradh 			asyc->set.dither = true;
206677dec6eSriastradh 		}
207677dec6eSriastradh 	} else
208677dec6eSriastradh 	if (property == disp->vibrant_hue_property) {
209677dec6eSriastradh 		if (asyc->procamp.vibrant_hue != val) {
210677dec6eSriastradh 			asyc->procamp.vibrant_hue = val;
211677dec6eSriastradh 			asyc->set.procamp = true;
212677dec6eSriastradh 		}
213677dec6eSriastradh 	} else
214677dec6eSriastradh 	if (property == disp->color_vibrance_property) {
215677dec6eSriastradh 		if (asyc->procamp.color_vibrance != val) {
216677dec6eSriastradh 			asyc->procamp.color_vibrance = val;
217677dec6eSriastradh 			asyc->set.procamp = true;
218677dec6eSriastradh 		}
219677dec6eSriastradh 	} else {
220677dec6eSriastradh 		return -EINVAL;
221677dec6eSriastradh 	}
222677dec6eSriastradh 
223677dec6eSriastradh 	return 0;
224677dec6eSriastradh }
225677dec6eSriastradh 
226677dec6eSriastradh void
nouveau_conn_atomic_destroy_state(struct drm_connector * connector,struct drm_connector_state * state)227677dec6eSriastradh nouveau_conn_atomic_destroy_state(struct drm_connector *connector,
228677dec6eSriastradh 				  struct drm_connector_state *state)
229677dec6eSriastradh {
230677dec6eSriastradh 	struct nouveau_conn_atom *asyc = nouveau_conn_atom(state);
231677dec6eSriastradh 	__drm_atomic_helper_connector_destroy_state(&asyc->state);
232677dec6eSriastradh 	kfree(asyc);
233677dec6eSriastradh }
234677dec6eSriastradh 
235677dec6eSriastradh struct drm_connector_state *
nouveau_conn_atomic_duplicate_state(struct drm_connector * connector)236677dec6eSriastradh nouveau_conn_atomic_duplicate_state(struct drm_connector *connector)
237677dec6eSriastradh {
238677dec6eSriastradh 	struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state);
239677dec6eSriastradh 	struct nouveau_conn_atom *asyc;
240677dec6eSriastradh 	if (!(asyc = kmalloc(sizeof(*asyc), GFP_KERNEL)))
241677dec6eSriastradh 		return NULL;
242677dec6eSriastradh 	__drm_atomic_helper_connector_duplicate_state(connector, &asyc->state);
243677dec6eSriastradh 	asyc->dither = armc->dither;
244677dec6eSriastradh 	asyc->scaler = armc->scaler;
245677dec6eSriastradh 	asyc->procamp = armc->procamp;
246677dec6eSriastradh 	asyc->set.mask = 0;
247677dec6eSriastradh 	return &asyc->state;
248677dec6eSriastradh }
249677dec6eSriastradh 
250677dec6eSriastradh void
nouveau_conn_reset(struct drm_connector * connector)251677dec6eSriastradh nouveau_conn_reset(struct drm_connector *connector)
252677dec6eSriastradh {
253677dec6eSriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
254677dec6eSriastradh 	struct nouveau_conn_atom *asyc;
255677dec6eSriastradh 
256677dec6eSriastradh 	if (drm_drv_uses_atomic_modeset(connector->dev)) {
257677dec6eSriastradh 		if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL))))
258677dec6eSriastradh 			return;
259677dec6eSriastradh 
260677dec6eSriastradh 		if (connector->state)
261677dec6eSriastradh 			nouveau_conn_atomic_destroy_state(connector,
262677dec6eSriastradh 							  connector->state);
263677dec6eSriastradh 
264677dec6eSriastradh 		__drm_atomic_helper_connector_reset(connector, &asyc->state);
265677dec6eSriastradh 	} else {
266677dec6eSriastradh 		asyc = &nv_connector->properties_state;
267677dec6eSriastradh 	}
268677dec6eSriastradh 
269677dec6eSriastradh 	asyc->dither.mode = DITHERING_MODE_AUTO;
270677dec6eSriastradh 	asyc->dither.depth = DITHERING_DEPTH_AUTO;
271677dec6eSriastradh 	asyc->scaler.mode = DRM_MODE_SCALE_NONE;
272677dec6eSriastradh 	asyc->scaler.underscan.mode = UNDERSCAN_OFF;
273677dec6eSriastradh 	asyc->procamp.color_vibrance = 150;
274677dec6eSriastradh 	asyc->procamp.vibrant_hue = 90;
275677dec6eSriastradh 
276677dec6eSriastradh 	if (nouveau_display(connector->dev)->disp.object.oclass < NV50_DISP) {
277677dec6eSriastradh 		switch (connector->connector_type) {
278677dec6eSriastradh 		case DRM_MODE_CONNECTOR_LVDS:
279677dec6eSriastradh 			/* See note in nouveau_conn_atomic_set_property(). */
280677dec6eSriastradh 			asyc->scaler.mode = DRM_MODE_SCALE_FULLSCREEN;
281677dec6eSriastradh 			break;
282677dec6eSriastradh 		default:
283677dec6eSriastradh 			break;
284677dec6eSriastradh 		}
285677dec6eSriastradh 	}
286677dec6eSriastradh }
287677dec6eSriastradh 
288677dec6eSriastradh void
nouveau_conn_attach_properties(struct drm_connector * connector)289677dec6eSriastradh nouveau_conn_attach_properties(struct drm_connector *connector)
290677dec6eSriastradh {
291677dec6eSriastradh 	struct drm_device *dev = connector->dev;
292677dec6eSriastradh 	struct nouveau_display *disp = nouveau_display(dev);
293677dec6eSriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
294677dec6eSriastradh 	struct nouveau_conn_atom *armc;
295677dec6eSriastradh 
296677dec6eSriastradh 	if (drm_drv_uses_atomic_modeset(connector->dev))
297677dec6eSriastradh 		armc = nouveau_conn_atom(connector->state);
298677dec6eSriastradh 	else
299677dec6eSriastradh 		armc = &nv_connector->properties_state;
300677dec6eSriastradh 
301677dec6eSriastradh 	/* Init DVI-I specific properties. */
302677dec6eSriastradh 	if (connector->connector_type == DRM_MODE_CONNECTOR_DVII)
303677dec6eSriastradh 		drm_object_attach_property(&connector->base, dev->mode_config.
304677dec6eSriastradh 					   dvi_i_subconnector_property, 0);
305677dec6eSriastradh 
306677dec6eSriastradh 	/* Add overscan compensation options to digital outputs. */
307677dec6eSriastradh 	if (disp->underscan_property &&
308677dec6eSriastradh 	    (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
309677dec6eSriastradh 	     connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
310677dec6eSriastradh 	     connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
311677dec6eSriastradh 	     connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)) {
312677dec6eSriastradh 		drm_object_attach_property(&connector->base,
313677dec6eSriastradh 					   disp->underscan_property,
314677dec6eSriastradh 					   UNDERSCAN_OFF);
315677dec6eSriastradh 		drm_object_attach_property(&connector->base,
316677dec6eSriastradh 					   disp->underscan_hborder_property, 0);
317677dec6eSriastradh 		drm_object_attach_property(&connector->base,
318677dec6eSriastradh 					   disp->underscan_vborder_property, 0);
319677dec6eSriastradh 	}
320677dec6eSriastradh 
321677dec6eSriastradh 	/* Add hue and saturation options. */
322677dec6eSriastradh 	if (disp->vibrant_hue_property)
323677dec6eSriastradh 		drm_object_attach_property(&connector->base,
324677dec6eSriastradh 					   disp->vibrant_hue_property,
325677dec6eSriastradh 					   armc->procamp.vibrant_hue);
326677dec6eSriastradh 	if (disp->color_vibrance_property)
327677dec6eSriastradh 		drm_object_attach_property(&connector->base,
328677dec6eSriastradh 					   disp->color_vibrance_property,
329677dec6eSriastradh 					   armc->procamp.color_vibrance);
330677dec6eSriastradh 
331677dec6eSriastradh 	/* Scaling mode property. */
332677dec6eSriastradh 	switch (connector->connector_type) {
333677dec6eSriastradh 	case DRM_MODE_CONNECTOR_TV:
334677dec6eSriastradh 		break;
335677dec6eSriastradh 	case DRM_MODE_CONNECTOR_VGA:
336677dec6eSriastradh 		if (disp->disp.object.oclass < NV50_DISP)
337677dec6eSriastradh 			break; /* Can only scale on DFPs. */
338677dec6eSriastradh 		/* Fall-through. */
339677dec6eSriastradh 	default:
340677dec6eSriastradh 		drm_object_attach_property(&connector->base, dev->mode_config.
341677dec6eSriastradh 					   scaling_mode_property,
342677dec6eSriastradh 					   armc->scaler.mode);
343677dec6eSriastradh 		break;
344677dec6eSriastradh 	}
345677dec6eSriastradh 
346677dec6eSriastradh 	/* Dithering properties. */
347677dec6eSriastradh 	switch (connector->connector_type) {
348677dec6eSriastradh 	case DRM_MODE_CONNECTOR_TV:
349677dec6eSriastradh 	case DRM_MODE_CONNECTOR_VGA:
350677dec6eSriastradh 		break;
351677dec6eSriastradh 	default:
352677dec6eSriastradh 		if (disp->dithering_mode) {
353677dec6eSriastradh 			drm_object_attach_property(&connector->base,
354677dec6eSriastradh 						   disp->dithering_mode,
355677dec6eSriastradh 						   armc->dither.mode);
356677dec6eSriastradh 		}
357677dec6eSriastradh 		if (disp->dithering_depth) {
358677dec6eSriastradh 			drm_object_attach_property(&connector->base,
359677dec6eSriastradh 						   disp->dithering_depth,
360677dec6eSriastradh 						   armc->dither.depth);
361677dec6eSriastradh 		}
362677dec6eSriastradh 		break;
363677dec6eSriastradh 	}
364677dec6eSriastradh }
365677dec6eSriastradh 
366cb459498Sriastradh MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
3674e59feabSriastradh int nouveau_tv_disable = 0;
368cb459498Sriastradh module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
369cb459498Sriastradh 
37004fcfa4fSriastradh #if defined(CONFIG_ACPI_BUTTON) || \
37104fcfa4fSriastradh 	(defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
372cb459498Sriastradh MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
3734e59feabSriastradh int nouveau_ignorelid = 0;
374cb459498Sriastradh module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
37504fcfa4fSriastradh #endif
376cb459498Sriastradh 
377cb459498Sriastradh MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)");
3784e59feabSriastradh int nouveau_duallink = 1;
379cb459498Sriastradh module_param_named(duallink, nouveau_duallink, int, 0400);
380cb459498Sriastradh 
381677dec6eSriastradh MODULE_PARM_DESC(hdmimhz, "Force a maximum HDMI pixel clock (in MHz)");
382677dec6eSriastradh int nouveau_hdmimhz = 0;
383677dec6eSriastradh module_param_named(hdmimhz, nouveau_hdmimhz, int, 0400);
384677dec6eSriastradh 
385cb459498Sriastradh struct nouveau_encoder *
find_encoder(struct drm_connector * connector,int type)386cb459498Sriastradh find_encoder(struct drm_connector *connector, int type)
387cb459498Sriastradh {
388cb459498Sriastradh 	struct nouveau_encoder *nv_encoder;
3894e59feabSriastradh 	struct drm_encoder *enc;
390cb459498Sriastradh 
391677dec6eSriastradh 	drm_connector_for_each_possible_encoder(connector, enc) {
3924e59feabSriastradh 		nv_encoder = nouveau_encoder(enc);
393cb459498Sriastradh 
3944e59feabSriastradh 		if (type == DCB_OUTPUT_ANY ||
3954e59feabSriastradh 		    (nv_encoder->dcb && nv_encoder->dcb->type == type))
396cb459498Sriastradh 			return nv_encoder;
397cb459498Sriastradh 	}
398cb459498Sriastradh 
399cb459498Sriastradh 	return NULL;
400cb459498Sriastradh }
401cb459498Sriastradh 
402cb459498Sriastradh struct nouveau_connector *
nouveau_encoder_connector_get(struct nouveau_encoder * encoder)403cb459498Sriastradh nouveau_encoder_connector_get(struct nouveau_encoder *encoder)
404cb459498Sriastradh {
405cb459498Sriastradh 	struct drm_device *dev = to_drm_encoder(encoder)->dev;
406cb459498Sriastradh 	struct drm_connector *drm_connector;
407cb459498Sriastradh 
408cb459498Sriastradh 	list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
409cb459498Sriastradh 		if (drm_connector->encoder == to_drm_encoder(encoder))
410cb459498Sriastradh 			return nouveau_connector(drm_connector);
411cb459498Sriastradh 	}
412cb459498Sriastradh 
413cb459498Sriastradh 	return NULL;
414cb459498Sriastradh }
415cb459498Sriastradh 
416cb459498Sriastradh static void
nouveau_connector_destroy(struct drm_connector * connector)417cb459498Sriastradh nouveau_connector_destroy(struct drm_connector *connector)
418cb459498Sriastradh {
419cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
4204e59feabSriastradh 	nvif_notify_fini(&nv_connector->hpd);
421cb459498Sriastradh 	kfree(nv_connector->edid);
4224e59feabSriastradh 	drm_connector_unregister(connector);
423cb459498Sriastradh 	drm_connector_cleanup(connector);
424677dec6eSriastradh 	if (nv_connector->aux.transfer) {
425677dec6eSriastradh 		drm_dp_cec_unregister_connector(&nv_connector->aux);
4264e59feabSriastradh 		drm_dp_aux_unregister(&nv_connector->aux);
427*98dc320aSriastradh 		kfree(__UNCONST(nv_connector->aux.name));
428677dec6eSriastradh 	}
429cb459498Sriastradh 	kfree(connector);
430cb459498Sriastradh }
431cb459498Sriastradh 
4324e59feabSriastradh static struct nouveau_encoder *
nouveau_connector_ddc_detect(struct drm_connector * connector)4334e59feabSriastradh nouveau_connector_ddc_detect(struct drm_connector *connector)
434cb459498Sriastradh {
435cb459498Sriastradh 	struct drm_device *dev = connector->dev;
436677dec6eSriastradh 	struct nouveau_encoder *nv_encoder = NULL, *found = NULL;
4374e59feabSriastradh 	struct drm_encoder *encoder;
438677dec6eSriastradh 	int ret;
439677dec6eSriastradh 	bool switcheroo_ddc = false;
440cb459498Sriastradh 
441677dec6eSriastradh 	drm_connector_for_each_possible_encoder(connector, encoder) {
4424e59feabSriastradh 		nv_encoder = nouveau_encoder(encoder);
443cb459498Sriastradh 
444677dec6eSriastradh 		switch (nv_encoder->dcb->type) {
445677dec6eSriastradh 		case DCB_OUTPUT_DP:
446677dec6eSriastradh 			ret = nouveau_dp_detect(nv_encoder);
447677dec6eSriastradh 			if (ret == NOUVEAU_DP_MST)
448677dec6eSriastradh 				return NULL;
449677dec6eSriastradh 			else if (ret == NOUVEAU_DP_SST)
450677dec6eSriastradh 				found = nv_encoder;
451677dec6eSriastradh 
4524e59feabSriastradh 			break;
453677dec6eSriastradh 		case DCB_OUTPUT_LVDS:
454677dec6eSriastradh 			switcheroo_ddc = !!(vga_switcheroo_handler_flags() &
455677dec6eSriastradh 					    VGA_SWITCHEROO_CAN_SWITCH_DDC);
456677dec6eSriastradh 		/* fall-through */
457677dec6eSriastradh 		default:
458677dec6eSriastradh 			if (!nv_encoder->i2c)
459677dec6eSriastradh 				break;
460677dec6eSriastradh 
461*98dc320aSriastradh #ifdef __NetBSD__
462*98dc320aSriastradh 			__USE(switcheroo_ddc);
463*98dc320aSriastradh 			__USE(dev);
464*98dc320aSriastradh #else
465677dec6eSriastradh 			if (switcheroo_ddc)
466677dec6eSriastradh 				vga_switcheroo_lock_ddc(dev->pdev);
467*98dc320aSriastradh #endif
4684e59feabSriastradh 			if (nvkm_probe_i2c(nv_encoder->i2c, 0x50))
469677dec6eSriastradh 				found = nv_encoder;
470*98dc320aSriastradh #ifndef __NetBSD__
471677dec6eSriastradh 			if (switcheroo_ddc)
472677dec6eSriastradh 				vga_switcheroo_unlock_ddc(dev->pdev);
473*98dc320aSriastradh #endif
474677dec6eSriastradh 
475cb459498Sriastradh 			break;
476cb459498Sriastradh 		}
477677dec6eSriastradh 		if (found)
478677dec6eSriastradh 			break;
479cb459498Sriastradh 	}
480cb459498Sriastradh 
481677dec6eSriastradh 	return found;
482cb459498Sriastradh }
483cb459498Sriastradh 
484cb459498Sriastradh static struct nouveau_encoder *
nouveau_connector_of_detect(struct drm_connector * connector)485cb459498Sriastradh nouveau_connector_of_detect(struct drm_connector *connector)
486cb459498Sriastradh {
487cb459498Sriastradh #ifdef __powerpc__
488cb459498Sriastradh 	struct drm_device *dev = connector->dev;
489cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
490cb459498Sriastradh 	struct nouveau_encoder *nv_encoder;
491cb459498Sriastradh 	struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
492cb459498Sriastradh 
493cb459498Sriastradh 	if (!dn ||
494cb459498Sriastradh 	    !((nv_encoder = find_encoder(connector, DCB_OUTPUT_TMDS)) ||
495cb459498Sriastradh 	      (nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG))))
496cb459498Sriastradh 		return NULL;
497cb459498Sriastradh 
498cb459498Sriastradh 	for_each_child_of_node(dn, cn) {
499cb459498Sriastradh 		const char *name = of_get_property(cn, "name", NULL);
500cb459498Sriastradh 		const void *edid = of_get_property(cn, "EDID", NULL);
501cb459498Sriastradh 		int idx = name ? name[strlen(name) - 1] - 'A' : 0;
502cb459498Sriastradh 
503cb459498Sriastradh 		if (nv_encoder->dcb->i2c_index == idx && edid) {
504cb459498Sriastradh 			nv_connector->edid =
505cb459498Sriastradh 				kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
506cb459498Sriastradh 			of_node_put(cn);
507cb459498Sriastradh 			return nv_encoder;
508cb459498Sriastradh 		}
509cb459498Sriastradh 	}
510cb459498Sriastradh #endif
511cb459498Sriastradh 	return NULL;
512cb459498Sriastradh }
513cb459498Sriastradh 
514cb459498Sriastradh static void
nouveau_connector_set_encoder(struct drm_connector * connector,struct nouveau_encoder * nv_encoder)515cb459498Sriastradh nouveau_connector_set_encoder(struct drm_connector *connector,
516cb459498Sriastradh 			      struct nouveau_encoder *nv_encoder)
517cb459498Sriastradh {
518cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
519cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
520cb459498Sriastradh 	struct drm_device *dev = connector->dev;
521cb459498Sriastradh 
522cb459498Sriastradh 	if (nv_connector->detected_encoder == nv_encoder)
523cb459498Sriastradh 		return;
524cb459498Sriastradh 	nv_connector->detected_encoder = nv_encoder;
525cb459498Sriastradh 
526677dec6eSriastradh 	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
527cb459498Sriastradh 		connector->interlace_allowed = true;
528cb459498Sriastradh 		connector->doublescan_allowed = true;
529cb459498Sriastradh 	} else
530cb459498Sriastradh 	if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS ||
531cb459498Sriastradh 	    nv_encoder->dcb->type == DCB_OUTPUT_TMDS) {
532cb459498Sriastradh 		connector->doublescan_allowed = false;
533cb459498Sriastradh 		connector->interlace_allowed = false;
534cb459498Sriastradh 	} else {
535cb459498Sriastradh 		connector->doublescan_allowed = true;
536677dec6eSriastradh 		if (drm->client.device.info.family == NV_DEVICE_INFO_V0_KELVIN ||
537677dec6eSriastradh 		    (drm->client.device.info.family == NV_DEVICE_INFO_V0_CELSIUS &&
538cb459498Sriastradh 		     (dev->pdev->device & 0x0ff0) != 0x0100 &&
539cb459498Sriastradh 		     (dev->pdev->device & 0x0ff0) != 0x0150))
540cb459498Sriastradh 			/* HW is broken */
541cb459498Sriastradh 			connector->interlace_allowed = false;
542cb459498Sriastradh 		else
543cb459498Sriastradh 			connector->interlace_allowed = true;
544cb459498Sriastradh 	}
545cb459498Sriastradh 
546cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
547cb459498Sriastradh 		drm_object_property_set_value(&connector->base,
548cb459498Sriastradh 			dev->mode_config.dvi_i_subconnector_property,
549cb459498Sriastradh 			nv_encoder->dcb->type == DCB_OUTPUT_TMDS ?
550cb459498Sriastradh 			DRM_MODE_SUBCONNECTOR_DVID :
551cb459498Sriastradh 			DRM_MODE_SUBCONNECTOR_DVIA);
552cb459498Sriastradh 	}
553cb459498Sriastradh }
554cb459498Sriastradh 
555cb459498Sriastradh static enum drm_connector_status
nouveau_connector_detect(struct drm_connector * connector,bool force)556cb459498Sriastradh nouveau_connector_detect(struct drm_connector *connector, bool force)
557cb459498Sriastradh {
558cb459498Sriastradh 	struct drm_device *dev = connector->dev;
559cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
560cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
561cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = NULL;
562cb459498Sriastradh 	struct nouveau_encoder *nv_partner;
5634e59feabSriastradh 	struct i2c_adapter *i2c;
564cb459498Sriastradh 	int type;
565cb459498Sriastradh 	int ret;
566cb459498Sriastradh 	enum drm_connector_status conn_status = connector_status_disconnected;
567cb459498Sriastradh 
568cb459498Sriastradh 	/* Cleanup the previous EDID block. */
569cb459498Sriastradh 	if (nv_connector->edid) {
570677dec6eSriastradh 		drm_connector_update_edid_property(connector, NULL);
571cb459498Sriastradh 		kfree(nv_connector->edid);
572cb459498Sriastradh 		nv_connector->edid = NULL;
573cb459498Sriastradh 	}
574cb459498Sriastradh 
575677dec6eSriastradh 	/* Outputs are only polled while runtime active, so resuming the
576677dec6eSriastradh 	 * device here is unnecessary (and would deadlock upon runtime suspend
577677dec6eSriastradh 	 * because it waits for polling to finish). We do however, want to
578677dec6eSriastradh 	 * prevent the autosuspend timer from elapsing during this operation
579677dec6eSriastradh 	 * if possible.
5804e59feabSriastradh 	 */
581677dec6eSriastradh 	if (drm_kms_helper_is_poll_worker()) {
582677dec6eSriastradh 		pm_runtime_get_noresume(dev->dev);
583677dec6eSriastradh 	} else {
584677dec6eSriastradh 		ret = pm_runtime_get_sync(dev->dev);
585cb459498Sriastradh 		if (ret < 0 && ret != -EACCES)
586cb459498Sriastradh 			return conn_status;
5874e59feabSriastradh 	}
588cb459498Sriastradh 
5894e59feabSriastradh 	nv_encoder = nouveau_connector_ddc_detect(connector);
5904e59feabSriastradh 	if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
591677dec6eSriastradh 		if ((vga_switcheroo_handler_flags() &
592677dec6eSriastradh 		     VGA_SWITCHEROO_CAN_SWITCH_DDC) &&
593677dec6eSriastradh 		    nv_connector->type == DCB_CONNECTOR_LVDS)
594677dec6eSriastradh 			nv_connector->edid = drm_get_edid_switcheroo(connector,
595677dec6eSriastradh 								     i2c);
596677dec6eSriastradh 		else
5974e59feabSriastradh 			nv_connector->edid = drm_get_edid(connector, i2c);
598677dec6eSriastradh 
599677dec6eSriastradh 		drm_connector_update_edid_property(connector,
600cb459498Sriastradh 							nv_connector->edid);
601cb459498Sriastradh 		if (!nv_connector->edid) {
602cb459498Sriastradh 			NV_ERROR(drm, "DDC responded, but no EDID for %s\n",
6034e59feabSriastradh 				 connector->name);
604cb459498Sriastradh 			goto detect_analog;
605cb459498Sriastradh 		}
606cb459498Sriastradh 
607cb459498Sriastradh 		/* Override encoder type for DVI-I based on whether EDID
608cb459498Sriastradh 		 * says the display is digital or analog, both use the
609cb459498Sriastradh 		 * same i2c channel so the value returned from ddc_detect
610cb459498Sriastradh 		 * isn't necessarily correct.
611cb459498Sriastradh 		 */
612cb459498Sriastradh 		nv_partner = NULL;
613cb459498Sriastradh 		if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS)
614cb459498Sriastradh 			nv_partner = find_encoder(connector, DCB_OUTPUT_ANALOG);
615cb459498Sriastradh 		if (nv_encoder->dcb->type == DCB_OUTPUT_ANALOG)
616cb459498Sriastradh 			nv_partner = find_encoder(connector, DCB_OUTPUT_TMDS);
617cb459498Sriastradh 
618cb459498Sriastradh 		if (nv_partner && ((nv_encoder->dcb->type == DCB_OUTPUT_ANALOG &&
619cb459498Sriastradh 				    nv_partner->dcb->type == DCB_OUTPUT_TMDS) ||
620cb459498Sriastradh 				   (nv_encoder->dcb->type == DCB_OUTPUT_TMDS &&
621cb459498Sriastradh 				    nv_partner->dcb->type == DCB_OUTPUT_ANALOG))) {
622cb459498Sriastradh 			if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
623cb459498Sriastradh 				type = DCB_OUTPUT_TMDS;
624cb459498Sriastradh 			else
625cb459498Sriastradh 				type = DCB_OUTPUT_ANALOG;
626cb459498Sriastradh 
627cb459498Sriastradh 			nv_encoder = find_encoder(connector, type);
6283b962aacSriastradh 			BUG_ON(nv_encoder == NULL);
629cb459498Sriastradh 		}
630cb459498Sriastradh 
631cb459498Sriastradh 		nouveau_connector_set_encoder(connector, nv_encoder);
632cb459498Sriastradh 		conn_status = connector_status_connected;
633677dec6eSriastradh 		drm_dp_cec_set_edid(&nv_connector->aux, nv_connector->edid);
634cb459498Sriastradh 		goto out;
635cb459498Sriastradh 	}
636cb459498Sriastradh 
637cb459498Sriastradh 	nv_encoder = nouveau_connector_of_detect(connector);
638cb459498Sriastradh 	if (nv_encoder) {
639cb459498Sriastradh 		nouveau_connector_set_encoder(connector, nv_encoder);
640cb459498Sriastradh 		conn_status = connector_status_connected;
641cb459498Sriastradh 		goto out;
642cb459498Sriastradh 	}
643cb459498Sriastradh 
644cb459498Sriastradh detect_analog:
645cb459498Sriastradh 	nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG);
646cb459498Sriastradh 	if (!nv_encoder && !nouveau_tv_disable)
647cb459498Sriastradh 		nv_encoder = find_encoder(connector, DCB_OUTPUT_TV);
648cb459498Sriastradh 	if (nv_encoder && force) {
649cb459498Sriastradh 		struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
6504e59feabSriastradh 		const struct drm_encoder_helper_funcs *helper =
651cb459498Sriastradh 						encoder->helper_private;
652cb459498Sriastradh 
653cb459498Sriastradh 		if (helper->detect(encoder, connector) ==
654cb459498Sriastradh 						connector_status_connected) {
655cb459498Sriastradh 			nouveau_connector_set_encoder(connector, nv_encoder);
656cb459498Sriastradh 			conn_status = connector_status_connected;
657cb459498Sriastradh 			goto out;
658cb459498Sriastradh 		}
659cb459498Sriastradh 
660cb459498Sriastradh 	}
661cb459498Sriastradh 
662cb459498Sriastradh  out:
663cb459498Sriastradh 
664677dec6eSriastradh 	pm_runtime_mark_last_busy(dev->dev);
665677dec6eSriastradh 	pm_runtime_put_autosuspend(dev->dev);
666cb459498Sriastradh 
667cb459498Sriastradh 	return conn_status;
668cb459498Sriastradh }
669cb459498Sriastradh 
670cb459498Sriastradh static enum drm_connector_status
nouveau_connector_detect_lvds(struct drm_connector * connector,bool force)671cb459498Sriastradh nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
672cb459498Sriastradh {
673cb459498Sriastradh 	struct drm_device *dev = connector->dev;
674cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
675cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
676cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = NULL;
677cb459498Sriastradh 	enum drm_connector_status status = connector_status_disconnected;
678cb459498Sriastradh 
679cb459498Sriastradh 	/* Cleanup the previous EDID block. */
680cb459498Sriastradh 	if (nv_connector->edid) {
681677dec6eSriastradh 		drm_connector_update_edid_property(connector, NULL);
682cb459498Sriastradh 		kfree(nv_connector->edid);
683cb459498Sriastradh 		nv_connector->edid = NULL;
684cb459498Sriastradh 	}
685cb459498Sriastradh 
686cb459498Sriastradh 	nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
687cb459498Sriastradh 	if (!nv_encoder)
688cb459498Sriastradh 		return connector_status_disconnected;
689cb459498Sriastradh 
690cb459498Sriastradh 	/* Try retrieving EDID via DDC */
691cb459498Sriastradh 	if (!drm->vbios.fp_no_ddc) {
692cb459498Sriastradh 		status = nouveau_connector_detect(connector, force);
693cb459498Sriastradh 		if (status == connector_status_connected)
694cb459498Sriastradh 			goto out;
695cb459498Sriastradh 	}
696cb459498Sriastradh 
697cb459498Sriastradh 	/* On some laptops (Sony, i'm looking at you) there appears to
698cb459498Sriastradh 	 * be no direct way of accessing the panel's EDID.  The only
699cb459498Sriastradh 	 * option available to us appears to be to ask ACPI for help..
700cb459498Sriastradh 	 *
701cb459498Sriastradh 	 * It's important this check's before trying straps, one of the
702cb459498Sriastradh 	 * said manufacturer's laptops are configured in such a way
703cb459498Sriastradh 	 * the nouveau decides an entry in the VBIOS FP mode table is
704cb459498Sriastradh 	 * valid - it's not (rh#613284)
705cb459498Sriastradh 	 */
706cb459498Sriastradh 	if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
707cb459498Sriastradh 		if ((nv_connector->edid = nouveau_acpi_edid(dev, connector))) {
708cb459498Sriastradh 			status = connector_status_connected;
709cb459498Sriastradh 			goto out;
710cb459498Sriastradh 		}
711cb459498Sriastradh 	}
712cb459498Sriastradh 
713cb459498Sriastradh 	/* If no EDID found above, and the VBIOS indicates a hardcoded
714cb459498Sriastradh 	 * modeline is avalilable for the panel, set it as the panel's
715cb459498Sriastradh 	 * native mode and exit.
716cb459498Sriastradh 	 */
717cb459498Sriastradh 	if (nouveau_bios_fp_mode(dev, NULL) && (drm->vbios.fp_no_ddc ||
718cb459498Sriastradh 	    nv_encoder->dcb->lvdsconf.use_straps_for_mode)) {
719cb459498Sriastradh 		status = connector_status_connected;
720cb459498Sriastradh 		goto out;
721cb459498Sriastradh 	}
722cb459498Sriastradh 
723cb459498Sriastradh 	/* Still nothing, some VBIOS images have a hardcoded EDID block
724cb459498Sriastradh 	 * stored for the panel stored in them.
725cb459498Sriastradh 	 */
726cb459498Sriastradh 	if (!drm->vbios.fp_no_ddc) {
727cb459498Sriastradh 		struct edid *edid =
728cb459498Sriastradh 			(struct edid *)nouveau_bios_embedded_edid(dev);
729cb459498Sriastradh 		if (edid) {
730cb459498Sriastradh 			nv_connector->edid =
731cb459498Sriastradh 					kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
732cb459498Sriastradh 			if (nv_connector->edid)
733cb459498Sriastradh 				status = connector_status_connected;
734cb459498Sriastradh 		}
735cb459498Sriastradh 	}
736cb459498Sriastradh 
737cb459498Sriastradh out:
738cb459498Sriastradh #if defined(CONFIG_ACPI_BUTTON) || \
739cb459498Sriastradh 	(defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
740cb459498Sriastradh 	if (status == connector_status_connected &&
741cb459498Sriastradh 	    !nouveau_ignorelid && !acpi_lid_open())
742cb459498Sriastradh 		status = connector_status_unknown;
743cb459498Sriastradh #endif
744cb459498Sriastradh 
745677dec6eSriastradh 	drm_connector_update_edid_property(connector, nv_connector->edid);
746cb459498Sriastradh 	nouveau_connector_set_encoder(connector, nv_encoder);
747cb459498Sriastradh 	return status;
748cb459498Sriastradh }
749cb459498Sriastradh 
750cb459498Sriastradh static void
nouveau_connector_force(struct drm_connector * connector)751cb459498Sriastradh nouveau_connector_force(struct drm_connector *connector)
752cb459498Sriastradh {
753cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
754cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
755cb459498Sriastradh 	struct nouveau_encoder *nv_encoder;
756cb459498Sriastradh 	int type;
757cb459498Sriastradh 
758cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
759cb459498Sriastradh 		if (connector->force == DRM_FORCE_ON_DIGITAL)
760cb459498Sriastradh 			type = DCB_OUTPUT_TMDS;
761cb459498Sriastradh 		else
762cb459498Sriastradh 			type = DCB_OUTPUT_ANALOG;
763cb459498Sriastradh 	} else
764cb459498Sriastradh 		type = DCB_OUTPUT_ANY;
765cb459498Sriastradh 
766cb459498Sriastradh 	nv_encoder = find_encoder(connector, type);
767cb459498Sriastradh 	if (!nv_encoder) {
768cb459498Sriastradh 		NV_ERROR(drm, "can't find encoder to force %s on!\n",
7694e59feabSriastradh 			 connector->name);
770cb459498Sriastradh 		connector->status = connector_status_disconnected;
771cb459498Sriastradh 		return;
772cb459498Sriastradh 	}
773cb459498Sriastradh 
774cb459498Sriastradh 	nouveau_connector_set_encoder(connector, nv_encoder);
775cb459498Sriastradh }
776cb459498Sriastradh 
777cb459498Sriastradh static int
nouveau_connector_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t value)778cb459498Sriastradh nouveau_connector_set_property(struct drm_connector *connector,
779cb459498Sriastradh 			       struct drm_property *property, uint64_t value)
780cb459498Sriastradh {
781cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
782cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
783677dec6eSriastradh 	struct nouveau_conn_atom *asyc = &nv_connector->properties_state;
784cb459498Sriastradh 	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
785cb459498Sriastradh 	int ret;
786cb459498Sriastradh 
787677dec6eSriastradh 	ret = connector->funcs->atomic_set_property(&nv_connector->base,
788677dec6eSriastradh 						    &asyc->state,
789677dec6eSriastradh 						    property, value);
790677dec6eSriastradh 	if (ret) {
791cb459498Sriastradh 		if (nv_encoder && nv_encoder->dcb->type == DCB_OUTPUT_TV)
792cb459498Sriastradh 			return get_slave_funcs(encoder)->set_property(
793cb459498Sriastradh 				encoder, connector, property, value);
794677dec6eSriastradh 		return ret;
795677dec6eSriastradh 	}
796cb459498Sriastradh 
797677dec6eSriastradh 	nv_connector->scaling_mode = asyc->scaler.mode;
798677dec6eSriastradh 	nv_connector->dithering_mode = asyc->dither.mode;
799677dec6eSriastradh 
800677dec6eSriastradh 	if (connector->encoder && connector->encoder->crtc) {
801677dec6eSriastradh 		ret = drm_crtc_helper_set_mode(connector->encoder->crtc,
802677dec6eSriastradh 					      &connector->encoder->crtc->mode,
803677dec6eSriastradh 					       connector->encoder->crtc->x,
804677dec6eSriastradh 					       connector->encoder->crtc->y,
805677dec6eSriastradh 					       NULL);
806677dec6eSriastradh 		if (!ret)
807cb459498Sriastradh 			return -EINVAL;
808cb459498Sriastradh 	}
809cb459498Sriastradh 
810677dec6eSriastradh 	return 0;
811cb459498Sriastradh }
812cb459498Sriastradh 
813cb459498Sriastradh struct moderec {
814cb459498Sriastradh 	int hdisplay;
815cb459498Sriastradh 	int vdisplay;
816cb459498Sriastradh };
817cb459498Sriastradh 
818cb459498Sriastradh static struct moderec scaler_modes[] = {
819cb459498Sriastradh 	{ 1920, 1200 },
820cb459498Sriastradh 	{ 1920, 1080 },
821cb459498Sriastradh 	{ 1680, 1050 },
822cb459498Sriastradh 	{ 1600, 1200 },
823cb459498Sriastradh 	{ 1400, 1050 },
824cb459498Sriastradh 	{ 1280, 1024 },
825cb459498Sriastradh 	{ 1280, 960 },
826cb459498Sriastradh 	{ 1152, 864 },
827cb459498Sriastradh 	{ 1024, 768 },
828cb459498Sriastradh 	{ 800, 600 },
829cb459498Sriastradh 	{ 720, 400 },
830cb459498Sriastradh 	{ 640, 480 },
831cb459498Sriastradh 	{ 640, 400 },
832cb459498Sriastradh 	{ 640, 350 },
833cb459498Sriastradh 	{}
834cb459498Sriastradh };
835cb459498Sriastradh 
836cb459498Sriastradh static int
nouveau_connector_scaler_modes_add(struct drm_connector * connector)837cb459498Sriastradh nouveau_connector_scaler_modes_add(struct drm_connector *connector)
838cb459498Sriastradh {
839cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
840cb459498Sriastradh 	struct drm_display_mode *native = nv_connector->native_mode, *m;
841cb459498Sriastradh 	struct drm_device *dev = connector->dev;
842cb459498Sriastradh 	struct moderec *mode = &scaler_modes[0];
843cb459498Sriastradh 	int modes = 0;
844cb459498Sriastradh 
845cb459498Sriastradh 	if (!native)
846cb459498Sriastradh 		return 0;
847cb459498Sriastradh 
848cb459498Sriastradh 	while (mode->hdisplay) {
849cb459498Sriastradh 		if (mode->hdisplay <= native->hdisplay &&
8504e59feabSriastradh 		    mode->vdisplay <= native->vdisplay &&
8514e59feabSriastradh 		    (mode->hdisplay != native->hdisplay ||
8524e59feabSriastradh 		     mode->vdisplay != native->vdisplay)) {
853cb459498Sriastradh 			m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay,
854cb459498Sriastradh 					 drm_mode_vrefresh(native), false,
855cb459498Sriastradh 					 false, false);
856cb459498Sriastradh 			if (!m)
857cb459498Sriastradh 				continue;
858cb459498Sriastradh 
859cb459498Sriastradh 			drm_mode_probed_add(connector, m);
860cb459498Sriastradh 			modes++;
861cb459498Sriastradh 		}
862cb459498Sriastradh 
863cb459498Sriastradh 		mode++;
864cb459498Sriastradh 	}
865cb459498Sriastradh 
866cb459498Sriastradh 	return modes;
867cb459498Sriastradh }
868cb459498Sriastradh 
869cb459498Sriastradh static void
nouveau_connector_detect_depth(struct drm_connector * connector)870cb459498Sriastradh nouveau_connector_detect_depth(struct drm_connector *connector)
871cb459498Sriastradh {
872cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
873cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
874cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
875cb459498Sriastradh 	struct nvbios *bios = &drm->vbios;
876cb459498Sriastradh 	struct drm_display_mode *mode = nv_connector->native_mode;
877cb459498Sriastradh 	bool duallink;
878cb459498Sriastradh 
879cb459498Sriastradh 	/* if the edid is feeling nice enough to provide this info, use it */
880cb459498Sriastradh 	if (nv_connector->edid && connector->display_info.bpc)
881cb459498Sriastradh 		return;
882cb459498Sriastradh 
883cb459498Sriastradh 	/* EDID 1.4 is *supposed* to be supported on eDP, but, Apple... */
884cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_eDP) {
885cb459498Sriastradh 		connector->display_info.bpc = 6;
886cb459498Sriastradh 		return;
887cb459498Sriastradh 	}
888cb459498Sriastradh 
889cb459498Sriastradh 	/* we're out of options unless we're LVDS, default to 8bpc */
890cb459498Sriastradh 	if (nv_encoder->dcb->type != DCB_OUTPUT_LVDS) {
891cb459498Sriastradh 		connector->display_info.bpc = 8;
892cb459498Sriastradh 		return;
893cb459498Sriastradh 	}
894cb459498Sriastradh 
895cb459498Sriastradh 	connector->display_info.bpc = 6;
896cb459498Sriastradh 
897cb459498Sriastradh 	/* LVDS: panel straps */
898cb459498Sriastradh 	if (bios->fp_no_ddc) {
899cb459498Sriastradh 		if (bios->fp.if_is_24bit)
900cb459498Sriastradh 			connector->display_info.bpc = 8;
901cb459498Sriastradh 		return;
902cb459498Sriastradh 	}
903cb459498Sriastradh 
904cb459498Sriastradh 	/* LVDS: DDC panel, need to first determine the number of links to
905cb459498Sriastradh 	 * know which if_is_24bit flag to check...
906cb459498Sriastradh 	 */
907cb459498Sriastradh 	if (nv_connector->edid &&
908cb459498Sriastradh 	    nv_connector->type == DCB_CONNECTOR_LVDS_SPWG)
909cb459498Sriastradh 		duallink = ((u8 *)nv_connector->edid)[121] == 2;
910cb459498Sriastradh 	else
911cb459498Sriastradh 		duallink = mode->clock >= bios->fp.duallink_transition_clk;
912cb459498Sriastradh 
913cb459498Sriastradh 	if ((!duallink && (bios->fp.strapless_is_24bit & 1)) ||
914cb459498Sriastradh 	    ( duallink && (bios->fp.strapless_is_24bit & 2)))
915cb459498Sriastradh 		connector->display_info.bpc = 8;
916cb459498Sriastradh }
917cb459498Sriastradh 
918cb459498Sriastradh static int
nouveau_connector_late_register(struct drm_connector * connector)919677dec6eSriastradh nouveau_connector_late_register(struct drm_connector *connector)
920677dec6eSriastradh {
921677dec6eSriastradh 	int ret;
922677dec6eSriastradh 
923677dec6eSriastradh 	ret = nouveau_backlight_init(connector);
924677dec6eSriastradh 
925677dec6eSriastradh 	return ret;
926677dec6eSriastradh }
927677dec6eSriastradh 
928677dec6eSriastradh static void
nouveau_connector_early_unregister(struct drm_connector * connector)929677dec6eSriastradh nouveau_connector_early_unregister(struct drm_connector *connector)
930677dec6eSriastradh {
931677dec6eSriastradh 	nouveau_backlight_fini(connector);
932677dec6eSriastradh }
933677dec6eSriastradh 
934677dec6eSriastradh static int
nouveau_connector_get_modes(struct drm_connector * connector)935cb459498Sriastradh nouveau_connector_get_modes(struct drm_connector *connector)
936cb459498Sriastradh {
937cb459498Sriastradh 	struct drm_device *dev = connector->dev;
938cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
939cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
940cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
941cb459498Sriastradh 	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
942cb459498Sriastradh 	int ret = 0;
943cb459498Sriastradh 
944cb459498Sriastradh 	/* destroy the native mode, the attached monitor could have changed.
945cb459498Sriastradh 	 */
946cb459498Sriastradh 	if (nv_connector->native_mode) {
947cb459498Sriastradh 		drm_mode_destroy(dev, nv_connector->native_mode);
948cb459498Sriastradh 		nv_connector->native_mode = NULL;
949cb459498Sriastradh 	}
950cb459498Sriastradh 
951cb459498Sriastradh 	if (nv_connector->edid)
952cb459498Sriastradh 		ret = drm_add_edid_modes(connector, nv_connector->edid);
953cb459498Sriastradh 	else
954cb459498Sriastradh 	if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS &&
955cb459498Sriastradh 	    (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
956cb459498Sriastradh 	     drm->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
957cb459498Sriastradh 		struct drm_display_mode mode;
958cb459498Sriastradh 
959cb459498Sriastradh 		nouveau_bios_fp_mode(dev, &mode);
960cb459498Sriastradh 		nv_connector->native_mode = drm_mode_duplicate(dev, &mode);
961cb459498Sriastradh 	}
962cb459498Sriastradh 
963cb459498Sriastradh 	/* Determine display colour depth for everything except LVDS now,
964cb459498Sriastradh 	 * DP requires this before mode_valid() is called.
965cb459498Sriastradh 	 */
966cb459498Sriastradh 	if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
967cb459498Sriastradh 		nouveau_connector_detect_depth(connector);
968cb459498Sriastradh 
969cb459498Sriastradh 	/* Find the native mode if this is a digital panel, if we didn't
970cb459498Sriastradh 	 * find any modes through DDC previously add the native mode to
971cb459498Sriastradh 	 * the list of modes.
972cb459498Sriastradh 	 */
973cb459498Sriastradh 	if (!nv_connector->native_mode)
974677dec6eSriastradh 		nv_connector->native_mode = nouveau_conn_native_mode(connector);
975cb459498Sriastradh 	if (ret == 0 && nv_connector->native_mode) {
976cb459498Sriastradh 		struct drm_display_mode *mode;
977cb459498Sriastradh 
978cb459498Sriastradh 		mode = drm_mode_duplicate(dev, nv_connector->native_mode);
979cb459498Sriastradh 		drm_mode_probed_add(connector, mode);
980cb459498Sriastradh 		ret = 1;
981cb459498Sriastradh 	}
982cb459498Sriastradh 
983cb459498Sriastradh 	/* Determine LVDS colour depth, must happen after determining
984cb459498Sriastradh 	 * "native" mode as some VBIOS tables require us to use the
985cb459498Sriastradh 	 * pixel clock as part of the lookup...
986cb459498Sriastradh 	 */
987cb459498Sriastradh 	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
988cb459498Sriastradh 		nouveau_connector_detect_depth(connector);
989cb459498Sriastradh 
990cb459498Sriastradh 	if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
991cb459498Sriastradh 		ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
992cb459498Sriastradh 
993cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_LVDS ||
994cb459498Sriastradh 	    nv_connector->type == DCB_CONNECTOR_LVDS_SPWG ||
995cb459498Sriastradh 	    nv_connector->type == DCB_CONNECTOR_eDP)
996cb459498Sriastradh 		ret += nouveau_connector_scaler_modes_add(connector);
997cb459498Sriastradh 
998cb459498Sriastradh 	return ret;
999cb459498Sriastradh }
1000cb459498Sriastradh 
1001cb459498Sriastradh static unsigned
get_tmds_link_bandwidth(struct drm_connector * connector)1002cb459498Sriastradh get_tmds_link_bandwidth(struct drm_connector *connector)
1003cb459498Sriastradh {
1004cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
1005677dec6eSriastradh 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
1006cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
1007cb459498Sriastradh 	struct dcb_output *dcb = nv_connector->detected_encoder->dcb;
1008677dec6eSriastradh 	struct drm_display_info *info = NULL;
1009677dec6eSriastradh 	unsigned duallink_scale =
1010677dec6eSriastradh 		nouveau_duallink && nv_encoder->dcb->duallink_possible ? 2 : 1;
1011cb459498Sriastradh 
1012677dec6eSriastradh 	if (drm_detect_hdmi_monitor(nv_connector->edid)) {
1013677dec6eSriastradh 		info = &nv_connector->base.display_info;
1014677dec6eSriastradh 		duallink_scale = 1;
1015cb459498Sriastradh 	}
1016cb459498Sriastradh 
1017677dec6eSriastradh 	if (info) {
1018677dec6eSriastradh 		if (nouveau_hdmimhz > 0)
1019677dec6eSriastradh 			return nouveau_hdmimhz * 1000;
1020677dec6eSriastradh 		/* Note: these limits are conservative, some Fermi's
1021677dec6eSriastradh 		 * can do 297 MHz. Unclear how this can be determined.
1022677dec6eSriastradh 		 */
1023677dec6eSriastradh 		if (drm->client.device.info.chipset >= 0x120) {
1024677dec6eSriastradh 			const int max_tmds_clock =
1025677dec6eSriastradh 				info->hdmi.scdc.scrambling.supported ?
1026677dec6eSriastradh 				594000 : 340000;
1027677dec6eSriastradh 			return info->max_tmds_clock ?
1028677dec6eSriastradh 				min(info->max_tmds_clock, max_tmds_clock) :
1029677dec6eSriastradh 				max_tmds_clock;
1030677dec6eSriastradh 		}
1031677dec6eSriastradh 		if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_KEPLER)
1032677dec6eSriastradh 			return 297000;
1033677dec6eSriastradh 		if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_FERMI)
1034677dec6eSriastradh 			return 225000;
1035677dec6eSriastradh 	}
1036677dec6eSriastradh 
1037677dec6eSriastradh 	if (dcb->location != DCB_LOC_ON_CHIP ||
1038677dec6eSriastradh 	    drm->client.device.info.chipset >= 0x46)
1039677dec6eSriastradh 		return 165000 * duallink_scale;
1040677dec6eSriastradh 	else if (drm->client.device.info.chipset >= 0x40)
1041677dec6eSriastradh 		return 155000 * duallink_scale;
1042677dec6eSriastradh 	else if (drm->client.device.info.chipset >= 0x18)
1043677dec6eSriastradh 		return 135000 * duallink_scale;
1044677dec6eSriastradh 	else
1045677dec6eSriastradh 		return 112000 * duallink_scale;
1046677dec6eSriastradh }
1047677dec6eSriastradh 
1048677dec6eSriastradh static enum drm_mode_status
nouveau_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1049cb459498Sriastradh nouveau_connector_mode_valid(struct drm_connector *connector,
1050cb459498Sriastradh 			     struct drm_display_mode *mode)
1051cb459498Sriastradh {
1052cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
1053cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
1054cb459498Sriastradh 	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
1055cb459498Sriastradh 	unsigned min_clock = 25000, max_clock = min_clock;
1056cb459498Sriastradh 	unsigned clock = mode->clock;
1057cb459498Sriastradh 
1058cb459498Sriastradh 	switch (nv_encoder->dcb->type) {
1059cb459498Sriastradh 	case DCB_OUTPUT_LVDS:
1060cb459498Sriastradh 		if (nv_connector->native_mode &&
1061cb459498Sriastradh 		    (mode->hdisplay > nv_connector->native_mode->hdisplay ||
1062cb459498Sriastradh 		     mode->vdisplay > nv_connector->native_mode->vdisplay))
1063cb459498Sriastradh 			return MODE_PANEL;
1064cb459498Sriastradh 
1065cb459498Sriastradh 		min_clock = 0;
1066cb459498Sriastradh 		max_clock = 400000;
1067cb459498Sriastradh 		break;
1068cb459498Sriastradh 	case DCB_OUTPUT_TMDS:
1069cb459498Sriastradh 		max_clock = get_tmds_link_bandwidth(connector);
1070cb459498Sriastradh 		break;
1071cb459498Sriastradh 	case DCB_OUTPUT_ANALOG:
1072cb459498Sriastradh 		max_clock = nv_encoder->dcb->crtconf.maxfreq;
1073cb459498Sriastradh 		if (!max_clock)
1074cb459498Sriastradh 			max_clock = 350000;
1075cb459498Sriastradh 		break;
1076cb459498Sriastradh 	case DCB_OUTPUT_TV:
1077cb459498Sriastradh 		return get_slave_funcs(encoder)->mode_valid(encoder, mode);
1078cb459498Sriastradh 	case DCB_OUTPUT_DP:
1079cb459498Sriastradh 		max_clock  = nv_encoder->dp.link_nr;
1080cb459498Sriastradh 		max_clock *= nv_encoder->dp.link_bw;
1081cb459498Sriastradh 		clock = clock * (connector->display_info.bpc * 3) / 10;
1082cb459498Sriastradh 		break;
1083cb459498Sriastradh 	default:
1084677dec6eSriastradh 		BUG();
1085cb459498Sriastradh 		return MODE_BAD;
1086cb459498Sriastradh 	}
1087cb459498Sriastradh 
1088677dec6eSriastradh 	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
1089677dec6eSriastradh 		clock *= 2;
1090677dec6eSriastradh 
1091cb459498Sriastradh 	if (clock < min_clock)
1092cb459498Sriastradh 		return MODE_CLOCK_LOW;
1093cb459498Sriastradh 
1094cb459498Sriastradh 	if (clock > max_clock)
1095cb459498Sriastradh 		return MODE_CLOCK_HIGH;
1096cb459498Sriastradh 
1097cb459498Sriastradh 	return MODE_OK;
1098cb459498Sriastradh }
1099cb459498Sriastradh 
1100cb459498Sriastradh static struct drm_encoder *
nouveau_connector_best_encoder(struct drm_connector * connector)1101cb459498Sriastradh nouveau_connector_best_encoder(struct drm_connector *connector)
1102cb459498Sriastradh {
1103cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
1104cb459498Sriastradh 
1105cb459498Sriastradh 	if (nv_connector->detected_encoder)
1106cb459498Sriastradh 		return to_drm_encoder(nv_connector->detected_encoder);
1107cb459498Sriastradh 
1108cb459498Sriastradh 	return NULL;
1109cb459498Sriastradh }
1110cb459498Sriastradh 
1111cb459498Sriastradh static const struct drm_connector_helper_funcs
1112cb459498Sriastradh nouveau_connector_helper_funcs = {
1113cb459498Sriastradh 	.get_modes = nouveau_connector_get_modes,
1114cb459498Sriastradh 	.mode_valid = nouveau_connector_mode_valid,
1115cb459498Sriastradh 	.best_encoder = nouveau_connector_best_encoder,
1116cb459498Sriastradh };
1117cb459498Sriastradh 
1118cb459498Sriastradh static const struct drm_connector_funcs
1119cb459498Sriastradh nouveau_connector_funcs = {
1120cb459498Sriastradh 	.dpms = drm_helper_connector_dpms,
1121677dec6eSriastradh 	.reset = nouveau_conn_reset,
1122cb459498Sriastradh 	.detect = nouveau_connector_detect,
1123677dec6eSriastradh 	.force = nouveau_connector_force,
1124cb459498Sriastradh 	.fill_modes = drm_helper_probe_single_connector_modes,
1125cb459498Sriastradh 	.set_property = nouveau_connector_set_property,
1126677dec6eSriastradh 	.destroy = nouveau_connector_destroy,
1127677dec6eSriastradh 	.atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
1128677dec6eSriastradh 	.atomic_destroy_state = nouveau_conn_atomic_destroy_state,
1129677dec6eSriastradh 	.atomic_set_property = nouveau_conn_atomic_set_property,
1130677dec6eSriastradh 	.atomic_get_property = nouveau_conn_atomic_get_property,
1131677dec6eSriastradh 	.late_register = nouveau_connector_late_register,
1132677dec6eSriastradh 	.early_unregister = nouveau_connector_early_unregister,
1133cb459498Sriastradh };
1134cb459498Sriastradh 
1135cb459498Sriastradh static const struct drm_connector_funcs
1136cb459498Sriastradh nouveau_connector_funcs_lvds = {
1137cb459498Sriastradh 	.dpms = drm_helper_connector_dpms,
1138677dec6eSriastradh 	.reset = nouveau_conn_reset,
1139cb459498Sriastradh 	.detect = nouveau_connector_detect_lvds,
1140677dec6eSriastradh 	.force = nouveau_connector_force,
1141cb459498Sriastradh 	.fill_modes = drm_helper_probe_single_connector_modes,
1142cb459498Sriastradh 	.set_property = nouveau_connector_set_property,
11434e59feabSriastradh 	.destroy = nouveau_connector_destroy,
1144677dec6eSriastradh 	.atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
1145677dec6eSriastradh 	.atomic_destroy_state = nouveau_conn_atomic_destroy_state,
1146677dec6eSriastradh 	.atomic_set_property = nouveau_conn_atomic_set_property,
1147677dec6eSriastradh 	.atomic_get_property = nouveau_conn_atomic_get_property,
1148677dec6eSriastradh 	.late_register = nouveau_connector_late_register,
1149677dec6eSriastradh 	.early_unregister = nouveau_connector_early_unregister,
11504e59feabSriastradh };
11514e59feabSriastradh 
11524e59feabSriastradh static int
nouveau_connector_hotplug(struct nvif_notify * notify)11534e59feabSriastradh nouveau_connector_hotplug(struct nvif_notify *notify)
1154cb459498Sriastradh {
1155cb459498Sriastradh 	struct nouveau_connector *nv_connector =
11564e59feabSriastradh 		container_of(notify, typeof(*nv_connector), hpd);
1157cb459498Sriastradh 	struct drm_connector *connector = &nv_connector->base;
11584e59feabSriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
11594e59feabSriastradh 	const struct nvif_notify_conn_rep_v0 *rep = notify->data;
11604e59feabSriastradh 	const char *name = connector->name;
1161677dec6eSriastradh 	struct nouveau_encoder *nv_encoder;
1162677dec6eSriastradh 	int ret;
11634e59feabSriastradh 	bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
1164cb459498Sriastradh 
1165677dec6eSriastradh 	if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
1166677dec6eSriastradh 		NV_DEBUG(drm, "service %s\n", name);
1167677dec6eSriastradh 		drm_dp_cec_irq(&nv_connector->aux);
1168677dec6eSriastradh 		if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP)))
1169677dec6eSriastradh 			nv50_mstm_service(nv_encoder->dp.mstm);
11704e59feabSriastradh 
1171677dec6eSriastradh 		return NVIF_NOTIFY_KEEP;
1172cb459498Sriastradh 	}
1173cb459498Sriastradh 
1174677dec6eSriastradh 	ret = pm_runtime_get(drm->dev->dev);
1175677dec6eSriastradh 	if (ret == 0) {
1176677dec6eSriastradh 		/* We can't block here if there's a pending PM request
1177677dec6eSriastradh 		 * running, as we'll deadlock nouveau_display_fini() when it
1178677dec6eSriastradh 		 * calls nvif_put() on our nvif_notify struct. So, simply
1179677dec6eSriastradh 		 * defer the hotplug event until the device finishes resuming
1180677dec6eSriastradh 		 */
1181677dec6eSriastradh 		NV_DEBUG(drm, "Deferring HPD on %s until runtime resume\n",
1182677dec6eSriastradh 			 name);
1183677dec6eSriastradh 		schedule_work(&drm->hpd_work);
1184677dec6eSriastradh 
1185677dec6eSriastradh 		pm_runtime_put_noidle(drm->dev->dev);
1186677dec6eSriastradh 		return NVIF_NOTIFY_KEEP;
1187677dec6eSriastradh 	} else if (ret != 1 && ret != -EACCES) {
1188677dec6eSriastradh 		NV_WARN(drm, "HPD on %s dropped due to RPM failure: %d\n",
1189677dec6eSriastradh 			name, ret);
1190677dec6eSriastradh 		return NVIF_NOTIFY_DROP;
1191677dec6eSriastradh 	}
1192677dec6eSriastradh 
1193677dec6eSriastradh 	if (!plugged)
1194677dec6eSriastradh 		drm_dp_cec_unset_edid(&nv_connector->aux);
1195677dec6eSriastradh 	NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
1196677dec6eSriastradh 	if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP))) {
1197677dec6eSriastradh 		if (!plugged)
1198677dec6eSriastradh 			nv50_mstm_remove(nv_encoder->dp.mstm);
1199677dec6eSriastradh 	}
1200677dec6eSriastradh 
1201677dec6eSriastradh 	drm_helper_hpd_irq_event(connector->dev);
1202677dec6eSriastradh 
1203677dec6eSriastradh 	pm_runtime_mark_last_busy(drm->dev->dev);
1204677dec6eSriastradh 	pm_runtime_put_autosuspend(drm->dev->dev);
12054e59feabSriastradh 	return NVIF_NOTIFY_KEEP;
12064e59feabSriastradh }
12074e59feabSriastradh 
12084e59feabSriastradh static ssize_t
nouveau_connector_aux_xfer(struct drm_dp_aux * obj,struct drm_dp_aux_msg * msg)12094e59feabSriastradh nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg)
1210cb459498Sriastradh {
12114e59feabSriastradh 	struct nouveau_connector *nv_connector =
12124e59feabSriastradh 		container_of(obj, typeof(*nv_connector), aux);
12134e59feabSriastradh 	struct nouveau_encoder *nv_encoder;
12144e59feabSriastradh 	struct nvkm_i2c_aux *aux;
1215677dec6eSriastradh 	u8 size = msg->size;
12164e59feabSriastradh 	int ret;
12174e59feabSriastradh 
12184e59feabSriastradh 	nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
12194e59feabSriastradh 	if (!nv_encoder || !(aux = nv_encoder->aux))
12204e59feabSriastradh 		return -ENODEV;
12214e59feabSriastradh 	if (WARN_ON(msg->size > 16))
12224e59feabSriastradh 		return -E2BIG;
12234e59feabSriastradh 
12244e59feabSriastradh 	ret = nvkm_i2c_aux_acquire(aux);
12254e59feabSriastradh 	if (ret)
12264e59feabSriastradh 		return ret;
12274e59feabSriastradh 
12284e59feabSriastradh 	ret = nvkm_i2c_aux_xfer(aux, false, msg->request, msg->address,
1229677dec6eSriastradh 				msg->buffer, &size);
12304e59feabSriastradh 	nvkm_i2c_aux_release(aux);
12314e59feabSriastradh 	if (ret >= 0) {
12324e59feabSriastradh 		msg->reply = ret;
1233677dec6eSriastradh 		return size;
12344e59feabSriastradh 	}
12354e59feabSriastradh 
12364e59feabSriastradh 	return ret;
1237cb459498Sriastradh }
1238cb459498Sriastradh 
1239cb459498Sriastradh static int
drm_conntype_from_dcb(enum dcb_connector_type dcb)1240cb459498Sriastradh drm_conntype_from_dcb(enum dcb_connector_type dcb)
1241cb459498Sriastradh {
1242cb459498Sriastradh 	switch (dcb) {
1243cb459498Sriastradh 	case DCB_CONNECTOR_VGA      : return DRM_MODE_CONNECTOR_VGA;
1244cb459498Sriastradh 	case DCB_CONNECTOR_TV_0     :
1245cb459498Sriastradh 	case DCB_CONNECTOR_TV_1     :
1246cb459498Sriastradh 	case DCB_CONNECTOR_TV_3     : return DRM_MODE_CONNECTOR_TV;
1247cb459498Sriastradh 	case DCB_CONNECTOR_DMS59_0  :
1248cb459498Sriastradh 	case DCB_CONNECTOR_DMS59_1  :
1249cb459498Sriastradh 	case DCB_CONNECTOR_DVI_I    : return DRM_MODE_CONNECTOR_DVII;
1250cb459498Sriastradh 	case DCB_CONNECTOR_DVI_D    : return DRM_MODE_CONNECTOR_DVID;
1251cb459498Sriastradh 	case DCB_CONNECTOR_LVDS     :
1252cb459498Sriastradh 	case DCB_CONNECTOR_LVDS_SPWG: return DRM_MODE_CONNECTOR_LVDS;
1253cb459498Sriastradh 	case DCB_CONNECTOR_DMS59_DP0:
1254cb459498Sriastradh 	case DCB_CONNECTOR_DMS59_DP1:
1255677dec6eSriastradh 	case DCB_CONNECTOR_DP       :
1256677dec6eSriastradh 	case DCB_CONNECTOR_USB_C    : return DRM_MODE_CONNECTOR_DisplayPort;
1257cb459498Sriastradh 	case DCB_CONNECTOR_eDP      : return DRM_MODE_CONNECTOR_eDP;
1258cb459498Sriastradh 	case DCB_CONNECTOR_HDMI_0   :
1259cb459498Sriastradh 	case DCB_CONNECTOR_HDMI_1   :
1260cb459498Sriastradh 	case DCB_CONNECTOR_HDMI_C   : return DRM_MODE_CONNECTOR_HDMIA;
1261677dec6eSriastradh 	case DCB_CONNECTOR_WFD	    : return DRM_MODE_CONNECTOR_VIRTUAL;
1262cb459498Sriastradh 	default:
1263cb459498Sriastradh 		break;
1264cb459498Sriastradh 	}
1265cb459498Sriastradh 
1266cb459498Sriastradh 	return DRM_MODE_CONNECTOR_Unknown;
1267cb459498Sriastradh }
1268cb459498Sriastradh 
1269cb459498Sriastradh struct drm_connector *
nouveau_connector_create(struct drm_device * dev,const struct dcb_output * dcbe)1270677dec6eSriastradh nouveau_connector_create(struct drm_device *dev,
1271677dec6eSriastradh 			 const struct dcb_output *dcbe)
1272cb459498Sriastradh {
1273cb459498Sriastradh 	const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
1274cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
1275cb459498Sriastradh 	struct nouveau_display *disp = nouveau_display(dev);
1276cb459498Sriastradh 	struct nouveau_connector *nv_connector = NULL;
1277cb459498Sriastradh 	struct drm_connector *connector;
1278677dec6eSriastradh 	struct drm_connector_list_iter conn_iter;
1279677dec6eSriastradh 	char aux_name[48] = {0};
1280677dec6eSriastradh 	int index = dcbe->connector;
1281cb459498Sriastradh 	int type, ret = 0;
1282cb459498Sriastradh 	bool dummy;
1283cb459498Sriastradh 
1284677dec6eSriastradh 	drm_connector_list_iter_begin(dev, &conn_iter);
1285677dec6eSriastradh 	nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
1286cb459498Sriastradh 		nv_connector = nouveau_connector(connector);
1287677dec6eSriastradh 		if (nv_connector->index == index) {
1288677dec6eSriastradh 			drm_connector_list_iter_end(&conn_iter);
1289cb459498Sriastradh 			return connector;
1290cb459498Sriastradh 		}
1291677dec6eSriastradh 	}
1292677dec6eSriastradh 	drm_connector_list_iter_end(&conn_iter);
1293cb459498Sriastradh 
1294cb459498Sriastradh 	nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
1295cb459498Sriastradh 	if (!nv_connector)
1296cb459498Sriastradh 		return ERR_PTR(-ENOMEM);
1297cb459498Sriastradh 
1298cb459498Sriastradh 	connector = &nv_connector->base;
1299cb459498Sriastradh 	nv_connector->index = index;
1300cb459498Sriastradh 
1301cb459498Sriastradh 	/* attempt to parse vbios connector type and hotplug gpio */
1302cb459498Sriastradh 	nv_connector->dcb = olddcb_conn(dev, index);
1303cb459498Sriastradh 	if (nv_connector->dcb) {
1304cb459498Sriastradh 		u32 entry = ROM16(nv_connector->dcb[0]);
1305cb459498Sriastradh 		if (olddcb_conntab(dev)[3] >= 4)
1306cb459498Sriastradh 			entry |= (u32)ROM16(nv_connector->dcb[2]) << 16;
1307cb459498Sriastradh 
1308cb459498Sriastradh 		nv_connector->type = nv_connector->dcb[0];
1309cb459498Sriastradh 		if (drm_conntype_from_dcb(nv_connector->type) ==
1310cb459498Sriastradh 					  DRM_MODE_CONNECTOR_Unknown) {
1311cb459498Sriastradh 			NV_WARN(drm, "unknown connector type %02x\n",
1312cb459498Sriastradh 				nv_connector->type);
1313cb459498Sriastradh 			nv_connector->type = DCB_CONNECTOR_NONE;
1314cb459498Sriastradh 		}
1315cb459498Sriastradh 
1316cb459498Sriastradh 		/* Gigabyte NX85T */
1317cb459498Sriastradh 		if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) {
1318cb459498Sriastradh 			if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
1319cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DVI_I;
1320cb459498Sriastradh 		}
1321cb459498Sriastradh 
1322cb459498Sriastradh 		/* Gigabyte GV-NX86T512H */
1323cb459498Sriastradh 		if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) {
1324cb459498Sriastradh 			if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
1325cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DVI_I;
1326cb459498Sriastradh 		}
1327cb459498Sriastradh 	} else {
1328cb459498Sriastradh 		nv_connector->type = DCB_CONNECTOR_NONE;
1329cb459498Sriastradh 	}
1330cb459498Sriastradh 
1331cb459498Sriastradh 	/* no vbios data, or an unknown dcb connector type - attempt to
1332cb459498Sriastradh 	 * figure out something suitable ourselves
1333cb459498Sriastradh 	 */
1334cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_NONE) {
1335cb459498Sriastradh 		struct dcb_table *dcbt = &drm->vbios.dcb;
1336cb459498Sriastradh 		u32 encoders = 0;
1337cb459498Sriastradh 		int i;
1338cb459498Sriastradh 
1339cb459498Sriastradh 		for (i = 0; i < dcbt->entries; i++) {
1340cb459498Sriastradh 			if (dcbt->entry[i].connector == nv_connector->index)
1341cb459498Sriastradh 				encoders |= (1 << dcbt->entry[i].type);
1342cb459498Sriastradh 		}
1343cb459498Sriastradh 
1344cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_DP)) {
1345cb459498Sriastradh 			if (encoders & (1 << DCB_OUTPUT_TMDS))
1346cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DP;
1347cb459498Sriastradh 			else
1348cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_eDP;
1349cb459498Sriastradh 		} else
1350cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_TMDS)) {
1351cb459498Sriastradh 			if (encoders & (1 << DCB_OUTPUT_ANALOG))
1352cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DVI_I;
1353cb459498Sriastradh 			else
1354cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DVI_D;
1355cb459498Sriastradh 		} else
1356cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_ANALOG)) {
1357cb459498Sriastradh 			nv_connector->type = DCB_CONNECTOR_VGA;
1358cb459498Sriastradh 		} else
1359cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_LVDS)) {
1360cb459498Sriastradh 			nv_connector->type = DCB_CONNECTOR_LVDS;
1361cb459498Sriastradh 		} else
1362cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_TV)) {
1363cb459498Sriastradh 			nv_connector->type = DCB_CONNECTOR_TV_0;
1364cb459498Sriastradh 		}
1365cb459498Sriastradh 	}
1366cb459498Sriastradh 
13674e59feabSriastradh 	switch ((type = drm_conntype_from_dcb(nv_connector->type))) {
13684e59feabSriastradh 	case DRM_MODE_CONNECTOR_LVDS:
1369cb459498Sriastradh 		ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy);
1370cb459498Sriastradh 		if (ret) {
1371cb459498Sriastradh 			NV_ERROR(drm, "Error parsing LVDS table, disabling\n");
1372cb459498Sriastradh 			kfree(nv_connector);
1373cb459498Sriastradh 			return ERR_PTR(ret);
1374cb459498Sriastradh 		}
1375cb459498Sriastradh 
1376cb459498Sriastradh 		funcs = &nouveau_connector_funcs_lvds;
13774e59feabSriastradh 		break;
13784e59feabSriastradh 	case DRM_MODE_CONNECTOR_DisplayPort:
13794e59feabSriastradh 	case DRM_MODE_CONNECTOR_eDP:
1380677dec6eSriastradh 		nv_connector->aux.dev = connector->kdev;
13814e59feabSriastradh 		nv_connector->aux.transfer = nouveau_connector_aux_xfer;
1382677dec6eSriastradh 		snprintf(aux_name, sizeof(aux_name), "sor-%04x-%04x",
1383677dec6eSriastradh 			 dcbe->hasht, dcbe->hashm);
1384677dec6eSriastradh 		nv_connector->aux.name = kstrdup(aux_name, GFP_KERNEL);
13854e59feabSriastradh 		ret = drm_dp_aux_register(&nv_connector->aux);
13864e59feabSriastradh 		if (ret) {
13874e59feabSriastradh 			NV_ERROR(drm, "failed to register aux channel\n");
13884e59feabSriastradh 			kfree(nv_connector);
13894e59feabSriastradh 			return ERR_PTR(ret);
13904e59feabSriastradh 		}
1391677dec6eSriastradh 		funcs = &nouveau_connector_funcs;
13924e59feabSriastradh 		break;
13934e59feabSriastradh 	default:
1394cb459498Sriastradh 		funcs = &nouveau_connector_funcs;
13954e59feabSriastradh 		break;
1396cb459498Sriastradh 	}
1397cb459498Sriastradh 
1398677dec6eSriastradh 	/* HDMI 3D support */
1399677dec6eSriastradh 	if ((disp->disp.object.oclass >= G82_DISP)
1400677dec6eSriastradh 	    && ((type == DRM_MODE_CONNECTOR_DisplayPort)
1401677dec6eSriastradh 		|| (type == DRM_MODE_CONNECTOR_eDP)
1402677dec6eSriastradh 		|| (type == DRM_MODE_CONNECTOR_HDMIA)))
1403677dec6eSriastradh 		connector->stereo_allowed = true;
1404677dec6eSriastradh 
1405cb459498Sriastradh 	/* defaults, will get overridden in detect() */
1406cb459498Sriastradh 	connector->interlace_allowed = false;
1407cb459498Sriastradh 	connector->doublescan_allowed = false;
1408cb459498Sriastradh 
1409cb459498Sriastradh 	drm_connector_init(dev, connector, funcs, type);
1410cb459498Sriastradh 	drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
1411cb459498Sriastradh 
1412677dec6eSriastradh 	connector->funcs->reset(connector);
1413677dec6eSriastradh 	nouveau_conn_attach_properties(connector);
1414cb459498Sriastradh 
1415677dec6eSriastradh 	/* Default scaling mode */
1416cb459498Sriastradh 	switch (nv_connector->type) {
14174e59feabSriastradh 	case DCB_CONNECTOR_LVDS:
14184e59feabSriastradh 	case DCB_CONNECTOR_LVDS_SPWG:
14194e59feabSriastradh 	case DCB_CONNECTOR_eDP:
14204e59feabSriastradh 		/* see note in nouveau_connector_set_property() */
1421677dec6eSriastradh 		if (disp->disp.object.oclass < NV50_DISP) {
14224e59feabSriastradh 			nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
14234e59feabSriastradh 			break;
1424cb459498Sriastradh 		}
1425cb459498Sriastradh 		nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
1426cb459498Sriastradh 		break;
1427cb459498Sriastradh 	default:
14284e59feabSriastradh 		nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
14294e59feabSriastradh 		break;
14304e59feabSriastradh 	}
1431cb459498Sriastradh 
14324e59feabSriastradh 	/* dithering properties */
14334e59feabSriastradh 	switch (nv_connector->type) {
14344e59feabSriastradh 	case DCB_CONNECTOR_TV_0:
14354e59feabSriastradh 	case DCB_CONNECTOR_TV_1:
14364e59feabSriastradh 	case DCB_CONNECTOR_TV_3:
14374e59feabSriastradh 	case DCB_CONNECTOR_VGA:
14384e59feabSriastradh 		break;
14394e59feabSriastradh 	default:
14404e59feabSriastradh 		nv_connector->dithering_mode = DITHERING_MODE_AUTO;
1441cb459498Sriastradh 		break;
1442cb459498Sriastradh 	}
1443cb459498Sriastradh 
1444677dec6eSriastradh 	switch (type) {
1445677dec6eSriastradh 	case DRM_MODE_CONNECTOR_DisplayPort:
1446677dec6eSriastradh 	case DRM_MODE_CONNECTOR_eDP:
1447677dec6eSriastradh 		drm_dp_cec_register_connector(&nv_connector->aux, connector);
1448677dec6eSriastradh 		break;
1449677dec6eSriastradh 	}
1450677dec6eSriastradh 
1451677dec6eSriastradh 	ret = nvif_notify_init(&disp->disp.object, nouveau_connector_hotplug,
1452677dec6eSriastradh 			       true, NV04_DISP_NTFY_CONN,
14534e59feabSriastradh 			       &(struct nvif_notify_conn_req_v0) {
14544e59feabSriastradh 				.mask = NVIF_NOTIFY_CONN_V0_ANY,
14554e59feabSriastradh 				.conn = index,
14564e59feabSriastradh 			       },
14574e59feabSriastradh 			       sizeof(struct nvif_notify_conn_req_v0),
14584e59feabSriastradh 			       sizeof(struct nvif_notify_conn_rep_v0),
14594e59feabSriastradh 			       &nv_connector->hpd);
14604e59feabSriastradh 	if (ret)
1461cb459498Sriastradh 		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
14624e59feabSriastradh 	else
1463cb459498Sriastradh 		connector->polled = DRM_CONNECTOR_POLL_HPD;
1464cb459498Sriastradh 
14654e59feabSriastradh 	drm_connector_register(connector);
1466cb459498Sriastradh 	return connector;
1467cb459498Sriastradh }
1468