1*04fcfa4fSriastradh /*	$NetBSD: nouveau_connector.c,v 1.2 2014/08/06 15:01:33 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*04fcfa4fSriastradh __KERNEL_RCSID(0, "$NetBSD: nouveau_connector.c,v 1.2 2014/08/06 15:01:33 riastradh Exp $");
319d5db0c2Sriastradh 
32cb459498Sriastradh #include <acpi/button.h>
33cb459498Sriastradh 
34*04fcfa4fSriastradh #include <linux/err.h>
35cb459498Sriastradh #include <linux/pm_runtime.h>
36*04fcfa4fSriastradh #include <linux/string.h>
37cb459498Sriastradh 
38cb459498Sriastradh #include <drm/drmP.h>
39cb459498Sriastradh #include <drm/drm_edid.h>
40cb459498Sriastradh #include <drm/drm_crtc_helper.h>
41cb459498Sriastradh 
42cb459498Sriastradh #include "nouveau_reg.h"
43cb459498Sriastradh #include "nouveau_drm.h"
44cb459498Sriastradh #include "dispnv04/hw.h"
45cb459498Sriastradh #include "nouveau_acpi.h"
46cb459498Sriastradh 
47cb459498Sriastradh #include "nouveau_display.h"
48cb459498Sriastradh #include "nouveau_connector.h"
49cb459498Sriastradh #include "nouveau_encoder.h"
50cb459498Sriastradh #include "nouveau_crtc.h"
51cb459498Sriastradh 
52cb459498Sriastradh #include <subdev/i2c.h>
53cb459498Sriastradh #include <subdev/gpio.h>
54cb459498Sriastradh 
55cb459498Sriastradh MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
56cb459498Sriastradh static int nouveau_tv_disable = 0;
57cb459498Sriastradh module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
58cb459498Sriastradh 
59*04fcfa4fSriastradh #if defined(CONFIG_ACPI_BUTTON) || \
60*04fcfa4fSriastradh 	(defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
61cb459498Sriastradh MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
62cb459498Sriastradh static int nouveau_ignorelid = 0;
63cb459498Sriastradh module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
64*04fcfa4fSriastradh #endif
65cb459498Sriastradh 
66cb459498Sriastradh MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)");
67cb459498Sriastradh static int nouveau_duallink = 1;
68cb459498Sriastradh module_param_named(duallink, nouveau_duallink, int, 0400);
69cb459498Sriastradh 
70cb459498Sriastradh struct nouveau_encoder *
71cb459498Sriastradh find_encoder(struct drm_connector *connector, int type)
72cb459498Sriastradh {
73cb459498Sriastradh 	struct drm_device *dev = connector->dev;
74cb459498Sriastradh 	struct nouveau_encoder *nv_encoder;
75cb459498Sriastradh 	struct drm_mode_object *obj;
76cb459498Sriastradh 	int i, id;
77cb459498Sriastradh 
78cb459498Sriastradh 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
79cb459498Sriastradh 		id = connector->encoder_ids[i];
80cb459498Sriastradh 		if (!id)
81cb459498Sriastradh 			break;
82cb459498Sriastradh 
83cb459498Sriastradh 		obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
84cb459498Sriastradh 		if (!obj)
85cb459498Sriastradh 			continue;
86cb459498Sriastradh 		nv_encoder = nouveau_encoder(obj_to_encoder(obj));
87cb459498Sriastradh 
88cb459498Sriastradh 		if (type == DCB_OUTPUT_ANY || nv_encoder->dcb->type == type)
89cb459498Sriastradh 			return nv_encoder;
90cb459498Sriastradh 	}
91cb459498Sriastradh 
92cb459498Sriastradh 	return NULL;
93cb459498Sriastradh }
94cb459498Sriastradh 
95cb459498Sriastradh struct nouveau_connector *
96cb459498Sriastradh nouveau_encoder_connector_get(struct nouveau_encoder *encoder)
97cb459498Sriastradh {
98cb459498Sriastradh 	struct drm_device *dev = to_drm_encoder(encoder)->dev;
99cb459498Sriastradh 	struct drm_connector *drm_connector;
100cb459498Sriastradh 
101cb459498Sriastradh 	list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
102cb459498Sriastradh 		if (drm_connector->encoder == to_drm_encoder(encoder))
103cb459498Sriastradh 			return nouveau_connector(drm_connector);
104cb459498Sriastradh 	}
105cb459498Sriastradh 
106cb459498Sriastradh 	return NULL;
107cb459498Sriastradh }
108cb459498Sriastradh 
109cb459498Sriastradh static void
110cb459498Sriastradh nouveau_connector_destroy(struct drm_connector *connector)
111cb459498Sriastradh {
112cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
113cb459498Sriastradh 	nouveau_event_ref(NULL, &nv_connector->hpd_func);
114cb459498Sriastradh 	kfree(nv_connector->edid);
115cb459498Sriastradh 	drm_sysfs_connector_remove(connector);
116cb459498Sriastradh 	drm_connector_cleanup(connector);
117cb459498Sriastradh 	kfree(connector);
118cb459498Sriastradh }
119cb459498Sriastradh 
120cb459498Sriastradh static struct nouveau_i2c_port *
121cb459498Sriastradh nouveau_connector_ddc_detect(struct drm_connector *connector,
122cb459498Sriastradh 			     struct nouveau_encoder **pnv_encoder)
123cb459498Sriastradh {
124cb459498Sriastradh 	struct drm_device *dev = connector->dev;
125cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
126cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
127cb459498Sriastradh 	struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
128cb459498Sriastradh 	struct nouveau_i2c_port *port = NULL;
129cb459498Sriastradh 	int i, panel = -ENODEV;
130cb459498Sriastradh 
131cb459498Sriastradh 	/* eDP panels need powering on by us (if the VBIOS doesn't default it
132cb459498Sriastradh 	 * to on) before doing any AUX channel transactions.  LVDS panel power
133cb459498Sriastradh 	 * is handled by the SOR itself, and not required for LVDS DDC.
134cb459498Sriastradh 	 */
135cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_eDP) {
136cb459498Sriastradh 		panel = gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
137cb459498Sriastradh 		if (panel == 0) {
138cb459498Sriastradh 			gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
139cb459498Sriastradh 			msleep(300);
140cb459498Sriastradh 		}
141cb459498Sriastradh 	}
142cb459498Sriastradh 
143cb459498Sriastradh 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
144cb459498Sriastradh 		struct nouveau_encoder *nv_encoder;
145cb459498Sriastradh 		struct drm_mode_object *obj;
146cb459498Sriastradh 		int id;
147cb459498Sriastradh 
148cb459498Sriastradh 		id = connector->encoder_ids[i];
149cb459498Sriastradh 		if (!id)
150cb459498Sriastradh 			break;
151cb459498Sriastradh 
152cb459498Sriastradh 		obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
153cb459498Sriastradh 		if (!obj)
154cb459498Sriastradh 			continue;
155cb459498Sriastradh 		nv_encoder = nouveau_encoder(obj_to_encoder(obj));
156cb459498Sriastradh 
157cb459498Sriastradh 		port = nv_encoder->i2c;
158cb459498Sriastradh 		if (port && nv_probe_i2c(port, 0x50)) {
159cb459498Sriastradh 			*pnv_encoder = nv_encoder;
160cb459498Sriastradh 			break;
161cb459498Sriastradh 		}
162cb459498Sriastradh 
163cb459498Sriastradh 		port = NULL;
164cb459498Sriastradh 	}
165cb459498Sriastradh 
166cb459498Sriastradh 	/* eDP panel not detected, restore panel power GPIO to previous
167cb459498Sriastradh 	 * state to avoid confusing the SOR for other output types.
168cb459498Sriastradh 	 */
169cb459498Sriastradh 	if (!port && panel == 0)
170cb459498Sriastradh 		gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel);
171cb459498Sriastradh 
172cb459498Sriastradh 	return port;
173cb459498Sriastradh }
174cb459498Sriastradh 
175cb459498Sriastradh static struct nouveau_encoder *
176cb459498Sriastradh nouveau_connector_of_detect(struct drm_connector *connector)
177cb459498Sriastradh {
178cb459498Sriastradh #ifdef __powerpc__
179cb459498Sriastradh 	struct drm_device *dev = connector->dev;
180cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
181cb459498Sriastradh 	struct nouveau_encoder *nv_encoder;
182cb459498Sriastradh 	struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
183cb459498Sriastradh 
184cb459498Sriastradh 	if (!dn ||
185cb459498Sriastradh 	    !((nv_encoder = find_encoder(connector, DCB_OUTPUT_TMDS)) ||
186cb459498Sriastradh 	      (nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG))))
187cb459498Sriastradh 		return NULL;
188cb459498Sriastradh 
189cb459498Sriastradh 	for_each_child_of_node(dn, cn) {
190cb459498Sriastradh 		const char *name = of_get_property(cn, "name", NULL);
191cb459498Sriastradh 		const void *edid = of_get_property(cn, "EDID", NULL);
192cb459498Sriastradh 		int idx = name ? name[strlen(name) - 1] - 'A' : 0;
193cb459498Sriastradh 
194cb459498Sriastradh 		if (nv_encoder->dcb->i2c_index == idx && edid) {
195cb459498Sriastradh 			nv_connector->edid =
196cb459498Sriastradh 				kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
197cb459498Sriastradh 			of_node_put(cn);
198cb459498Sriastradh 			return nv_encoder;
199cb459498Sriastradh 		}
200cb459498Sriastradh 	}
201cb459498Sriastradh #endif
202cb459498Sriastradh 	return NULL;
203cb459498Sriastradh }
204cb459498Sriastradh 
205cb459498Sriastradh static void
206cb459498Sriastradh nouveau_connector_set_encoder(struct drm_connector *connector,
207cb459498Sriastradh 			      struct nouveau_encoder *nv_encoder)
208cb459498Sriastradh {
209cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
210cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
211cb459498Sriastradh 	struct drm_device *dev = connector->dev;
212cb459498Sriastradh 
213cb459498Sriastradh 	if (nv_connector->detected_encoder == nv_encoder)
214cb459498Sriastradh 		return;
215cb459498Sriastradh 	nv_connector->detected_encoder = nv_encoder;
216cb459498Sriastradh 
217cb459498Sriastradh 	if (nv_device(drm->device)->card_type >= NV_50) {
218cb459498Sriastradh 		connector->interlace_allowed = true;
219cb459498Sriastradh 		connector->doublescan_allowed = true;
220cb459498Sriastradh 	} else
221cb459498Sriastradh 	if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS ||
222cb459498Sriastradh 	    nv_encoder->dcb->type == DCB_OUTPUT_TMDS) {
223cb459498Sriastradh 		connector->doublescan_allowed = false;
224cb459498Sriastradh 		connector->interlace_allowed = false;
225cb459498Sriastradh 	} else {
226cb459498Sriastradh 		connector->doublescan_allowed = true;
227cb459498Sriastradh 		if (nv_device(drm->device)->card_type == NV_20 ||
228cb459498Sriastradh 		    ((nv_device(drm->device)->card_type == NV_10 ||
229cb459498Sriastradh 		      nv_device(drm->device)->card_type == NV_11) &&
230cb459498Sriastradh 		     (dev->pdev->device & 0x0ff0) != 0x0100 &&
231cb459498Sriastradh 		     (dev->pdev->device & 0x0ff0) != 0x0150))
232cb459498Sriastradh 			/* HW is broken */
233cb459498Sriastradh 			connector->interlace_allowed = false;
234cb459498Sriastradh 		else
235cb459498Sriastradh 			connector->interlace_allowed = true;
236cb459498Sriastradh 	}
237cb459498Sriastradh 
238cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
239cb459498Sriastradh 		drm_object_property_set_value(&connector->base,
240cb459498Sriastradh 			dev->mode_config.dvi_i_subconnector_property,
241cb459498Sriastradh 			nv_encoder->dcb->type == DCB_OUTPUT_TMDS ?
242cb459498Sriastradh 			DRM_MODE_SUBCONNECTOR_DVID :
243cb459498Sriastradh 			DRM_MODE_SUBCONNECTOR_DVIA);
244cb459498Sriastradh 	}
245cb459498Sriastradh }
246cb459498Sriastradh 
247cb459498Sriastradh static enum drm_connector_status
248cb459498Sriastradh nouveau_connector_detect(struct drm_connector *connector, bool force)
249cb459498Sriastradh {
250cb459498Sriastradh 	struct drm_device *dev = connector->dev;
251cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
252cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
253cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = NULL;
254cb459498Sriastradh 	struct nouveau_encoder *nv_partner;
255cb459498Sriastradh 	struct nouveau_i2c_port *i2c;
256cb459498Sriastradh 	int type;
257cb459498Sriastradh 	int ret;
258cb459498Sriastradh 	enum drm_connector_status conn_status = connector_status_disconnected;
259cb459498Sriastradh 
260cb459498Sriastradh 	/* Cleanup the previous EDID block. */
261cb459498Sriastradh 	if (nv_connector->edid) {
262cb459498Sriastradh 		drm_mode_connector_update_edid_property(connector, NULL);
263cb459498Sriastradh 		kfree(nv_connector->edid);
264cb459498Sriastradh 		nv_connector->edid = NULL;
265cb459498Sriastradh 	}
266cb459498Sriastradh 
267cb459498Sriastradh 	ret = pm_runtime_get_sync(connector->dev->dev);
268cb459498Sriastradh 	if (ret < 0 && ret != -EACCES)
269cb459498Sriastradh 		return conn_status;
270cb459498Sriastradh 
271cb459498Sriastradh 	i2c = nouveau_connector_ddc_detect(connector, &nv_encoder);
272cb459498Sriastradh 	if (i2c) {
273cb459498Sriastradh 		nv_connector->edid = drm_get_edid(connector, &i2c->adapter);
274cb459498Sriastradh 		drm_mode_connector_update_edid_property(connector,
275cb459498Sriastradh 							nv_connector->edid);
276cb459498Sriastradh 		if (!nv_connector->edid) {
277cb459498Sriastradh 			NV_ERROR(drm, "DDC responded, but no EDID for %s\n",
278cb459498Sriastradh 				 drm_get_connector_name(connector));
279cb459498Sriastradh 			goto detect_analog;
280cb459498Sriastradh 		}
281cb459498Sriastradh 
282cb459498Sriastradh 		if (nv_encoder->dcb->type == DCB_OUTPUT_DP &&
283cb459498Sriastradh 		    !nouveau_dp_detect(to_drm_encoder(nv_encoder))) {
284cb459498Sriastradh 			NV_ERROR(drm, "Detected %s, but failed init\n",
285cb459498Sriastradh 				 drm_get_connector_name(connector));
286cb459498Sriastradh 			conn_status = connector_status_disconnected;
287cb459498Sriastradh 			goto out;
288cb459498Sriastradh 		}
289cb459498Sriastradh 
290cb459498Sriastradh 		/* Override encoder type for DVI-I based on whether EDID
291cb459498Sriastradh 		 * says the display is digital or analog, both use the
292cb459498Sriastradh 		 * same i2c channel so the value returned from ddc_detect
293cb459498Sriastradh 		 * isn't necessarily correct.
294cb459498Sriastradh 		 */
295cb459498Sriastradh 		nv_partner = NULL;
296cb459498Sriastradh 		if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS)
297cb459498Sriastradh 			nv_partner = find_encoder(connector, DCB_OUTPUT_ANALOG);
298cb459498Sriastradh 		if (nv_encoder->dcb->type == DCB_OUTPUT_ANALOG)
299cb459498Sriastradh 			nv_partner = find_encoder(connector, DCB_OUTPUT_TMDS);
300cb459498Sriastradh 
301cb459498Sriastradh 		if (nv_partner && ((nv_encoder->dcb->type == DCB_OUTPUT_ANALOG &&
302cb459498Sriastradh 				    nv_partner->dcb->type == DCB_OUTPUT_TMDS) ||
303cb459498Sriastradh 				   (nv_encoder->dcb->type == DCB_OUTPUT_TMDS &&
304cb459498Sriastradh 				    nv_partner->dcb->type == DCB_OUTPUT_ANALOG))) {
305cb459498Sriastradh 			if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
306cb459498Sriastradh 				type = DCB_OUTPUT_TMDS;
307cb459498Sriastradh 			else
308cb459498Sriastradh 				type = DCB_OUTPUT_ANALOG;
309cb459498Sriastradh 
310cb459498Sriastradh 			nv_encoder = find_encoder(connector, type);
311cb459498Sriastradh 		}
312cb459498Sriastradh 
313cb459498Sriastradh 		nouveau_connector_set_encoder(connector, nv_encoder);
314cb459498Sriastradh 		conn_status = connector_status_connected;
315cb459498Sriastradh 		goto out;
316cb459498Sriastradh 	}
317cb459498Sriastradh 
318cb459498Sriastradh 	nv_encoder = nouveau_connector_of_detect(connector);
319cb459498Sriastradh 	if (nv_encoder) {
320cb459498Sriastradh 		nouveau_connector_set_encoder(connector, nv_encoder);
321cb459498Sriastradh 		conn_status = connector_status_connected;
322cb459498Sriastradh 		goto out;
323cb459498Sriastradh 	}
324cb459498Sriastradh 
325cb459498Sriastradh detect_analog:
326cb459498Sriastradh 	nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG);
327cb459498Sriastradh 	if (!nv_encoder && !nouveau_tv_disable)
328cb459498Sriastradh 		nv_encoder = find_encoder(connector, DCB_OUTPUT_TV);
329cb459498Sriastradh 	if (nv_encoder && force) {
330cb459498Sriastradh 		struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
331cb459498Sriastradh 		struct drm_encoder_helper_funcs *helper =
332cb459498Sriastradh 						encoder->helper_private;
333cb459498Sriastradh 
334cb459498Sriastradh 		if (helper->detect(encoder, connector) ==
335cb459498Sriastradh 						connector_status_connected) {
336cb459498Sriastradh 			nouveau_connector_set_encoder(connector, nv_encoder);
337cb459498Sriastradh 			conn_status = connector_status_connected;
338cb459498Sriastradh 			goto out;
339cb459498Sriastradh 		}
340cb459498Sriastradh 
341cb459498Sriastradh 	}
342cb459498Sriastradh 
343cb459498Sriastradh  out:
344cb459498Sriastradh 
345cb459498Sriastradh 	pm_runtime_mark_last_busy(connector->dev->dev);
346cb459498Sriastradh 	pm_runtime_put_autosuspend(connector->dev->dev);
347cb459498Sriastradh 
348cb459498Sriastradh 	return conn_status;
349cb459498Sriastradh }
350cb459498Sriastradh 
351cb459498Sriastradh static enum drm_connector_status
352cb459498Sriastradh nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
353cb459498Sriastradh {
354cb459498Sriastradh 	struct drm_device *dev = connector->dev;
355cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
356cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
357cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = NULL;
358cb459498Sriastradh 	enum drm_connector_status status = connector_status_disconnected;
359cb459498Sriastradh 
360cb459498Sriastradh 	/* Cleanup the previous EDID block. */
361cb459498Sriastradh 	if (nv_connector->edid) {
362cb459498Sriastradh 		drm_mode_connector_update_edid_property(connector, NULL);
363cb459498Sriastradh 		kfree(nv_connector->edid);
364cb459498Sriastradh 		nv_connector->edid = NULL;
365cb459498Sriastradh 	}
366cb459498Sriastradh 
367cb459498Sriastradh 	nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
368cb459498Sriastradh 	if (!nv_encoder)
369cb459498Sriastradh 		return connector_status_disconnected;
370cb459498Sriastradh 
371cb459498Sriastradh 	/* Try retrieving EDID via DDC */
372cb459498Sriastradh 	if (!drm->vbios.fp_no_ddc) {
373cb459498Sriastradh 		status = nouveau_connector_detect(connector, force);
374cb459498Sriastradh 		if (status == connector_status_connected)
375cb459498Sriastradh 			goto out;
376cb459498Sriastradh 	}
377cb459498Sriastradh 
378cb459498Sriastradh 	/* On some laptops (Sony, i'm looking at you) there appears to
379cb459498Sriastradh 	 * be no direct way of accessing the panel's EDID.  The only
380cb459498Sriastradh 	 * option available to us appears to be to ask ACPI for help..
381cb459498Sriastradh 	 *
382cb459498Sriastradh 	 * It's important this check's before trying straps, one of the
383cb459498Sriastradh 	 * said manufacturer's laptops are configured in such a way
384cb459498Sriastradh 	 * the nouveau decides an entry in the VBIOS FP mode table is
385cb459498Sriastradh 	 * valid - it's not (rh#613284)
386cb459498Sriastradh 	 */
387cb459498Sriastradh 	if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
388cb459498Sriastradh 		if ((nv_connector->edid = nouveau_acpi_edid(dev, connector))) {
389cb459498Sriastradh 			status = connector_status_connected;
390cb459498Sriastradh 			goto out;
391cb459498Sriastradh 		}
392cb459498Sriastradh 	}
393cb459498Sriastradh 
394cb459498Sriastradh 	/* If no EDID found above, and the VBIOS indicates a hardcoded
395cb459498Sriastradh 	 * modeline is avalilable for the panel, set it as the panel's
396cb459498Sriastradh 	 * native mode and exit.
397cb459498Sriastradh 	 */
398cb459498Sriastradh 	if (nouveau_bios_fp_mode(dev, NULL) && (drm->vbios.fp_no_ddc ||
399cb459498Sriastradh 	    nv_encoder->dcb->lvdsconf.use_straps_for_mode)) {
400cb459498Sriastradh 		status = connector_status_connected;
401cb459498Sriastradh 		goto out;
402cb459498Sriastradh 	}
403cb459498Sriastradh 
404cb459498Sriastradh 	/* Still nothing, some VBIOS images have a hardcoded EDID block
405cb459498Sriastradh 	 * stored for the panel stored in them.
406cb459498Sriastradh 	 */
407cb459498Sriastradh 	if (!drm->vbios.fp_no_ddc) {
408cb459498Sriastradh 		struct edid *edid =
409cb459498Sriastradh 			(struct edid *)nouveau_bios_embedded_edid(dev);
410cb459498Sriastradh 		if (edid) {
411cb459498Sriastradh 			nv_connector->edid =
412cb459498Sriastradh 					kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
413cb459498Sriastradh 			if (nv_connector->edid)
414cb459498Sriastradh 				status = connector_status_connected;
415cb459498Sriastradh 		}
416cb459498Sriastradh 	}
417cb459498Sriastradh 
418cb459498Sriastradh out:
419cb459498Sriastradh #if defined(CONFIG_ACPI_BUTTON) || \
420cb459498Sriastradh 	(defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
421cb459498Sriastradh 	if (status == connector_status_connected &&
422cb459498Sriastradh 	    !nouveau_ignorelid && !acpi_lid_open())
423cb459498Sriastradh 		status = connector_status_unknown;
424cb459498Sriastradh #endif
425cb459498Sriastradh 
426cb459498Sriastradh 	drm_mode_connector_update_edid_property(connector, nv_connector->edid);
427cb459498Sriastradh 	nouveau_connector_set_encoder(connector, nv_encoder);
428cb459498Sriastradh 	return status;
429cb459498Sriastradh }
430cb459498Sriastradh 
431cb459498Sriastradh static void
432cb459498Sriastradh nouveau_connector_force(struct drm_connector *connector)
433cb459498Sriastradh {
434cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
435cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
436cb459498Sriastradh 	struct nouveau_encoder *nv_encoder;
437cb459498Sriastradh 	int type;
438cb459498Sriastradh 
439cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
440cb459498Sriastradh 		if (connector->force == DRM_FORCE_ON_DIGITAL)
441cb459498Sriastradh 			type = DCB_OUTPUT_TMDS;
442cb459498Sriastradh 		else
443cb459498Sriastradh 			type = DCB_OUTPUT_ANALOG;
444cb459498Sriastradh 	} else
445cb459498Sriastradh 		type = DCB_OUTPUT_ANY;
446cb459498Sriastradh 
447cb459498Sriastradh 	nv_encoder = find_encoder(connector, type);
448cb459498Sriastradh 	if (!nv_encoder) {
449cb459498Sriastradh 		NV_ERROR(drm, "can't find encoder to force %s on!\n",
450cb459498Sriastradh 			 drm_get_connector_name(connector));
451cb459498Sriastradh 		connector->status = connector_status_disconnected;
452cb459498Sriastradh 		return;
453cb459498Sriastradh 	}
454cb459498Sriastradh 
455cb459498Sriastradh 	nouveau_connector_set_encoder(connector, nv_encoder);
456cb459498Sriastradh }
457cb459498Sriastradh 
458cb459498Sriastradh static int
459cb459498Sriastradh nouveau_connector_set_property(struct drm_connector *connector,
460cb459498Sriastradh 			       struct drm_property *property, uint64_t value)
461cb459498Sriastradh {
462cb459498Sriastradh 	struct nouveau_display *disp = nouveau_display(connector->dev);
463cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
464cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
465cb459498Sriastradh 	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
466cb459498Sriastradh 	struct drm_device *dev = connector->dev;
467cb459498Sriastradh 	struct nouveau_crtc *nv_crtc;
468cb459498Sriastradh 	int ret;
469cb459498Sriastradh 
470cb459498Sriastradh 	nv_crtc = NULL;
471cb459498Sriastradh 	if (connector->encoder && connector->encoder->crtc)
472cb459498Sriastradh 		nv_crtc = nouveau_crtc(connector->encoder->crtc);
473cb459498Sriastradh 
474cb459498Sriastradh 	/* Scaling mode */
475cb459498Sriastradh 	if (property == dev->mode_config.scaling_mode_property) {
476cb459498Sriastradh 		bool modeset = false;
477cb459498Sriastradh 
478cb459498Sriastradh 		switch (value) {
479cb459498Sriastradh 		case DRM_MODE_SCALE_NONE:
480cb459498Sriastradh 		case DRM_MODE_SCALE_FULLSCREEN:
481cb459498Sriastradh 		case DRM_MODE_SCALE_CENTER:
482cb459498Sriastradh 		case DRM_MODE_SCALE_ASPECT:
483cb459498Sriastradh 			break;
484cb459498Sriastradh 		default:
485cb459498Sriastradh 			return -EINVAL;
486cb459498Sriastradh 		}
487cb459498Sriastradh 
488cb459498Sriastradh 		/* LVDS always needs gpu scaling */
489cb459498Sriastradh 		if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
490cb459498Sriastradh 		    value == DRM_MODE_SCALE_NONE)
491cb459498Sriastradh 			return -EINVAL;
492cb459498Sriastradh 
493cb459498Sriastradh 		/* Changing between GPU and panel scaling requires a full
494cb459498Sriastradh 		 * modeset
495cb459498Sriastradh 		 */
496cb459498Sriastradh 		if ((nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) ||
497cb459498Sriastradh 		    (value == DRM_MODE_SCALE_NONE))
498cb459498Sriastradh 			modeset = true;
499cb459498Sriastradh 		nv_connector->scaling_mode = value;
500cb459498Sriastradh 
501cb459498Sriastradh 		if (!nv_crtc)
502cb459498Sriastradh 			return 0;
503cb459498Sriastradh 
504cb459498Sriastradh 		if (modeset || !nv_crtc->set_scale) {
505cb459498Sriastradh 			ret = drm_crtc_helper_set_mode(&nv_crtc->base,
506cb459498Sriastradh 							&nv_crtc->base.mode,
507cb459498Sriastradh 							nv_crtc->base.x,
508cb459498Sriastradh 							nv_crtc->base.y, NULL);
509cb459498Sriastradh 			if (!ret)
510cb459498Sriastradh 				return -EINVAL;
511cb459498Sriastradh 		} else {
512cb459498Sriastradh 			ret = nv_crtc->set_scale(nv_crtc, true);
513cb459498Sriastradh 			if (ret)
514cb459498Sriastradh 				return ret;
515cb459498Sriastradh 		}
516cb459498Sriastradh 
517cb459498Sriastradh 		return 0;
518cb459498Sriastradh 	}
519cb459498Sriastradh 
520cb459498Sriastradh 	/* Underscan */
521cb459498Sriastradh 	if (property == disp->underscan_property) {
522cb459498Sriastradh 		if (nv_connector->underscan != value) {
523cb459498Sriastradh 			nv_connector->underscan = value;
524cb459498Sriastradh 			if (!nv_crtc || !nv_crtc->set_scale)
525cb459498Sriastradh 				return 0;
526cb459498Sriastradh 
527cb459498Sriastradh 			return nv_crtc->set_scale(nv_crtc, true);
528cb459498Sriastradh 		}
529cb459498Sriastradh 
530cb459498Sriastradh 		return 0;
531cb459498Sriastradh 	}
532cb459498Sriastradh 
533cb459498Sriastradh 	if (property == disp->underscan_hborder_property) {
534cb459498Sriastradh 		if (nv_connector->underscan_hborder != value) {
535cb459498Sriastradh 			nv_connector->underscan_hborder = value;
536cb459498Sriastradh 			if (!nv_crtc || !nv_crtc->set_scale)
537cb459498Sriastradh 				return 0;
538cb459498Sriastradh 
539cb459498Sriastradh 			return nv_crtc->set_scale(nv_crtc, true);
540cb459498Sriastradh 		}
541cb459498Sriastradh 
542cb459498Sriastradh 		return 0;
543cb459498Sriastradh 	}
544cb459498Sriastradh 
545cb459498Sriastradh 	if (property == disp->underscan_vborder_property) {
546cb459498Sriastradh 		if (nv_connector->underscan_vborder != value) {
547cb459498Sriastradh 			nv_connector->underscan_vborder = value;
548cb459498Sriastradh 			if (!nv_crtc || !nv_crtc->set_scale)
549cb459498Sriastradh 				return 0;
550cb459498Sriastradh 
551cb459498Sriastradh 			return nv_crtc->set_scale(nv_crtc, true);
552cb459498Sriastradh 		}
553cb459498Sriastradh 
554cb459498Sriastradh 		return 0;
555cb459498Sriastradh 	}
556cb459498Sriastradh 
557cb459498Sriastradh 	/* Dithering */
558cb459498Sriastradh 	if (property == disp->dithering_mode) {
559cb459498Sriastradh 		nv_connector->dithering_mode = value;
560cb459498Sriastradh 		if (!nv_crtc || !nv_crtc->set_dither)
561cb459498Sriastradh 			return 0;
562cb459498Sriastradh 
563cb459498Sriastradh 		return nv_crtc->set_dither(nv_crtc, true);
564cb459498Sriastradh 	}
565cb459498Sriastradh 
566cb459498Sriastradh 	if (property == disp->dithering_depth) {
567cb459498Sriastradh 		nv_connector->dithering_depth = value;
568cb459498Sriastradh 		if (!nv_crtc || !nv_crtc->set_dither)
569cb459498Sriastradh 			return 0;
570cb459498Sriastradh 
571cb459498Sriastradh 		return nv_crtc->set_dither(nv_crtc, true);
572cb459498Sriastradh 	}
573cb459498Sriastradh 
574cb459498Sriastradh 	if (nv_crtc && nv_crtc->set_color_vibrance) {
575cb459498Sriastradh 		/* Hue */
576cb459498Sriastradh 		if (property == disp->vibrant_hue_property) {
577cb459498Sriastradh 			nv_crtc->vibrant_hue = value - 90;
578cb459498Sriastradh 			return nv_crtc->set_color_vibrance(nv_crtc, true);
579cb459498Sriastradh 		}
580cb459498Sriastradh 		/* Saturation */
581cb459498Sriastradh 		if (property == disp->color_vibrance_property) {
582cb459498Sriastradh 			nv_crtc->color_vibrance = value - 100;
583cb459498Sriastradh 			return nv_crtc->set_color_vibrance(nv_crtc, true);
584cb459498Sriastradh 		}
585cb459498Sriastradh 	}
586cb459498Sriastradh 
587cb459498Sriastradh 	if (nv_encoder && nv_encoder->dcb->type == DCB_OUTPUT_TV)
588cb459498Sriastradh 		return get_slave_funcs(encoder)->set_property(
589cb459498Sriastradh 			encoder, connector, property, value);
590cb459498Sriastradh 
591cb459498Sriastradh 	return -EINVAL;
592cb459498Sriastradh }
593cb459498Sriastradh 
594cb459498Sriastradh static struct drm_display_mode *
595cb459498Sriastradh nouveau_connector_native_mode(struct drm_connector *connector)
596cb459498Sriastradh {
597cb459498Sriastradh 	struct drm_connector_helper_funcs *helper = connector->helper_private;
598cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
599cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
600cb459498Sriastradh 	struct drm_device *dev = connector->dev;
601cb459498Sriastradh 	struct drm_display_mode *mode, *largest = NULL;
602cb459498Sriastradh 	int high_w = 0, high_h = 0, high_v = 0;
603cb459498Sriastradh 
604cb459498Sriastradh 	list_for_each_entry(mode, &nv_connector->base.probed_modes, head) {
605cb459498Sriastradh 		mode->vrefresh = drm_mode_vrefresh(mode);
606cb459498Sriastradh 		if (helper->mode_valid(connector, mode) != MODE_OK ||
607cb459498Sriastradh 		    (mode->flags & DRM_MODE_FLAG_INTERLACE))
608cb459498Sriastradh 			continue;
609cb459498Sriastradh 
610cb459498Sriastradh 		/* Use preferred mode if there is one.. */
611cb459498Sriastradh 		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
612cb459498Sriastradh 			NV_DEBUG(drm, "native mode from preferred\n");
613cb459498Sriastradh 			return drm_mode_duplicate(dev, mode);
614cb459498Sriastradh 		}
615cb459498Sriastradh 
616cb459498Sriastradh 		/* Otherwise, take the resolution with the largest width, then
617cb459498Sriastradh 		 * height, then vertical refresh
618cb459498Sriastradh 		 */
619cb459498Sriastradh 		if (mode->hdisplay < high_w)
620cb459498Sriastradh 			continue;
621cb459498Sriastradh 
622cb459498Sriastradh 		if (mode->hdisplay == high_w && mode->vdisplay < high_h)
623cb459498Sriastradh 			continue;
624cb459498Sriastradh 
625cb459498Sriastradh 		if (mode->hdisplay == high_w && mode->vdisplay == high_h &&
626cb459498Sriastradh 		    mode->vrefresh < high_v)
627cb459498Sriastradh 			continue;
628cb459498Sriastradh 
629cb459498Sriastradh 		high_w = mode->hdisplay;
630cb459498Sriastradh 		high_h = mode->vdisplay;
631cb459498Sriastradh 		high_v = mode->vrefresh;
632cb459498Sriastradh 		largest = mode;
633cb459498Sriastradh 	}
634cb459498Sriastradh 
635cb459498Sriastradh 	NV_DEBUG(drm, "native mode from largest: %dx%d@%d\n",
636cb459498Sriastradh 		      high_w, high_h, high_v);
637cb459498Sriastradh 	return largest ? drm_mode_duplicate(dev, largest) : NULL;
638cb459498Sriastradh }
639cb459498Sriastradh 
640cb459498Sriastradh struct moderec {
641cb459498Sriastradh 	int hdisplay;
642cb459498Sriastradh 	int vdisplay;
643cb459498Sriastradh };
644cb459498Sriastradh 
645cb459498Sriastradh static struct moderec scaler_modes[] = {
646cb459498Sriastradh 	{ 1920, 1200 },
647cb459498Sriastradh 	{ 1920, 1080 },
648cb459498Sriastradh 	{ 1680, 1050 },
649cb459498Sriastradh 	{ 1600, 1200 },
650cb459498Sriastradh 	{ 1400, 1050 },
651cb459498Sriastradh 	{ 1280, 1024 },
652cb459498Sriastradh 	{ 1280, 960 },
653cb459498Sriastradh 	{ 1152, 864 },
654cb459498Sriastradh 	{ 1024, 768 },
655cb459498Sriastradh 	{ 800, 600 },
656cb459498Sriastradh 	{ 720, 400 },
657cb459498Sriastradh 	{ 640, 480 },
658cb459498Sriastradh 	{ 640, 400 },
659cb459498Sriastradh 	{ 640, 350 },
660cb459498Sriastradh 	{}
661cb459498Sriastradh };
662cb459498Sriastradh 
663cb459498Sriastradh static int
664cb459498Sriastradh nouveau_connector_scaler_modes_add(struct drm_connector *connector)
665cb459498Sriastradh {
666cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
667cb459498Sriastradh 	struct drm_display_mode *native = nv_connector->native_mode, *m;
668cb459498Sriastradh 	struct drm_device *dev = connector->dev;
669cb459498Sriastradh 	struct moderec *mode = &scaler_modes[0];
670cb459498Sriastradh 	int modes = 0;
671cb459498Sriastradh 
672cb459498Sriastradh 	if (!native)
673cb459498Sriastradh 		return 0;
674cb459498Sriastradh 
675cb459498Sriastradh 	while (mode->hdisplay) {
676cb459498Sriastradh 		if (mode->hdisplay <= native->hdisplay &&
677cb459498Sriastradh 		    mode->vdisplay <= native->vdisplay) {
678cb459498Sriastradh 			m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay,
679cb459498Sriastradh 					 drm_mode_vrefresh(native), false,
680cb459498Sriastradh 					 false, false);
681cb459498Sriastradh 			if (!m)
682cb459498Sriastradh 				continue;
683cb459498Sriastradh 
684cb459498Sriastradh 			m->type |= DRM_MODE_TYPE_DRIVER;
685cb459498Sriastradh 
686cb459498Sriastradh 			drm_mode_probed_add(connector, m);
687cb459498Sriastradh 			modes++;
688cb459498Sriastradh 		}
689cb459498Sriastradh 
690cb459498Sriastradh 		mode++;
691cb459498Sriastradh 	}
692cb459498Sriastradh 
693cb459498Sriastradh 	return modes;
694cb459498Sriastradh }
695cb459498Sriastradh 
696cb459498Sriastradh static void
697cb459498Sriastradh nouveau_connector_detect_depth(struct drm_connector *connector)
698cb459498Sriastradh {
699cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
700cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
701cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
702cb459498Sriastradh 	struct nvbios *bios = &drm->vbios;
703cb459498Sriastradh 	struct drm_display_mode *mode = nv_connector->native_mode;
704cb459498Sriastradh 	bool duallink;
705cb459498Sriastradh 
706cb459498Sriastradh 	/* if the edid is feeling nice enough to provide this info, use it */
707cb459498Sriastradh 	if (nv_connector->edid && connector->display_info.bpc)
708cb459498Sriastradh 		return;
709cb459498Sriastradh 
710cb459498Sriastradh 	/* EDID 1.4 is *supposed* to be supported on eDP, but, Apple... */
711cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_eDP) {
712cb459498Sriastradh 		connector->display_info.bpc = 6;
713cb459498Sriastradh 		return;
714cb459498Sriastradh 	}
715cb459498Sriastradh 
716cb459498Sriastradh 	/* we're out of options unless we're LVDS, default to 8bpc */
717cb459498Sriastradh 	if (nv_encoder->dcb->type != DCB_OUTPUT_LVDS) {
718cb459498Sriastradh 		connector->display_info.bpc = 8;
719cb459498Sriastradh 		return;
720cb459498Sriastradh 	}
721cb459498Sriastradh 
722cb459498Sriastradh 	connector->display_info.bpc = 6;
723cb459498Sriastradh 
724cb459498Sriastradh 	/* LVDS: panel straps */
725cb459498Sriastradh 	if (bios->fp_no_ddc) {
726cb459498Sriastradh 		if (bios->fp.if_is_24bit)
727cb459498Sriastradh 			connector->display_info.bpc = 8;
728cb459498Sriastradh 		return;
729cb459498Sriastradh 	}
730cb459498Sriastradh 
731cb459498Sriastradh 	/* LVDS: DDC panel, need to first determine the number of links to
732cb459498Sriastradh 	 * know which if_is_24bit flag to check...
733cb459498Sriastradh 	 */
734cb459498Sriastradh 	if (nv_connector->edid &&
735cb459498Sriastradh 	    nv_connector->type == DCB_CONNECTOR_LVDS_SPWG)
736cb459498Sriastradh 		duallink = ((u8 *)nv_connector->edid)[121] == 2;
737cb459498Sriastradh 	else
738cb459498Sriastradh 		duallink = mode->clock >= bios->fp.duallink_transition_clk;
739cb459498Sriastradh 
740cb459498Sriastradh 	if ((!duallink && (bios->fp.strapless_is_24bit & 1)) ||
741cb459498Sriastradh 	    ( duallink && (bios->fp.strapless_is_24bit & 2)))
742cb459498Sriastradh 		connector->display_info.bpc = 8;
743cb459498Sriastradh }
744cb459498Sriastradh 
745cb459498Sriastradh static int
746cb459498Sriastradh nouveau_connector_get_modes(struct drm_connector *connector)
747cb459498Sriastradh {
748cb459498Sriastradh 	struct drm_device *dev = connector->dev;
749cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
750cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
751cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
752cb459498Sriastradh 	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
753cb459498Sriastradh 	int ret = 0;
754cb459498Sriastradh 
755cb459498Sriastradh 	/* destroy the native mode, the attached monitor could have changed.
756cb459498Sriastradh 	 */
757cb459498Sriastradh 	if (nv_connector->native_mode) {
758cb459498Sriastradh 		drm_mode_destroy(dev, nv_connector->native_mode);
759cb459498Sriastradh 		nv_connector->native_mode = NULL;
760cb459498Sriastradh 	}
761cb459498Sriastradh 
762cb459498Sriastradh 	if (nv_connector->edid)
763cb459498Sriastradh 		ret = drm_add_edid_modes(connector, nv_connector->edid);
764cb459498Sriastradh 	else
765cb459498Sriastradh 	if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS &&
766cb459498Sriastradh 	    (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
767cb459498Sriastradh 	     drm->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
768cb459498Sriastradh 		struct drm_display_mode mode;
769cb459498Sriastradh 
770cb459498Sriastradh 		nouveau_bios_fp_mode(dev, &mode);
771cb459498Sriastradh 		nv_connector->native_mode = drm_mode_duplicate(dev, &mode);
772cb459498Sriastradh 	}
773cb459498Sriastradh 
774cb459498Sriastradh 	/* Determine display colour depth for everything except LVDS now,
775cb459498Sriastradh 	 * DP requires this before mode_valid() is called.
776cb459498Sriastradh 	 */
777cb459498Sriastradh 	if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
778cb459498Sriastradh 		nouveau_connector_detect_depth(connector);
779cb459498Sriastradh 
780cb459498Sriastradh 	/* Find the native mode if this is a digital panel, if we didn't
781cb459498Sriastradh 	 * find any modes through DDC previously add the native mode to
782cb459498Sriastradh 	 * the list of modes.
783cb459498Sriastradh 	 */
784cb459498Sriastradh 	if (!nv_connector->native_mode)
785cb459498Sriastradh 		nv_connector->native_mode =
786cb459498Sriastradh 			nouveau_connector_native_mode(connector);
787cb459498Sriastradh 	if (ret == 0 && nv_connector->native_mode) {
788cb459498Sriastradh 		struct drm_display_mode *mode;
789cb459498Sriastradh 
790cb459498Sriastradh 		mode = drm_mode_duplicate(dev, nv_connector->native_mode);
791cb459498Sriastradh 		drm_mode_probed_add(connector, mode);
792cb459498Sriastradh 		ret = 1;
793cb459498Sriastradh 	}
794cb459498Sriastradh 
795cb459498Sriastradh 	/* Determine LVDS colour depth, must happen after determining
796cb459498Sriastradh 	 * "native" mode as some VBIOS tables require us to use the
797cb459498Sriastradh 	 * pixel clock as part of the lookup...
798cb459498Sriastradh 	 */
799cb459498Sriastradh 	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
800cb459498Sriastradh 		nouveau_connector_detect_depth(connector);
801cb459498Sriastradh 
802cb459498Sriastradh 	if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
803cb459498Sriastradh 		ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
804cb459498Sriastradh 
805cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_LVDS ||
806cb459498Sriastradh 	    nv_connector->type == DCB_CONNECTOR_LVDS_SPWG ||
807cb459498Sriastradh 	    nv_connector->type == DCB_CONNECTOR_eDP)
808cb459498Sriastradh 		ret += nouveau_connector_scaler_modes_add(connector);
809cb459498Sriastradh 
810cb459498Sriastradh 	return ret;
811cb459498Sriastradh }
812cb459498Sriastradh 
813cb459498Sriastradh static unsigned
814cb459498Sriastradh get_tmds_link_bandwidth(struct drm_connector *connector)
815cb459498Sriastradh {
816cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
817cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
818cb459498Sriastradh 	struct dcb_output *dcb = nv_connector->detected_encoder->dcb;
819cb459498Sriastradh 
820cb459498Sriastradh 	if (dcb->location != DCB_LOC_ON_CHIP ||
821cb459498Sriastradh 	    nv_device(drm->device)->chipset >= 0x46)
822cb459498Sriastradh 		return 165000;
823cb459498Sriastradh 	else if (nv_device(drm->device)->chipset >= 0x40)
824cb459498Sriastradh 		return 155000;
825cb459498Sriastradh 	else if (nv_device(drm->device)->chipset >= 0x18)
826cb459498Sriastradh 		return 135000;
827cb459498Sriastradh 	else
828cb459498Sriastradh 		return 112000;
829cb459498Sriastradh }
830cb459498Sriastradh 
831cb459498Sriastradh static int
832cb459498Sriastradh nouveau_connector_mode_valid(struct drm_connector *connector,
833cb459498Sriastradh 			     struct drm_display_mode *mode)
834cb459498Sriastradh {
835cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
836cb459498Sriastradh 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
837cb459498Sriastradh 	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
838cb459498Sriastradh 	unsigned min_clock = 25000, max_clock = min_clock;
839cb459498Sriastradh 	unsigned clock = mode->clock;
840cb459498Sriastradh 
841cb459498Sriastradh 	switch (nv_encoder->dcb->type) {
842cb459498Sriastradh 	case DCB_OUTPUT_LVDS:
843cb459498Sriastradh 		if (nv_connector->native_mode &&
844cb459498Sriastradh 		    (mode->hdisplay > nv_connector->native_mode->hdisplay ||
845cb459498Sriastradh 		     mode->vdisplay > nv_connector->native_mode->vdisplay))
846cb459498Sriastradh 			return MODE_PANEL;
847cb459498Sriastradh 
848cb459498Sriastradh 		min_clock = 0;
849cb459498Sriastradh 		max_clock = 400000;
850cb459498Sriastradh 		break;
851cb459498Sriastradh 	case DCB_OUTPUT_TMDS:
852cb459498Sriastradh 		max_clock = get_tmds_link_bandwidth(connector);
853cb459498Sriastradh 		if (nouveau_duallink && nv_encoder->dcb->duallink_possible)
854cb459498Sriastradh 			max_clock *= 2;
855cb459498Sriastradh 		break;
856cb459498Sriastradh 	case DCB_OUTPUT_ANALOG:
857cb459498Sriastradh 		max_clock = nv_encoder->dcb->crtconf.maxfreq;
858cb459498Sriastradh 		if (!max_clock)
859cb459498Sriastradh 			max_clock = 350000;
860cb459498Sriastradh 		break;
861cb459498Sriastradh 	case DCB_OUTPUT_TV:
862cb459498Sriastradh 		return get_slave_funcs(encoder)->mode_valid(encoder, mode);
863cb459498Sriastradh 	case DCB_OUTPUT_DP:
864cb459498Sriastradh 		max_clock  = nv_encoder->dp.link_nr;
865cb459498Sriastradh 		max_clock *= nv_encoder->dp.link_bw;
866cb459498Sriastradh 		clock = clock * (connector->display_info.bpc * 3) / 10;
867cb459498Sriastradh 		break;
868cb459498Sriastradh 	default:
869cb459498Sriastradh 		BUG_ON(1);
870cb459498Sriastradh 		return MODE_BAD;
871cb459498Sriastradh 	}
872cb459498Sriastradh 
873cb459498Sriastradh 	if (clock < min_clock)
874cb459498Sriastradh 		return MODE_CLOCK_LOW;
875cb459498Sriastradh 
876cb459498Sriastradh 	if (clock > max_clock)
877cb459498Sriastradh 		return MODE_CLOCK_HIGH;
878cb459498Sriastradh 
879cb459498Sriastradh 	return MODE_OK;
880cb459498Sriastradh }
881cb459498Sriastradh 
882cb459498Sriastradh static struct drm_encoder *
883cb459498Sriastradh nouveau_connector_best_encoder(struct drm_connector *connector)
884cb459498Sriastradh {
885cb459498Sriastradh 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
886cb459498Sriastradh 
887cb459498Sriastradh 	if (nv_connector->detected_encoder)
888cb459498Sriastradh 		return to_drm_encoder(nv_connector->detected_encoder);
889cb459498Sriastradh 
890cb459498Sriastradh 	return NULL;
891cb459498Sriastradh }
892cb459498Sriastradh 
893cb459498Sriastradh static const struct drm_connector_helper_funcs
894cb459498Sriastradh nouveau_connector_helper_funcs = {
895cb459498Sriastradh 	.get_modes = nouveau_connector_get_modes,
896cb459498Sriastradh 	.mode_valid = nouveau_connector_mode_valid,
897cb459498Sriastradh 	.best_encoder = nouveau_connector_best_encoder,
898cb459498Sriastradh };
899cb459498Sriastradh 
900cb459498Sriastradh static const struct drm_connector_funcs
901cb459498Sriastradh nouveau_connector_funcs = {
902cb459498Sriastradh 	.dpms = drm_helper_connector_dpms,
903cb459498Sriastradh 	.save = NULL,
904cb459498Sriastradh 	.restore = NULL,
905cb459498Sriastradh 	.detect = nouveau_connector_detect,
906cb459498Sriastradh 	.destroy = nouveau_connector_destroy,
907cb459498Sriastradh 	.fill_modes = drm_helper_probe_single_connector_modes,
908cb459498Sriastradh 	.set_property = nouveau_connector_set_property,
909cb459498Sriastradh 	.force = nouveau_connector_force
910cb459498Sriastradh };
911cb459498Sriastradh 
912cb459498Sriastradh static const struct drm_connector_funcs
913cb459498Sriastradh nouveau_connector_funcs_lvds = {
914cb459498Sriastradh 	.dpms = drm_helper_connector_dpms,
915cb459498Sriastradh 	.save = NULL,
916cb459498Sriastradh 	.restore = NULL,
917cb459498Sriastradh 	.detect = nouveau_connector_detect_lvds,
918cb459498Sriastradh 	.destroy = nouveau_connector_destroy,
919cb459498Sriastradh 	.fill_modes = drm_helper_probe_single_connector_modes,
920cb459498Sriastradh 	.set_property = nouveau_connector_set_property,
921cb459498Sriastradh 	.force = nouveau_connector_force
922cb459498Sriastradh };
923cb459498Sriastradh 
924cb459498Sriastradh static void
925cb459498Sriastradh nouveau_connector_hotplug_work(struct work_struct *work)
926cb459498Sriastradh {
927cb459498Sriastradh 	struct nouveau_connector *nv_connector =
928cb459498Sriastradh 		container_of(work, struct nouveau_connector, hpd_work);
929cb459498Sriastradh 	struct drm_connector *connector = &nv_connector->base;
930cb459498Sriastradh 	struct drm_device *dev = connector->dev;
931cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
932cb459498Sriastradh 	struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
933cb459498Sriastradh 	bool plugged = gpio->get(gpio, 0, nv_connector->hpd.func, 0xff);
934cb459498Sriastradh 
935cb459498Sriastradh 	NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un",
936cb459498Sriastradh 		 drm_get_connector_name(connector));
937cb459498Sriastradh 
938cb459498Sriastradh 	if (plugged)
939cb459498Sriastradh 		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
940cb459498Sriastradh 	else
941cb459498Sriastradh 		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
942cb459498Sriastradh 
943cb459498Sriastradh 	drm_helper_hpd_irq_event(dev);
944cb459498Sriastradh }
945cb459498Sriastradh 
946cb459498Sriastradh static int
947cb459498Sriastradh nouveau_connector_hotplug(void *data, int index)
948cb459498Sriastradh {
949cb459498Sriastradh 	struct nouveau_connector *nv_connector = data;
950cb459498Sriastradh 	schedule_work(&nv_connector->hpd_work);
951cb459498Sriastradh 	return NVKM_EVENT_KEEP;
952cb459498Sriastradh }
953cb459498Sriastradh 
954cb459498Sriastradh static int
955cb459498Sriastradh drm_conntype_from_dcb(enum dcb_connector_type dcb)
956cb459498Sriastradh {
957cb459498Sriastradh 	switch (dcb) {
958cb459498Sriastradh 	case DCB_CONNECTOR_VGA      : return DRM_MODE_CONNECTOR_VGA;
959cb459498Sriastradh 	case DCB_CONNECTOR_TV_0     :
960cb459498Sriastradh 	case DCB_CONNECTOR_TV_1     :
961cb459498Sriastradh 	case DCB_CONNECTOR_TV_3     : return DRM_MODE_CONNECTOR_TV;
962cb459498Sriastradh 	case DCB_CONNECTOR_DMS59_0  :
963cb459498Sriastradh 	case DCB_CONNECTOR_DMS59_1  :
964cb459498Sriastradh 	case DCB_CONNECTOR_DVI_I    : return DRM_MODE_CONNECTOR_DVII;
965cb459498Sriastradh 	case DCB_CONNECTOR_DVI_D    : return DRM_MODE_CONNECTOR_DVID;
966cb459498Sriastradh 	case DCB_CONNECTOR_LVDS     :
967cb459498Sriastradh 	case DCB_CONNECTOR_LVDS_SPWG: return DRM_MODE_CONNECTOR_LVDS;
968cb459498Sriastradh 	case DCB_CONNECTOR_DMS59_DP0:
969cb459498Sriastradh 	case DCB_CONNECTOR_DMS59_DP1:
970cb459498Sriastradh 	case DCB_CONNECTOR_DP       : return DRM_MODE_CONNECTOR_DisplayPort;
971cb459498Sriastradh 	case DCB_CONNECTOR_eDP      : return DRM_MODE_CONNECTOR_eDP;
972cb459498Sriastradh 	case DCB_CONNECTOR_HDMI_0   :
973cb459498Sriastradh 	case DCB_CONNECTOR_HDMI_1   :
974cb459498Sriastradh 	case DCB_CONNECTOR_HDMI_C   : return DRM_MODE_CONNECTOR_HDMIA;
975cb459498Sriastradh 	default:
976cb459498Sriastradh 		break;
977cb459498Sriastradh 	}
978cb459498Sriastradh 
979cb459498Sriastradh 	return DRM_MODE_CONNECTOR_Unknown;
980cb459498Sriastradh }
981cb459498Sriastradh 
982cb459498Sriastradh struct drm_connector *
983cb459498Sriastradh nouveau_connector_create(struct drm_device *dev, int index)
984cb459498Sriastradh {
985cb459498Sriastradh 	const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
986cb459498Sriastradh 	struct nouveau_drm *drm = nouveau_drm(dev);
987cb459498Sriastradh 	struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
988cb459498Sriastradh 	struct nouveau_display *disp = nouveau_display(dev);
989cb459498Sriastradh 	struct nouveau_connector *nv_connector = NULL;
990cb459498Sriastradh 	struct drm_connector *connector;
991cb459498Sriastradh 	int type, ret = 0;
992cb459498Sriastradh 	bool dummy;
993cb459498Sriastradh 
994cb459498Sriastradh 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
995cb459498Sriastradh 		nv_connector = nouveau_connector(connector);
996cb459498Sriastradh 		if (nv_connector->index == index)
997cb459498Sriastradh 			return connector;
998cb459498Sriastradh 	}
999cb459498Sriastradh 
1000cb459498Sriastradh 	nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
1001cb459498Sriastradh 	if (!nv_connector)
1002cb459498Sriastradh 		return ERR_PTR(-ENOMEM);
1003cb459498Sriastradh 
1004cb459498Sriastradh 	connector = &nv_connector->base;
1005cb459498Sriastradh 	INIT_WORK(&nv_connector->hpd_work, nouveau_connector_hotplug_work);
1006cb459498Sriastradh 	nv_connector->index = index;
1007cb459498Sriastradh 
1008cb459498Sriastradh 	/* attempt to parse vbios connector type and hotplug gpio */
1009cb459498Sriastradh 	nv_connector->dcb = olddcb_conn(dev, index);
1010cb459498Sriastradh 	if (nv_connector->dcb) {
1011cb459498Sriastradh 		static const u8 hpd[16] = {
1012cb459498Sriastradh 			0xff, 0x07, 0x08, 0xff, 0xff, 0x51, 0x52, 0xff,
1013cb459498Sriastradh 			0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x5f, 0x60,
1014cb459498Sriastradh 		};
1015cb459498Sriastradh 
1016cb459498Sriastradh 		u32 entry = ROM16(nv_connector->dcb[0]);
1017cb459498Sriastradh 		if (olddcb_conntab(dev)[3] >= 4)
1018cb459498Sriastradh 			entry |= (u32)ROM16(nv_connector->dcb[2]) << 16;
1019cb459498Sriastradh 
1020cb459498Sriastradh 		ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)],
1021cb459498Sriastradh 				 DCB_GPIO_UNUSED, &nv_connector->hpd);
1022cb459498Sriastradh 		if (ret)
1023cb459498Sriastradh 			nv_connector->hpd.func = DCB_GPIO_UNUSED;
1024cb459498Sriastradh 
1025cb459498Sriastradh 		if (nv_connector->hpd.func != DCB_GPIO_UNUSED) {
1026cb459498Sriastradh 			nouveau_event_new(gpio->events, nv_connector->hpd.line,
1027cb459498Sriastradh 					  nouveau_connector_hotplug,
1028cb459498Sriastradh 					  nv_connector,
1029cb459498Sriastradh 					 &nv_connector->hpd_func);
1030cb459498Sriastradh 		}
1031cb459498Sriastradh 
1032cb459498Sriastradh 		nv_connector->type = nv_connector->dcb[0];
1033cb459498Sriastradh 		if (drm_conntype_from_dcb(nv_connector->type) ==
1034cb459498Sriastradh 					  DRM_MODE_CONNECTOR_Unknown) {
1035cb459498Sriastradh 			NV_WARN(drm, "unknown connector type %02x\n",
1036cb459498Sriastradh 				nv_connector->type);
1037cb459498Sriastradh 			nv_connector->type = DCB_CONNECTOR_NONE;
1038cb459498Sriastradh 		}
1039cb459498Sriastradh 
1040cb459498Sriastradh 		/* Gigabyte NX85T */
1041cb459498Sriastradh 		if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) {
1042cb459498Sriastradh 			if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
1043cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DVI_I;
1044cb459498Sriastradh 		}
1045cb459498Sriastradh 
1046cb459498Sriastradh 		/* Gigabyte GV-NX86T512H */
1047cb459498Sriastradh 		if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) {
1048cb459498Sriastradh 			if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
1049cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DVI_I;
1050cb459498Sriastradh 		}
1051cb459498Sriastradh 	} else {
1052cb459498Sriastradh 		nv_connector->type = DCB_CONNECTOR_NONE;
1053cb459498Sriastradh 		nv_connector->hpd.func = DCB_GPIO_UNUSED;
1054cb459498Sriastradh 	}
1055cb459498Sriastradh 
1056cb459498Sriastradh 	/* no vbios data, or an unknown dcb connector type - attempt to
1057cb459498Sriastradh 	 * figure out something suitable ourselves
1058cb459498Sriastradh 	 */
1059cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_NONE) {
1060cb459498Sriastradh 		struct dcb_table *dcbt = &drm->vbios.dcb;
1061cb459498Sriastradh 		u32 encoders = 0;
1062cb459498Sriastradh 		int i;
1063cb459498Sriastradh 
1064cb459498Sriastradh 		for (i = 0; i < dcbt->entries; i++) {
1065cb459498Sriastradh 			if (dcbt->entry[i].connector == nv_connector->index)
1066cb459498Sriastradh 				encoders |= (1 << dcbt->entry[i].type);
1067cb459498Sriastradh 		}
1068cb459498Sriastradh 
1069cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_DP)) {
1070cb459498Sriastradh 			if (encoders & (1 << DCB_OUTPUT_TMDS))
1071cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DP;
1072cb459498Sriastradh 			else
1073cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_eDP;
1074cb459498Sriastradh 		} else
1075cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_TMDS)) {
1076cb459498Sriastradh 			if (encoders & (1 << DCB_OUTPUT_ANALOG))
1077cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DVI_I;
1078cb459498Sriastradh 			else
1079cb459498Sriastradh 				nv_connector->type = DCB_CONNECTOR_DVI_D;
1080cb459498Sriastradh 		} else
1081cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_ANALOG)) {
1082cb459498Sriastradh 			nv_connector->type = DCB_CONNECTOR_VGA;
1083cb459498Sriastradh 		} else
1084cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_LVDS)) {
1085cb459498Sriastradh 			nv_connector->type = DCB_CONNECTOR_LVDS;
1086cb459498Sriastradh 		} else
1087cb459498Sriastradh 		if (encoders & (1 << DCB_OUTPUT_TV)) {
1088cb459498Sriastradh 			nv_connector->type = DCB_CONNECTOR_TV_0;
1089cb459498Sriastradh 		}
1090cb459498Sriastradh 	}
1091cb459498Sriastradh 
1092cb459498Sriastradh 	type = drm_conntype_from_dcb(nv_connector->type);
1093cb459498Sriastradh 	if (type == DRM_MODE_CONNECTOR_LVDS) {
1094cb459498Sriastradh 		ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy);
1095cb459498Sriastradh 		if (ret) {
1096cb459498Sriastradh 			NV_ERROR(drm, "Error parsing LVDS table, disabling\n");
1097cb459498Sriastradh 			kfree(nv_connector);
1098cb459498Sriastradh 			return ERR_PTR(ret);
1099cb459498Sriastradh 		}
1100cb459498Sriastradh 
1101cb459498Sriastradh 		funcs = &nouveau_connector_funcs_lvds;
1102cb459498Sriastradh 	} else {
1103cb459498Sriastradh 		funcs = &nouveau_connector_funcs;
1104cb459498Sriastradh 	}
1105cb459498Sriastradh 
1106cb459498Sriastradh 	/* defaults, will get overridden in detect() */
1107cb459498Sriastradh 	connector->interlace_allowed = false;
1108cb459498Sriastradh 	connector->doublescan_allowed = false;
1109cb459498Sriastradh 
1110cb459498Sriastradh 	drm_connector_init(dev, connector, funcs, type);
1111cb459498Sriastradh 	drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
1112cb459498Sriastradh 
1113cb459498Sriastradh 	/* Init DVI-I specific properties */
1114cb459498Sriastradh 	if (nv_connector->type == DCB_CONNECTOR_DVI_I)
1115cb459498Sriastradh 		drm_object_attach_property(&connector->base, dev->mode_config.dvi_i_subconnector_property, 0);
1116cb459498Sriastradh 
1117cb459498Sriastradh 	/* Add overscan compensation options to digital outputs */
1118cb459498Sriastradh 	if (disp->underscan_property &&
1119cb459498Sriastradh 	    (type == DRM_MODE_CONNECTOR_DVID ||
1120cb459498Sriastradh 	     type == DRM_MODE_CONNECTOR_DVII ||
1121cb459498Sriastradh 	     type == DRM_MODE_CONNECTOR_HDMIA ||
1122cb459498Sriastradh 	     type == DRM_MODE_CONNECTOR_DisplayPort)) {
1123cb459498Sriastradh 		drm_object_attach_property(&connector->base,
1124cb459498Sriastradh 					      disp->underscan_property,
1125cb459498Sriastradh 					      UNDERSCAN_OFF);
1126cb459498Sriastradh 		drm_object_attach_property(&connector->base,
1127cb459498Sriastradh 					      disp->underscan_hborder_property,
1128cb459498Sriastradh 					      0);
1129cb459498Sriastradh 		drm_object_attach_property(&connector->base,
1130cb459498Sriastradh 					      disp->underscan_vborder_property,
1131cb459498Sriastradh 					      0);
1132cb459498Sriastradh 	}
1133cb459498Sriastradh 
1134cb459498Sriastradh 	/* Add hue and saturation options */
1135cb459498Sriastradh 	if (disp->vibrant_hue_property)
1136cb459498Sriastradh 		drm_object_attach_property(&connector->base,
1137cb459498Sriastradh 					      disp->vibrant_hue_property,
1138cb459498Sriastradh 					      90);
1139cb459498Sriastradh 	if (disp->color_vibrance_property)
1140cb459498Sriastradh 		drm_object_attach_property(&connector->base,
1141cb459498Sriastradh 					      disp->color_vibrance_property,
1142cb459498Sriastradh 					      150);
1143cb459498Sriastradh 
1144cb459498Sriastradh 	switch (nv_connector->type) {
1145cb459498Sriastradh 	case DCB_CONNECTOR_VGA:
1146cb459498Sriastradh 		if (nv_device(drm->device)->card_type >= NV_50) {
1147cb459498Sriastradh 			drm_object_attach_property(&connector->base,
1148cb459498Sriastradh 					dev->mode_config.scaling_mode_property,
1149cb459498Sriastradh 					nv_connector->scaling_mode);
1150cb459498Sriastradh 		}
1151cb459498Sriastradh 		/* fall-through */
1152cb459498Sriastradh 	case DCB_CONNECTOR_TV_0:
1153cb459498Sriastradh 	case DCB_CONNECTOR_TV_1:
1154cb459498Sriastradh 	case DCB_CONNECTOR_TV_3:
1155cb459498Sriastradh 		nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
1156cb459498Sriastradh 		break;
1157cb459498Sriastradh 	default:
1158cb459498Sriastradh 		nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
1159cb459498Sriastradh 
1160cb459498Sriastradh 		drm_object_attach_property(&connector->base,
1161cb459498Sriastradh 				dev->mode_config.scaling_mode_property,
1162cb459498Sriastradh 				nv_connector->scaling_mode);
1163cb459498Sriastradh 		if (disp->dithering_mode) {
1164cb459498Sriastradh 			nv_connector->dithering_mode = DITHERING_MODE_AUTO;
1165cb459498Sriastradh 			drm_object_attach_property(&connector->base,
1166cb459498Sriastradh 						disp->dithering_mode,
1167cb459498Sriastradh 						nv_connector->dithering_mode);
1168cb459498Sriastradh 		}
1169cb459498Sriastradh 		if (disp->dithering_depth) {
1170cb459498Sriastradh 			nv_connector->dithering_depth = DITHERING_DEPTH_AUTO;
1171cb459498Sriastradh 			drm_object_attach_property(&connector->base,
1172cb459498Sriastradh 						disp->dithering_depth,
1173cb459498Sriastradh 						nv_connector->dithering_depth);
1174cb459498Sriastradh 		}
1175cb459498Sriastradh 		break;
1176cb459498Sriastradh 	}
1177cb459498Sriastradh 
1178cb459498Sriastradh 	connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1179cb459498Sriastradh 	if (nv_connector->hpd.func != DCB_GPIO_UNUSED)
1180cb459498Sriastradh 		connector->polled = DRM_CONNECTOR_POLL_HPD;
1181cb459498Sriastradh 
1182cb459498Sriastradh 	drm_sysfs_connector_add(connector);
1183cb459498Sriastradh 	return connector;
1184cb459498Sriastradh }
1185