16ee73861SBen Skeggs /*
26ee73861SBen Skeggs * Copyright (C) 2008 Maarten Maathuis.
36ee73861SBen Skeggs * All Rights Reserved.
46ee73861SBen Skeggs *
56ee73861SBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining
66ee73861SBen Skeggs * a copy of this software and associated documentation files (the
76ee73861SBen Skeggs * "Software"), to deal in the Software without restriction, including
86ee73861SBen Skeggs * without limitation the rights to use, copy, modify, merge, publish,
96ee73861SBen Skeggs * distribute, sublicense, and/or sell copies of the Software, and to
106ee73861SBen Skeggs * permit persons to whom the Software is furnished to do so, subject to
116ee73861SBen Skeggs * the following conditions:
126ee73861SBen Skeggs *
136ee73861SBen Skeggs * The above copyright notice and this permission notice (including the
146ee73861SBen Skeggs * next paragraph) shall be included in all copies or substantial
156ee73861SBen Skeggs * portions of the Software.
166ee73861SBen Skeggs *
176ee73861SBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
186ee73861SBen Skeggs * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
196ee73861SBen Skeggs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
206ee73861SBen Skeggs * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
216ee73861SBen Skeggs * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
226ee73861SBen Skeggs * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
236ee73861SBen Skeggs * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
246ee73861SBen Skeggs *
256ee73861SBen Skeggs */
266ee73861SBen Skeggs
27a1470890SBen Skeggs #include <acpi/button.h>
28a1470890SBen Skeggs
295addcf0aSDave Airlie #include <linux/pm_runtime.h>
3039c1c901SLukas Wunner #include <linux/vga_switcheroo.h>
315addcf0aSDave Airlie
32616915ecSBen Skeggs #include <drm/drm_atomic_helper.h>
33760285e7SDavid Howells #include <drm/drm_edid.h>
34760285e7SDavid Howells #include <drm/drm_crtc_helper.h>
35fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
36a743d758SDhinakaran Pandiyan #include <drm/drm_atomic.h>
37a1470890SBen Skeggs
386ee73861SBen Skeggs #include "nouveau_reg.h"
394dc28134SBen Skeggs #include "nouveau_drv.h"
401a646342SBen Skeggs #include "dispnv04/hw.h"
41d6a9efecSLyude Paul #include "dispnv50/disp.h"
42c0077061SBen Skeggs #include "nouveau_acpi.h"
436ee73861SBen Skeggs
4477145f1cSBen Skeggs #include "nouveau_display.h"
4577145f1cSBen Skeggs #include "nouveau_connector.h"
466ee73861SBen Skeggs #include "nouveau_encoder.h"
476ee73861SBen Skeggs #include "nouveau_crtc.h"
4877145f1cSBen Skeggs
49923bc416SBen Skeggs #include <nvif/class.h>
50773eb04dSBen Skeggs #include <nvif/if0011.h>
5179ca2770SBen Skeggs
52616915ecSBen Skeggs struct drm_display_mode *
nouveau_conn_native_mode(struct drm_connector * connector)53616915ecSBen Skeggs nouveau_conn_native_mode(struct drm_connector *connector)
54616915ecSBen Skeggs {
55616915ecSBen Skeggs const struct drm_connector_helper_funcs *helper = connector->helper_private;
56616915ecSBen Skeggs struct nouveau_drm *drm = nouveau_drm(connector->dev);
57616915ecSBen Skeggs struct drm_device *dev = connector->dev;
58616915ecSBen Skeggs struct drm_display_mode *mode, *largest = NULL;
59616915ecSBen Skeggs int high_w = 0, high_h = 0, high_v = 0;
60616915ecSBen Skeggs
61616915ecSBen Skeggs list_for_each_entry(mode, &connector->probed_modes, head) {
62616915ecSBen Skeggs if (helper->mode_valid(connector, mode) != MODE_OK ||
63616915ecSBen Skeggs (mode->flags & DRM_MODE_FLAG_INTERLACE))
64616915ecSBen Skeggs continue;
65616915ecSBen Skeggs
66616915ecSBen Skeggs /* Use preferred mode if there is one.. */
67616915ecSBen Skeggs if (mode->type & DRM_MODE_TYPE_PREFERRED) {
68616915ecSBen Skeggs NV_DEBUG(drm, "native mode from preferred\n");
69616915ecSBen Skeggs return drm_mode_duplicate(dev, mode);
70616915ecSBen Skeggs }
71616915ecSBen Skeggs
72616915ecSBen Skeggs /* Otherwise, take the resolution with the largest width, then
73616915ecSBen Skeggs * height, then vertical refresh
74616915ecSBen Skeggs */
75616915ecSBen Skeggs if (mode->hdisplay < high_w)
76616915ecSBen Skeggs continue;
77616915ecSBen Skeggs
78616915ecSBen Skeggs if (mode->hdisplay == high_w && mode->vdisplay < high_h)
79616915ecSBen Skeggs continue;
80616915ecSBen Skeggs
81616915ecSBen Skeggs if (mode->hdisplay == high_w && mode->vdisplay == high_h &&
820425662fSVille Syrjälä drm_mode_vrefresh(mode) < high_v)
83616915ecSBen Skeggs continue;
84616915ecSBen Skeggs
85616915ecSBen Skeggs high_w = mode->hdisplay;
86616915ecSBen Skeggs high_h = mode->vdisplay;
870425662fSVille Syrjälä high_v = drm_mode_vrefresh(mode);
88616915ecSBen Skeggs largest = mode;
89616915ecSBen Skeggs }
90616915ecSBen Skeggs
91616915ecSBen Skeggs NV_DEBUG(drm, "native mode from largest: %dx%d@%d\n",
92616915ecSBen Skeggs high_w, high_h, high_v);
93616915ecSBen Skeggs return largest ? drm_mode_duplicate(dev, largest) : NULL;
94616915ecSBen Skeggs }
95616915ecSBen Skeggs
96616915ecSBen Skeggs int
nouveau_conn_atomic_get_property(struct drm_connector * connector,const struct drm_connector_state * state,struct drm_property * property,u64 * val)97616915ecSBen Skeggs nouveau_conn_atomic_get_property(struct drm_connector *connector,
98616915ecSBen Skeggs const struct drm_connector_state *state,
99616915ecSBen Skeggs struct drm_property *property, u64 *val)
100616915ecSBen Skeggs {
101616915ecSBen Skeggs struct nouveau_conn_atom *asyc = nouveau_conn_atom(state);
102616915ecSBen Skeggs struct nouveau_display *disp = nouveau_display(connector->dev);
103616915ecSBen Skeggs struct drm_device *dev = connector->dev;
104616915ecSBen Skeggs
105616915ecSBen Skeggs if (property == dev->mode_config.scaling_mode_property)
106616915ecSBen Skeggs *val = asyc->scaler.mode;
107616915ecSBen Skeggs else if (property == disp->underscan_property)
108616915ecSBen Skeggs *val = asyc->scaler.underscan.mode;
109616915ecSBen Skeggs else if (property == disp->underscan_hborder_property)
110616915ecSBen Skeggs *val = asyc->scaler.underscan.hborder;
111616915ecSBen Skeggs else if (property == disp->underscan_vborder_property)
112616915ecSBen Skeggs *val = asyc->scaler.underscan.vborder;
113616915ecSBen Skeggs else if (property == disp->dithering_mode)
114616915ecSBen Skeggs *val = asyc->dither.mode;
115616915ecSBen Skeggs else if (property == disp->dithering_depth)
116616915ecSBen Skeggs *val = asyc->dither.depth;
117616915ecSBen Skeggs else if (property == disp->vibrant_hue_property)
118616915ecSBen Skeggs *val = asyc->procamp.vibrant_hue;
119616915ecSBen Skeggs else if (property == disp->color_vibrance_property)
120616915ecSBen Skeggs *val = asyc->procamp.color_vibrance;
121616915ecSBen Skeggs else
122616915ecSBen Skeggs return -EINVAL;
123616915ecSBen Skeggs
124616915ecSBen Skeggs return 0;
125616915ecSBen Skeggs }
126616915ecSBen Skeggs
127616915ecSBen Skeggs int
nouveau_conn_atomic_set_property(struct drm_connector * connector,struct drm_connector_state * state,struct drm_property * property,u64 val)128616915ecSBen Skeggs nouveau_conn_atomic_set_property(struct drm_connector *connector,
129616915ecSBen Skeggs struct drm_connector_state *state,
130616915ecSBen Skeggs struct drm_property *property, u64 val)
131616915ecSBen Skeggs {
132616915ecSBen Skeggs struct drm_device *dev = connector->dev;
133616915ecSBen Skeggs struct nouveau_conn_atom *asyc = nouveau_conn_atom(state);
134616915ecSBen Skeggs struct nouveau_display *disp = nouveau_display(dev);
135616915ecSBen Skeggs
136616915ecSBen Skeggs if (property == dev->mode_config.scaling_mode_property) {
137616915ecSBen Skeggs switch (val) {
138616915ecSBen Skeggs case DRM_MODE_SCALE_NONE:
139616915ecSBen Skeggs /* We allow 'None' for EDID modes, even on a fixed
140616915ecSBen Skeggs * panel (some exist with support for lower refresh
141616915ecSBen Skeggs * rates, which people might want to use for power-
142616915ecSBen Skeggs * saving purposes).
143616915ecSBen Skeggs *
144616915ecSBen Skeggs * Non-EDID modes will force the use of GPU scaling
145616915ecSBen Skeggs * to the native mode regardless of this setting.
146616915ecSBen Skeggs */
147616915ecSBen Skeggs switch (connector->connector_type) {
148616915ecSBen Skeggs case DRM_MODE_CONNECTOR_LVDS:
149616915ecSBen Skeggs case DRM_MODE_CONNECTOR_eDP:
150616915ecSBen Skeggs /* ... except prior to G80, where the code
151616915ecSBen Skeggs * doesn't support such things.
152616915ecSBen Skeggs */
1530d4a2c57SBen Skeggs if (disp->disp.object.oclass < NV50_DISP)
154616915ecSBen Skeggs return -EINVAL;
155616915ecSBen Skeggs break;
156616915ecSBen Skeggs default:
157616915ecSBen Skeggs break;
158616915ecSBen Skeggs }
159f49efb10SGustavo A. R. Silva break;
160616915ecSBen Skeggs case DRM_MODE_SCALE_FULLSCREEN:
161616915ecSBen Skeggs case DRM_MODE_SCALE_CENTER:
162616915ecSBen Skeggs case DRM_MODE_SCALE_ASPECT:
163616915ecSBen Skeggs break;
164616915ecSBen Skeggs default:
165616915ecSBen Skeggs return -EINVAL;
166616915ecSBen Skeggs }
167616915ecSBen Skeggs
168616915ecSBen Skeggs if (asyc->scaler.mode != val) {
169616915ecSBen Skeggs asyc->scaler.mode = val;
170616915ecSBen Skeggs asyc->set.scaler = true;
171616915ecSBen Skeggs }
172616915ecSBen Skeggs } else
173616915ecSBen Skeggs if (property == disp->underscan_property) {
174616915ecSBen Skeggs if (asyc->scaler.underscan.mode != val) {
175616915ecSBen Skeggs asyc->scaler.underscan.mode = val;
176616915ecSBen Skeggs asyc->set.scaler = true;
177616915ecSBen Skeggs }
178616915ecSBen Skeggs } else
179616915ecSBen Skeggs if (property == disp->underscan_hborder_property) {
180616915ecSBen Skeggs if (asyc->scaler.underscan.hborder != val) {
181616915ecSBen Skeggs asyc->scaler.underscan.hborder = val;
182616915ecSBen Skeggs asyc->set.scaler = true;
183616915ecSBen Skeggs }
184616915ecSBen Skeggs } else
185616915ecSBen Skeggs if (property == disp->underscan_vborder_property) {
186616915ecSBen Skeggs if (asyc->scaler.underscan.vborder != val) {
187616915ecSBen Skeggs asyc->scaler.underscan.vborder = val;
188616915ecSBen Skeggs asyc->set.scaler = true;
189616915ecSBen Skeggs }
190616915ecSBen Skeggs } else
191616915ecSBen Skeggs if (property == disp->dithering_mode) {
192616915ecSBen Skeggs if (asyc->dither.mode != val) {
193616915ecSBen Skeggs asyc->dither.mode = val;
194616915ecSBen Skeggs asyc->set.dither = true;
195616915ecSBen Skeggs }
196616915ecSBen Skeggs } else
197616915ecSBen Skeggs if (property == disp->dithering_depth) {
198616915ecSBen Skeggs if (asyc->dither.mode != val) {
199616915ecSBen Skeggs asyc->dither.depth = val;
200616915ecSBen Skeggs asyc->set.dither = true;
201616915ecSBen Skeggs }
202616915ecSBen Skeggs } else
203616915ecSBen Skeggs if (property == disp->vibrant_hue_property) {
204616915ecSBen Skeggs if (asyc->procamp.vibrant_hue != val) {
205616915ecSBen Skeggs asyc->procamp.vibrant_hue = val;
206616915ecSBen Skeggs asyc->set.procamp = true;
207616915ecSBen Skeggs }
208616915ecSBen Skeggs } else
209616915ecSBen Skeggs if (property == disp->color_vibrance_property) {
210616915ecSBen Skeggs if (asyc->procamp.color_vibrance != val) {
211616915ecSBen Skeggs asyc->procamp.color_vibrance = val;
212616915ecSBen Skeggs asyc->set.procamp = true;
213616915ecSBen Skeggs }
214616915ecSBen Skeggs } else {
215616915ecSBen Skeggs return -EINVAL;
216616915ecSBen Skeggs }
217616915ecSBen Skeggs
218616915ecSBen Skeggs return 0;
219616915ecSBen Skeggs }
220616915ecSBen Skeggs
221616915ecSBen Skeggs void
nouveau_conn_atomic_destroy_state(struct drm_connector * connector,struct drm_connector_state * state)222616915ecSBen Skeggs nouveau_conn_atomic_destroy_state(struct drm_connector *connector,
223616915ecSBen Skeggs struct drm_connector_state *state)
224616915ecSBen Skeggs {
225616915ecSBen Skeggs struct nouveau_conn_atom *asyc = nouveau_conn_atom(state);
226616915ecSBen Skeggs __drm_atomic_helper_connector_destroy_state(&asyc->state);
227616915ecSBen Skeggs kfree(asyc);
228616915ecSBen Skeggs }
229616915ecSBen Skeggs
230616915ecSBen Skeggs struct drm_connector_state *
nouveau_conn_atomic_duplicate_state(struct drm_connector * connector)231616915ecSBen Skeggs nouveau_conn_atomic_duplicate_state(struct drm_connector *connector)
232616915ecSBen Skeggs {
233616915ecSBen Skeggs struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state);
234616915ecSBen Skeggs struct nouveau_conn_atom *asyc;
235616915ecSBen Skeggs if (!(asyc = kmalloc(sizeof(*asyc), GFP_KERNEL)))
236616915ecSBen Skeggs return NULL;
237616915ecSBen Skeggs __drm_atomic_helper_connector_duplicate_state(connector, &asyc->state);
238616915ecSBen Skeggs asyc->dither = armc->dither;
239616915ecSBen Skeggs asyc->scaler = armc->scaler;
240616915ecSBen Skeggs asyc->procamp = armc->procamp;
241616915ecSBen Skeggs asyc->set.mask = 0;
242616915ecSBen Skeggs return &asyc->state;
243616915ecSBen Skeggs }
244616915ecSBen Skeggs
245616915ecSBen Skeggs void
nouveau_conn_reset(struct drm_connector * connector)246616915ecSBen Skeggs nouveau_conn_reset(struct drm_connector *connector)
247616915ecSBen Skeggs {
24864d17f25SHans de Goede struct nouveau_connector *nv_connector = nouveau_connector(connector);
249616915ecSBen Skeggs struct nouveau_conn_atom *asyc;
250616915ecSBen Skeggs
25164d17f25SHans de Goede if (drm_drv_uses_atomic_modeset(connector->dev)) {
252616915ecSBen Skeggs if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL))))
253616915ecSBen Skeggs return;
254616915ecSBen Skeggs
255616915ecSBen Skeggs if (connector->state)
25664d17f25SHans de Goede nouveau_conn_atomic_destroy_state(connector,
25764d17f25SHans de Goede connector->state);
25864d17f25SHans de Goede
259616915ecSBen Skeggs __drm_atomic_helper_connector_reset(connector, &asyc->state);
26064d17f25SHans de Goede } else {
26164d17f25SHans de Goede asyc = &nv_connector->properties_state;
26264d17f25SHans de Goede }
26364d17f25SHans de Goede
264616915ecSBen Skeggs asyc->dither.mode = DITHERING_MODE_AUTO;
265616915ecSBen Skeggs asyc->dither.depth = DITHERING_DEPTH_AUTO;
266616915ecSBen Skeggs asyc->scaler.mode = DRM_MODE_SCALE_NONE;
267616915ecSBen Skeggs asyc->scaler.underscan.mode = UNDERSCAN_OFF;
268616915ecSBen Skeggs asyc->procamp.color_vibrance = 150;
269616915ecSBen Skeggs asyc->procamp.vibrant_hue = 90;
270616915ecSBen Skeggs
2710d4a2c57SBen Skeggs if (nouveau_display(connector->dev)->disp.object.oclass < NV50_DISP) {
272616915ecSBen Skeggs switch (connector->connector_type) {
273616915ecSBen Skeggs case DRM_MODE_CONNECTOR_LVDS:
274616915ecSBen Skeggs /* See note in nouveau_conn_atomic_set_property(). */
275616915ecSBen Skeggs asyc->scaler.mode = DRM_MODE_SCALE_FULLSCREEN;
276616915ecSBen Skeggs break;
277616915ecSBen Skeggs default:
278616915ecSBen Skeggs break;
279616915ecSBen Skeggs }
280616915ecSBen Skeggs }
281616915ecSBen Skeggs }
282616915ecSBen Skeggs
28356182b8bSBen Skeggs void
nouveau_conn_attach_properties(struct drm_connector * connector)28456182b8bSBen Skeggs nouveau_conn_attach_properties(struct drm_connector *connector)
28556182b8bSBen Skeggs {
28656182b8bSBen Skeggs struct drm_device *dev = connector->dev;
28756182b8bSBen Skeggs struct nouveau_display *disp = nouveau_display(dev);
28864d17f25SHans de Goede struct nouveau_connector *nv_connector = nouveau_connector(connector);
28964d17f25SHans de Goede struct nouveau_conn_atom *armc;
29064d17f25SHans de Goede
29164d17f25SHans de Goede if (drm_drv_uses_atomic_modeset(connector->dev))
29264d17f25SHans de Goede armc = nouveau_conn_atom(connector->state);
29364d17f25SHans de Goede else
29464d17f25SHans de Goede armc = &nv_connector->properties_state;
29556182b8bSBen Skeggs
29656182b8bSBen Skeggs /* Init DVI-I specific properties. */
29756182b8bSBen Skeggs if (connector->connector_type == DRM_MODE_CONNECTOR_DVII)
29856182b8bSBen Skeggs drm_object_attach_property(&connector->base, dev->mode_config.
29956182b8bSBen Skeggs dvi_i_subconnector_property, 0);
30056182b8bSBen Skeggs
30156182b8bSBen Skeggs /* Add overscan compensation options to digital outputs. */
30256182b8bSBen Skeggs if (disp->underscan_property &&
30356182b8bSBen Skeggs (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
30456182b8bSBen Skeggs connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
30556182b8bSBen Skeggs connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
30656182b8bSBen Skeggs connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)) {
30756182b8bSBen Skeggs drm_object_attach_property(&connector->base,
30856182b8bSBen Skeggs disp->underscan_property,
30956182b8bSBen Skeggs UNDERSCAN_OFF);
31056182b8bSBen Skeggs drm_object_attach_property(&connector->base,
31156182b8bSBen Skeggs disp->underscan_hborder_property, 0);
31256182b8bSBen Skeggs drm_object_attach_property(&connector->base,
31356182b8bSBen Skeggs disp->underscan_vborder_property, 0);
31456182b8bSBen Skeggs }
31556182b8bSBen Skeggs
31656182b8bSBen Skeggs /* Add hue and saturation options. */
31756182b8bSBen Skeggs if (disp->vibrant_hue_property)
31856182b8bSBen Skeggs drm_object_attach_property(&connector->base,
31956182b8bSBen Skeggs disp->vibrant_hue_property,
32056182b8bSBen Skeggs armc->procamp.vibrant_hue);
32156182b8bSBen Skeggs if (disp->color_vibrance_property)
32256182b8bSBen Skeggs drm_object_attach_property(&connector->base,
32356182b8bSBen Skeggs disp->color_vibrance_property,
32456182b8bSBen Skeggs armc->procamp.color_vibrance);
32556182b8bSBen Skeggs
32656182b8bSBen Skeggs /* Scaling mode property. */
32756182b8bSBen Skeggs switch (connector->connector_type) {
32856182b8bSBen Skeggs case DRM_MODE_CONNECTOR_TV:
32956182b8bSBen Skeggs break;
33056182b8bSBen Skeggs case DRM_MODE_CONNECTOR_VGA:
3310d4a2c57SBen Skeggs if (disp->disp.object.oclass < NV50_DISP)
33256182b8bSBen Skeggs break; /* Can only scale on DFPs. */
333f6e7393eSGustavo A. R. Silva fallthrough;
33456182b8bSBen Skeggs default:
33556182b8bSBen Skeggs drm_object_attach_property(&connector->base, dev->mode_config.
33656182b8bSBen Skeggs scaling_mode_property,
33756182b8bSBen Skeggs armc->scaler.mode);
33856182b8bSBen Skeggs break;
33956182b8bSBen Skeggs }
34056182b8bSBen Skeggs
34156182b8bSBen Skeggs /* Dithering properties. */
34256182b8bSBen Skeggs switch (connector->connector_type) {
34356182b8bSBen Skeggs case DRM_MODE_CONNECTOR_TV:
34456182b8bSBen Skeggs case DRM_MODE_CONNECTOR_VGA:
34556182b8bSBen Skeggs break;
34656182b8bSBen Skeggs default:
34756182b8bSBen Skeggs if (disp->dithering_mode) {
34856182b8bSBen Skeggs drm_object_attach_property(&connector->base,
34956182b8bSBen Skeggs disp->dithering_mode,
35056182b8bSBen Skeggs armc->dither.mode);
35156182b8bSBen Skeggs }
35256182b8bSBen Skeggs if (disp->dithering_depth) {
35356182b8bSBen Skeggs drm_object_attach_property(&connector->base,
35456182b8bSBen Skeggs disp->dithering_depth,
35556182b8bSBen Skeggs armc->dither.depth);
35656182b8bSBen Skeggs }
35756182b8bSBen Skeggs break;
35856182b8bSBen Skeggs }
35956182b8bSBen Skeggs }
36056182b8bSBen Skeggs
36177145f1cSBen Skeggs MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
362703fa264SPierre Moreau int nouveau_tv_disable = 0;
36377145f1cSBen Skeggs module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
36477145f1cSBen Skeggs
36577145f1cSBen Skeggs MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
366703fa264SPierre Moreau int nouveau_ignorelid = 0;
36777145f1cSBen Skeggs module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
36877145f1cSBen Skeggs
36977145f1cSBen Skeggs MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)");
370703fa264SPierre Moreau int nouveau_duallink = 1;
37177145f1cSBen Skeggs module_param_named(duallink, nouveau_duallink, int, 0400);
3726ee73861SBen Skeggs
3731a0c96c0SIlia Mirkin MODULE_PARM_DESC(hdmimhz, "Force a maximum HDMI pixel clock (in MHz)");
3741a0c96c0SIlia Mirkin int nouveau_hdmimhz = 0;
3751a0c96c0SIlia Mirkin module_param_named(hdmimhz, nouveau_hdmimhz, int, 0400);
3761a0c96c0SIlia Mirkin
37710b461e4SBen Skeggs struct nouveau_encoder *
find_encoder(struct drm_connector * connector,int type)378e19b20bbSBen Skeggs find_encoder(struct drm_connector *connector, int type)
3796ee73861SBen Skeggs {
3806ee73861SBen Skeggs struct nouveau_encoder *nv_encoder;
3816d385c0aSRob Clark struct drm_encoder *enc;
3826ee73861SBen Skeggs
38362afb4adSJosé Roberto de Souza drm_connector_for_each_possible_encoder(connector, enc) {
3846d385c0aSRob Clark nv_encoder = nouveau_encoder(enc);
3856ee73861SBen Skeggs
3864874322eSBen Skeggs if (type == DCB_OUTPUT_ANY ||
3874874322eSBen Skeggs (nv_encoder->dcb && nv_encoder->dcb->type == type))
3886ee73861SBen Skeggs return nv_encoder;
3896ee73861SBen Skeggs }
3906ee73861SBen Skeggs
3916ee73861SBen Skeggs return NULL;
3926ee73861SBen Skeggs }
3936ee73861SBen Skeggs
3946ee73861SBen Skeggs static void
nouveau_connector_destroy(struct drm_connector * connector)395fce2bad0SBen Skeggs nouveau_connector_destroy(struct drm_connector *connector)
3966ee73861SBen Skeggs {
397fce2bad0SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
398773eb04dSBen Skeggs nvif_event_dtor(&nv_connector->irq);
399773eb04dSBen Skeggs nvif_event_dtor(&nv_connector->hpd);
400c8ebe275SXavier Chantry kfree(nv_connector->edid);
40134ea3d38SThomas Wood drm_connector_unregister(connector);
402fce2bad0SBen Skeggs drm_connector_cleanup(connector);
40346094b2bSHans Verkuil if (nv_connector->aux.transfer) {
40446094b2bSHans Verkuil drm_dp_cec_unregister_connector(&nv_connector->aux);
4053c7fc252SLyude Paul kfree(nv_connector->aux.name);
40646094b2bSHans Verkuil }
40795983aeaSBen Skeggs nvif_conn_dtor(&nv_connector->conn);
408fce2bad0SBen Skeggs kfree(connector);
4096ee73861SBen Skeggs }
4106ee73861SBen Skeggs
4118777c5c1SBen Skeggs static struct nouveau_encoder *
nouveau_connector_ddc_detect(struct drm_connector * connector)4128777c5c1SBen Skeggs nouveau_connector_ddc_detect(struct drm_connector *connector)
4136ee73861SBen Skeggs {
4146ee73861SBen Skeggs struct drm_device *dev = connector->dev;
4154c0d42f7SThomas Zimmermann struct pci_dev *pdev = to_pci_dev(dev->dev);
416d5986a1cSLyude Paul struct nouveau_encoder *nv_encoder = NULL, *found = NULL;
4176d385c0aSRob Clark struct drm_encoder *encoder;
41862afb4adSJosé Roberto de Souza int ret;
419d5986a1cSLyude Paul bool switcheroo_ddc = false;
4206ee73861SBen Skeggs
42162afb4adSJosé Roberto de Souza drm_connector_for_each_possible_encoder(connector, encoder) {
4226d385c0aSRob Clark nv_encoder = nouveau_encoder(encoder);
4234ca2b712SFrancisco Jerez
424d5986a1cSLyude Paul switch (nv_encoder->dcb->type) {
425d5986a1cSLyude Paul case DCB_OUTPUT_DP:
4266ba11932SLyude Paul ret = nouveau_dp_detect(nouveau_connector(connector),
4276ba11932SLyude Paul nv_encoder);
42852aa30f2SBen Skeggs if (ret == NOUVEAU_DP_MST)
42952aa30f2SBen Skeggs return NULL;
430d5986a1cSLyude Paul else if (ret == NOUVEAU_DP_SST)
431d5986a1cSLyude Paul found = nv_encoder;
432d5986a1cSLyude Paul
4338777c5c1SBen Skeggs break;
434d5986a1cSLyude Paul case DCB_OUTPUT_LVDS:
435d5986a1cSLyude Paul switcheroo_ddc = !!(vga_switcheroo_handler_flags() &
436d5986a1cSLyude Paul VGA_SWITCHEROO_CAN_SWITCH_DDC);
437f6e7393eSGustavo A. R. Silva fallthrough;
438d5986a1cSLyude Paul default:
439d5986a1cSLyude Paul if (!nv_encoder->i2c)
440d5986a1cSLyude Paul break;
441d5986a1cSLyude Paul
442d5986a1cSLyude Paul if (switcheroo_ddc)
4434c0d42f7SThomas Zimmermann vga_switcheroo_lock_ddc(pdev);
4442aa5eac5SBen Skeggs if (nvkm_probe_i2c(nv_encoder->i2c, 0x50))
445d5986a1cSLyude Paul found = nv_encoder;
446d5986a1cSLyude Paul if (switcheroo_ddc)
4474c0d42f7SThomas Zimmermann vga_switcheroo_unlock_ddc(pdev);
448d5986a1cSLyude Paul
4491a1841d3SBen Skeggs break;
4506ee73861SBen Skeggs }
451d5986a1cSLyude Paul if (found)
452d5986a1cSLyude Paul break;
4531a1841d3SBen Skeggs }
4541a1841d3SBen Skeggs
455d5986a1cSLyude Paul return found;
4566ee73861SBen Skeggs }
4576ee73861SBen Skeggs
458c16c5707SFrancisco Jerez static struct nouveau_encoder *
nouveau_connector_of_detect(struct drm_connector * connector)459c16c5707SFrancisco Jerez nouveau_connector_of_detect(struct drm_connector *connector)
460c16c5707SFrancisco Jerez {
461c16c5707SFrancisco Jerez #ifdef __powerpc__
462c16c5707SFrancisco Jerez struct drm_device *dev = connector->dev;
463c16c5707SFrancisco Jerez struct nouveau_connector *nv_connector = nouveau_connector(connector);
464c16c5707SFrancisco Jerez struct nouveau_encoder *nv_encoder;
465bfba9416SThomas Zimmermann struct pci_dev *pdev = to_pci_dev(dev->dev);
466bfba9416SThomas Zimmermann struct device_node *cn, *dn = pci_device_to_OF_node(pdev);
467c16c5707SFrancisco Jerez
468c16c5707SFrancisco Jerez if (!dn ||
469cb75d97eSBen Skeggs !((nv_encoder = find_encoder(connector, DCB_OUTPUT_TMDS)) ||
470cb75d97eSBen Skeggs (nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG))))
471c16c5707SFrancisco Jerez return NULL;
472c16c5707SFrancisco Jerez
473c16c5707SFrancisco Jerez for_each_child_of_node(dn, cn) {
474c16c5707SFrancisco Jerez const char *name = of_get_property(cn, "name", NULL);
475c16c5707SFrancisco Jerez const void *edid = of_get_property(cn, "EDID", NULL);
476c16c5707SFrancisco Jerez int idx = name ? name[strlen(name) - 1] - 'A' : 0;
477c16c5707SFrancisco Jerez
478c16c5707SFrancisco Jerez if (nv_encoder->dcb->i2c_index == idx && edid) {
479c16c5707SFrancisco Jerez nv_connector->edid =
480c16c5707SFrancisco Jerez kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
481c16c5707SFrancisco Jerez of_node_put(cn);
482c16c5707SFrancisco Jerez return nv_encoder;
483c16c5707SFrancisco Jerez }
484c16c5707SFrancisco Jerez }
485c16c5707SFrancisco Jerez #endif
486c16c5707SFrancisco Jerez return NULL;
487c16c5707SFrancisco Jerez }
488c16c5707SFrancisco Jerez
4896ee73861SBen Skeggs static void
nouveau_connector_set_encoder(struct drm_connector * connector,struct nouveau_encoder * nv_encoder)4906ee73861SBen Skeggs nouveau_connector_set_encoder(struct drm_connector *connector,
4916ee73861SBen Skeggs struct nouveau_encoder *nv_encoder)
4926ee73861SBen Skeggs {
4936ee73861SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
49477145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(connector->dev);
4956ee73861SBen Skeggs struct drm_device *dev = connector->dev;
4964c0d42f7SThomas Zimmermann struct pci_dev *pdev = to_pci_dev(dev->dev);
4976ee73861SBen Skeggs
4986ee73861SBen Skeggs if (nv_connector->detected_encoder == nv_encoder)
4996ee73861SBen Skeggs return;
5006ee73861SBen Skeggs nv_connector->detected_encoder = nv_encoder;
5016ee73861SBen Skeggs
5021167c6bcSBen Skeggs if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
5034a2cb418SLyude Paul if (nv_encoder->dcb->type == DCB_OUTPUT_DP)
5044a2cb418SLyude Paul connector->interlace_allowed =
5054a2cb418SLyude Paul nv_encoder->caps.dp_interlace;
5064a2cb418SLyude Paul else
5078ba92493SLyude Paul connector->interlace_allowed =
5088ba92493SLyude Paul drm->client.device.info.family < NV_DEVICE_INFO_V0_VOLTA;
509c8334423SBen Skeggs connector->doublescan_allowed = true;
510c8334423SBen Skeggs } else
511cb75d97eSBen Skeggs if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS ||
512cb75d97eSBen Skeggs nv_encoder->dcb->type == DCB_OUTPUT_TMDS) {
5136ee73861SBen Skeggs connector->doublescan_allowed = false;
5146ee73861SBen Skeggs connector->interlace_allowed = false;
5156ee73861SBen Skeggs } else {
5166ee73861SBen Skeggs connector->doublescan_allowed = true;
5171167c6bcSBen Skeggs if (drm->client.device.info.family == NV_DEVICE_INFO_V0_KELVIN ||
5181167c6bcSBen Skeggs (drm->client.device.info.family == NV_DEVICE_INFO_V0_CELSIUS &&
5194c0d42f7SThomas Zimmermann (pdev->device & 0x0ff0) != 0x0100 &&
5204c0d42f7SThomas Zimmermann (pdev->device & 0x0ff0) != 0x0150))
5216ee73861SBen Skeggs /* HW is broken */
5226ee73861SBen Skeggs connector->interlace_allowed = false;
5236ee73861SBen Skeggs else
5246ee73861SBen Skeggs connector->interlace_allowed = true;
5256ee73861SBen Skeggs }
5266ee73861SBen Skeggs
527befb51e9SBen Skeggs if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
5282db83827SRob Clark drm_object_property_set_value(&connector->base,
5296ee73861SBen Skeggs dev->mode_config.dvi_i_subconnector_property,
530cb75d97eSBen Skeggs nv_encoder->dcb->type == DCB_OUTPUT_TMDS ?
5316ee73861SBen Skeggs DRM_MODE_SUBCONNECTOR_DVID :
5326ee73861SBen Skeggs DRM_MODE_SUBCONNECTOR_DVIA);
5336ee73861SBen Skeggs }
5346ee73861SBen Skeggs }
5356ee73861SBen Skeggs
536f28e32d3SLyude Paul static void
nouveau_connector_set_edid(struct nouveau_connector * nv_connector,struct edid * edid)537f28e32d3SLyude Paul nouveau_connector_set_edid(struct nouveau_connector *nv_connector,
538f28e32d3SLyude Paul struct edid *edid)
539f28e32d3SLyude Paul {
540630f5122SAlexander Kapshuk if (nv_connector->edid != edid) {
541f28e32d3SLyude Paul struct edid *old_edid = nv_connector->edid;
542f28e32d3SLyude Paul
543f28e32d3SLyude Paul drm_connector_update_edid_property(&nv_connector->base, edid);
544f28e32d3SLyude Paul kfree(old_edid);
545f28e32d3SLyude Paul nv_connector->edid = edid;
546f28e32d3SLyude Paul }
547630f5122SAlexander Kapshuk }
548f28e32d3SLyude Paul
5496ee73861SBen Skeggs static enum drm_connector_status
nouveau_connector_detect(struct drm_connector * connector,bool force)550930a9e28SChris Wilson nouveau_connector_detect(struct drm_connector *connector, bool force)
5516ee73861SBen Skeggs {
5526ee73861SBen Skeggs struct drm_device *dev = connector->dev;
55377145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev);
5546ee73861SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
5556ee73861SBen Skeggs struct nouveau_encoder *nv_encoder = NULL;
556e19b20bbSBen Skeggs struct nouveau_encoder *nv_partner;
5572aa5eac5SBen Skeggs struct i2c_adapter *i2c;
55803cd06caSFrancisco Jerez int type;
5595addcf0aSDave Airlie int ret;
5605addcf0aSDave Airlie enum drm_connector_status conn_status = connector_status_disconnected;
5616ee73861SBen Skeggs
5626833fb1eSLyude Paul /* Outputs are only polled while runtime active, so resuming the
5636833fb1eSLyude Paul * device here is unnecessary (and would deadlock upon runtime suspend
5646833fb1eSLyude Paul * because it waits for polling to finish). We do however, want to
5656833fb1eSLyude Paul * prevent the autosuspend timer from elapsing during this operation
5666833fb1eSLyude Paul * if possible.
567d61a5c10SLukas Wunner */
5686833fb1eSLyude Paul if (drm_kms_helper_is_poll_worker()) {
5696833fb1eSLyude Paul pm_runtime_get_noresume(dev->dev);
5706833fb1eSLyude Paul } else {
5716833fb1eSLyude Paul ret = pm_runtime_get_sync(dev->dev);
572990a1162SAditya Pakki if (ret < 0 && ret != -EACCES) {
573990a1162SAditya Pakki pm_runtime_put_autosuspend(dev->dev);
574f28e32d3SLyude Paul nouveau_connector_set_edid(nv_connector, NULL);
5755addcf0aSDave Airlie return conn_status;
576d61a5c10SLukas Wunner }
577990a1162SAditya Pakki }
5785addcf0aSDave Airlie
5798777c5c1SBen Skeggs nv_encoder = nouveau_connector_ddc_detect(connector);
5808777c5c1SBen Skeggs if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
581f28e32d3SLyude Paul struct edid *new_edid;
582f28e32d3SLyude Paul
58339c1c901SLukas Wunner if ((vga_switcheroo_handler_flags() &
58439c1c901SLukas Wunner VGA_SWITCHEROO_CAN_SWITCH_DDC) &&
58539c1c901SLukas Wunner nv_connector->type == DCB_CONNECTOR_LVDS)
586f28e32d3SLyude Paul new_edid = drm_get_edid_switcheroo(connector, i2c);
58739c1c901SLukas Wunner else
588f28e32d3SLyude Paul new_edid = drm_get_edid(connector, i2c);
58939c1c901SLukas Wunner
590f28e32d3SLyude Paul nouveau_connector_set_edid(nv_connector, new_edid);
5916ee73861SBen Skeggs if (!nv_connector->edid) {
59277145f1cSBen Skeggs NV_ERROR(drm, "DDC responded, but no EDID for %s\n",
5938c6c361aSJani Nikula connector->name);
5940ed3165eSFrancisco Jerez goto detect_analog;
5956ee73861SBen Skeggs }
5966ee73861SBen Skeggs
5976ee73861SBen Skeggs /* Override encoder type for DVI-I based on whether EDID
5986ee73861SBen Skeggs * says the display is digital or analog, both use the
5996ee73861SBen Skeggs * same i2c channel so the value returned from ddc_detect
6006ee73861SBen Skeggs * isn't necessarily correct.
6016ee73861SBen Skeggs */
602e19b20bbSBen Skeggs nv_partner = NULL;
603cb75d97eSBen Skeggs if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS)
604cb75d97eSBen Skeggs nv_partner = find_encoder(connector, DCB_OUTPUT_ANALOG);
605cb75d97eSBen Skeggs if (nv_encoder->dcb->type == DCB_OUTPUT_ANALOG)
606cb75d97eSBen Skeggs nv_partner = find_encoder(connector, DCB_OUTPUT_TMDS);
607e19b20bbSBen Skeggs
608cb75d97eSBen Skeggs if (nv_partner && ((nv_encoder->dcb->type == DCB_OUTPUT_ANALOG &&
609cb75d97eSBen Skeggs nv_partner->dcb->type == DCB_OUTPUT_TMDS) ||
610cb75d97eSBen Skeggs (nv_encoder->dcb->type == DCB_OUTPUT_TMDS &&
611cb75d97eSBen Skeggs nv_partner->dcb->type == DCB_OUTPUT_ANALOG))) {
6126ee73861SBen Skeggs if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
613cb75d97eSBen Skeggs type = DCB_OUTPUT_TMDS;
6146ee73861SBen Skeggs else
615cb75d97eSBen Skeggs type = DCB_OUTPUT_ANALOG;
6166ee73861SBen Skeggs
617e19b20bbSBen Skeggs nv_encoder = find_encoder(connector, type);
6186ee73861SBen Skeggs }
6196ee73861SBen Skeggs
6206ee73861SBen Skeggs nouveau_connector_set_encoder(connector, nv_encoder);
6215addcf0aSDave Airlie conn_status = connector_status_connected;
622ca3545cfSBen Skeggs
623ca3545cfSBen Skeggs if (nv_encoder->dcb->type == DCB_OUTPUT_DP)
62446094b2bSHans Verkuil drm_dp_cec_set_edid(&nv_connector->aux, nv_connector->edid);
625ca3545cfSBen Skeggs
6265addcf0aSDave Airlie goto out;
627f28e32d3SLyude Paul } else {
628f28e32d3SLyude Paul nouveau_connector_set_edid(nv_connector, NULL);
6296ee73861SBen Skeggs }
6306ee73861SBen Skeggs
631c16c5707SFrancisco Jerez nv_encoder = nouveau_connector_of_detect(connector);
632c16c5707SFrancisco Jerez if (nv_encoder) {
633c16c5707SFrancisco Jerez nouveau_connector_set_encoder(connector, nv_encoder);
6345addcf0aSDave Airlie conn_status = connector_status_connected;
6355addcf0aSDave Airlie goto out;
636c16c5707SFrancisco Jerez }
637c16c5707SFrancisco Jerez
6380ed3165eSFrancisco Jerez detect_analog:
639cb75d97eSBen Skeggs nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG);
640f4053509SBen Skeggs if (!nv_encoder && !nouveau_tv_disable)
641cb75d97eSBen Skeggs nv_encoder = find_encoder(connector, DCB_OUTPUT_TV);
64284b8081cSFrancisco Jerez if (nv_encoder && force) {
6436ee73861SBen Skeggs struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
644d58ded76SJani Nikula const struct drm_encoder_helper_funcs *helper =
6456ee73861SBen Skeggs encoder->helper_private;
6466ee73861SBen Skeggs
6476ee73861SBen Skeggs if (helper->detect(encoder, connector) ==
6486ee73861SBen Skeggs connector_status_connected) {
6496ee73861SBen Skeggs nouveau_connector_set_encoder(connector, nv_encoder);
6505addcf0aSDave Airlie conn_status = connector_status_connected;
6515addcf0aSDave Airlie goto out;
6526ee73861SBen Skeggs }
6536ee73861SBen Skeggs }
6546ee73861SBen Skeggs
6555addcf0aSDave Airlie out:
65602bb7fe2SLyude Paul if (!nv_connector->edid)
65702bb7fe2SLyude Paul drm_dp_cec_unset_edid(&nv_connector->aux);
6585addcf0aSDave Airlie
6596833fb1eSLyude Paul pm_runtime_mark_last_busy(dev->dev);
6606833fb1eSLyude Paul pm_runtime_put_autosuspend(dev->dev);
6615addcf0aSDave Airlie
6625addcf0aSDave Airlie return conn_status;
6636ee73861SBen Skeggs }
6646ee73861SBen Skeggs
665d17f395cSBen Skeggs static enum drm_connector_status
nouveau_connector_detect_lvds(struct drm_connector * connector,bool force)666930a9e28SChris Wilson nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
667d17f395cSBen Skeggs {
668d17f395cSBen Skeggs struct drm_device *dev = connector->dev;
66977145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev);
670d17f395cSBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
671d17f395cSBen Skeggs struct nouveau_encoder *nv_encoder = NULL;
672f28e32d3SLyude Paul struct edid *edid = NULL;
673d17f395cSBen Skeggs enum drm_connector_status status = connector_status_disconnected;
674d17f395cSBen Skeggs
675cb75d97eSBen Skeggs nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
676d17f395cSBen Skeggs if (!nv_encoder)
677f28e32d3SLyude Paul goto out;
678d17f395cSBen Skeggs
679a6ed76d7SBen Skeggs /* Try retrieving EDID via DDC */
68077145f1cSBen Skeggs if (!drm->vbios.fp_no_ddc) {
681930a9e28SChris Wilson status = nouveau_connector_detect(connector, force);
682630f5122SAlexander Kapshuk if (status == connector_status_connected) {
683630f5122SAlexander Kapshuk edid = nv_connector->edid;
684d17f395cSBen Skeggs goto out;
685d17f395cSBen Skeggs }
686630f5122SAlexander Kapshuk }
687d17f395cSBen Skeggs
688a6ed76d7SBen Skeggs /* On some laptops (Sony, i'm looking at you) there appears to
689a6ed76d7SBen Skeggs * be no direct way of accessing the panel's EDID. The only
690a6ed76d7SBen Skeggs * option available to us appears to be to ask ACPI for help..
691a6ed76d7SBen Skeggs *
692a6ed76d7SBen Skeggs * It's important this check's before trying straps, one of the
693a6ed76d7SBen Skeggs * said manufacturer's laptops are configured in such a way
694a6ed76d7SBen Skeggs * the nouveau decides an entry in the VBIOS FP mode table is
695a6ed76d7SBen Skeggs * valid - it's not (rh#613284)
696a6ed76d7SBen Skeggs */
697a6ed76d7SBen Skeggs if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
698f28e32d3SLyude Paul edid = nouveau_acpi_edid(dev, connector);
699f28e32d3SLyude Paul if (edid) {
700a6ed76d7SBen Skeggs status = connector_status_connected;
701a6ed76d7SBen Skeggs goto out;
702a6ed76d7SBen Skeggs }
703a6ed76d7SBen Skeggs }
704a6ed76d7SBen Skeggs
705d17f395cSBen Skeggs /* If no EDID found above, and the VBIOS indicates a hardcoded
706d17f395cSBen Skeggs * modeline is avalilable for the panel, set it as the panel's
707d17f395cSBen Skeggs * native mode and exit.
708d17f395cSBen Skeggs */
70977145f1cSBen Skeggs if (nouveau_bios_fp_mode(dev, NULL) && (drm->vbios.fp_no_ddc ||
710d17f395cSBen Skeggs nv_encoder->dcb->lvdsconf.use_straps_for_mode)) {
711d17f395cSBen Skeggs status = connector_status_connected;
712d17f395cSBen Skeggs goto out;
713d17f395cSBen Skeggs }
714d17f395cSBen Skeggs
715d17f395cSBen Skeggs /* Still nothing, some VBIOS images have a hardcoded EDID block
716d17f395cSBen Skeggs * stored for the panel stored in them.
717d17f395cSBen Skeggs */
71877145f1cSBen Skeggs if (!drm->vbios.fp_no_ddc) {
719f28e32d3SLyude Paul edid = (struct edid *)nouveau_bios_embedded_edid(dev);
720d17f395cSBen Skeggs if (edid) {
721f28e32d3SLyude Paul edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
722f28e32d3SLyude Paul if (edid)
723d17f395cSBen Skeggs status = connector_status_connected;
724d17f395cSBen Skeggs }
725d17f395cSBen Skeggs }
726d17f395cSBen Skeggs
727d17f395cSBen Skeggs out:
728d17f395cSBen Skeggs #if defined(CONFIG_ACPI_BUTTON) || \
729d17f395cSBen Skeggs (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
730d17f395cSBen Skeggs if (status == connector_status_connected &&
731d17f395cSBen Skeggs !nouveau_ignorelid && !acpi_lid_open())
732d17f395cSBen Skeggs status = connector_status_unknown;
733d17f395cSBen Skeggs #endif
734d17f395cSBen Skeggs
735f28e32d3SLyude Paul nouveau_connector_set_edid(nv_connector, edid);
73655b94bb8SNatalia Petrova if (nv_encoder)
7373195c5f9SAlbert Damen nouveau_connector_set_encoder(connector, nv_encoder);
738d17f395cSBen Skeggs return status;
739d17f395cSBen Skeggs }
740d17f395cSBen Skeggs
7416ee73861SBen Skeggs static void
nouveau_connector_force(struct drm_connector * connector)7426ee73861SBen Skeggs nouveau_connector_force(struct drm_connector *connector)
7436ee73861SBen Skeggs {
74477145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(connector->dev);
745be079e97SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
7466ee73861SBen Skeggs struct nouveau_encoder *nv_encoder;
7476ee73861SBen Skeggs int type;
7486ee73861SBen Skeggs
749befb51e9SBen Skeggs if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
7506ee73861SBen Skeggs if (connector->force == DRM_FORCE_ON_DIGITAL)
751cb75d97eSBen Skeggs type = DCB_OUTPUT_TMDS;
7526ee73861SBen Skeggs else
753cb75d97eSBen Skeggs type = DCB_OUTPUT_ANALOG;
7546ee73861SBen Skeggs } else
755cb75d97eSBen Skeggs type = DCB_OUTPUT_ANY;
7566ee73861SBen Skeggs
757e19b20bbSBen Skeggs nv_encoder = find_encoder(connector, type);
7586ee73861SBen Skeggs if (!nv_encoder) {
75977145f1cSBen Skeggs NV_ERROR(drm, "can't find encoder to force %s on!\n",
7608c6c361aSJani Nikula connector->name);
7616ee73861SBen Skeggs return;
7626ee73861SBen Skeggs }
7636ee73861SBen Skeggs
7646ee73861SBen Skeggs nouveau_connector_set_encoder(connector, nv_encoder);
7656ee73861SBen Skeggs }
7666ee73861SBen Skeggs
7676ee73861SBen Skeggs static int
nouveau_connector_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t value)7686ee73861SBen Skeggs nouveau_connector_set_property(struct drm_connector *connector,
7696ee73861SBen Skeggs struct drm_property *property, uint64_t value)
7706ee73861SBen Skeggs {
7716ee73861SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
7726ee73861SBen Skeggs struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
77364d17f25SHans de Goede struct nouveau_conn_atom *asyc = &nv_connector->properties_state;
7744a9f822fSFrancisco Jerez struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
7756ee73861SBen Skeggs int ret;
7766ee73861SBen Skeggs
777616915ecSBen Skeggs ret = connector->funcs->atomic_set_property(&nv_connector->base,
778616915ecSBen Skeggs &asyc->state,
779616915ecSBen Skeggs property, value);
780616915ecSBen Skeggs if (ret) {
781cb75d97eSBen Skeggs if (nv_encoder && nv_encoder->dcb->type == DCB_OUTPUT_TV)
7824a9f822fSFrancisco Jerez return get_slave_funcs(encoder)->set_property(
7834a9f822fSFrancisco Jerez encoder, connector, property, value);
784616915ecSBen Skeggs return ret;
785616915ecSBen Skeggs }
7866ee73861SBen Skeggs
787616915ecSBen Skeggs nv_connector->scaling_mode = asyc->scaler.mode;
788616915ecSBen Skeggs nv_connector->dithering_mode = asyc->dither.mode;
789616915ecSBen Skeggs
790c2d926aaSBen Skeggs if (connector->encoder && connector->encoder->crtc) {
791c2d926aaSBen Skeggs ret = drm_crtc_helper_set_mode(connector->encoder->crtc,
792c2d926aaSBen Skeggs &connector->encoder->crtc->mode,
793c2d926aaSBen Skeggs connector->encoder->crtc->x,
794c2d926aaSBen Skeggs connector->encoder->crtc->y,
795c2d926aaSBen Skeggs NULL);
796616915ecSBen Skeggs if (!ret)
7976ee73861SBen Skeggs return -EINVAL;
798c2d926aaSBen Skeggs }
7996ee73861SBen Skeggs
800616915ecSBen Skeggs return 0;
8016ee73861SBen Skeggs }
8026ee73861SBen Skeggs
8036ee73861SBen Skeggs struct moderec {
8046ee73861SBen Skeggs int hdisplay;
8056ee73861SBen Skeggs int vdisplay;
8066ee73861SBen Skeggs };
8076ee73861SBen Skeggs
8086ee73861SBen Skeggs static struct moderec scaler_modes[] = {
8096ee73861SBen Skeggs { 1920, 1200 },
8106ee73861SBen Skeggs { 1920, 1080 },
8116ee73861SBen Skeggs { 1680, 1050 },
8126ee73861SBen Skeggs { 1600, 1200 },
8136ee73861SBen Skeggs { 1400, 1050 },
8146ee73861SBen Skeggs { 1280, 1024 },
8156ee73861SBen Skeggs { 1280, 960 },
8166ee73861SBen Skeggs { 1152, 864 },
8176ee73861SBen Skeggs { 1024, 768 },
8186ee73861SBen Skeggs { 800, 600 },
8196ee73861SBen Skeggs { 720, 400 },
8206ee73861SBen Skeggs { 640, 480 },
8216ee73861SBen Skeggs { 640, 400 },
8226ee73861SBen Skeggs { 640, 350 },
8236ee73861SBen Skeggs {}
8246ee73861SBen Skeggs };
8256ee73861SBen Skeggs
8266ee73861SBen Skeggs static int
nouveau_connector_scaler_modes_add(struct drm_connector * connector)8276ee73861SBen Skeggs nouveau_connector_scaler_modes_add(struct drm_connector *connector)
8286ee73861SBen Skeggs {
8296ee73861SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
8306ee73861SBen Skeggs struct drm_display_mode *native = nv_connector->native_mode, *m;
8316ee73861SBen Skeggs struct drm_device *dev = connector->dev;
8326ee73861SBen Skeggs struct moderec *mode = &scaler_modes[0];
8336ee73861SBen Skeggs int modes = 0;
8346ee73861SBen Skeggs
8356ee73861SBen Skeggs if (!native)
8366ee73861SBen Skeggs return 0;
8376ee73861SBen Skeggs
8386ee73861SBen Skeggs while (mode->hdisplay) {
8396ee73861SBen Skeggs if (mode->hdisplay <= native->hdisplay &&
840f0d15402SBen Skeggs mode->vdisplay <= native->vdisplay &&
841f0d15402SBen Skeggs (mode->hdisplay != native->hdisplay ||
842f0d15402SBen Skeggs mode->vdisplay != native->vdisplay)) {
8436ee73861SBen Skeggs m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay,
8446ee73861SBen Skeggs drm_mode_vrefresh(native), false,
8456ee73861SBen Skeggs false, false);
8466ee73861SBen Skeggs if (!m)
8476ee73861SBen Skeggs continue;
8486ee73861SBen Skeggs
8496ee73861SBen Skeggs drm_mode_probed_add(connector, m);
8506ee73861SBen Skeggs modes++;
8516ee73861SBen Skeggs }
8526ee73861SBen Skeggs
8536ee73861SBen Skeggs mode++;
8546ee73861SBen Skeggs }
8556ee73861SBen Skeggs
8566ee73861SBen Skeggs return modes;
8576ee73861SBen Skeggs }
8586ee73861SBen Skeggs
85963221755SBen Skeggs static void
nouveau_connector_detect_depth(struct drm_connector * connector)86063221755SBen Skeggs nouveau_connector_detect_depth(struct drm_connector *connector)
86163221755SBen Skeggs {
86277145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(connector->dev);
86363221755SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
86463221755SBen Skeggs struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
86577145f1cSBen Skeggs struct nvbios *bios = &drm->vbios;
86663221755SBen Skeggs struct drm_display_mode *mode = nv_connector->native_mode;
86763221755SBen Skeggs bool duallink;
86863221755SBen Skeggs
86963221755SBen Skeggs /* if the edid is feeling nice enough to provide this info, use it */
87063221755SBen Skeggs if (nv_connector->edid && connector->display_info.bpc)
87163221755SBen Skeggs return;
87263221755SBen Skeggs
873a6a17859SBen Skeggs /* EDID 1.4 is *supposed* to be supported on eDP, but, Apple... */
874a6a17859SBen Skeggs if (nv_connector->type == DCB_CONNECTOR_eDP) {
875a6a17859SBen Skeggs connector->display_info.bpc = 6;
876a6a17859SBen Skeggs return;
877a6a17859SBen Skeggs }
878a6a17859SBen Skeggs
879a6a17859SBen Skeggs /* we're out of options unless we're LVDS, default to 8bpc */
880cb75d97eSBen Skeggs if (nv_encoder->dcb->type != DCB_OUTPUT_LVDS) {
881c8435362SBen Skeggs connector->display_info.bpc = 8;
88263221755SBen Skeggs return;
883c8435362SBen Skeggs }
884c8435362SBen Skeggs
885c8435362SBen Skeggs connector->display_info.bpc = 6;
88663221755SBen Skeggs
88763221755SBen Skeggs /* LVDS: panel straps */
88863221755SBen Skeggs if (bios->fp_no_ddc) {
88963221755SBen Skeggs if (bios->fp.if_is_24bit)
89063221755SBen Skeggs connector->display_info.bpc = 8;
89163221755SBen Skeggs return;
89263221755SBen Skeggs }
89363221755SBen Skeggs
89463221755SBen Skeggs /* LVDS: DDC panel, need to first determine the number of links to
89563221755SBen Skeggs * know which if_is_24bit flag to check...
89663221755SBen Skeggs */
89763221755SBen Skeggs if (nv_connector->edid &&
898befb51e9SBen Skeggs nv_connector->type == DCB_CONNECTOR_LVDS_SPWG)
89963221755SBen Skeggs duallink = ((u8 *)nv_connector->edid)[121] == 2;
90063221755SBen Skeggs else
90163221755SBen Skeggs duallink = mode->clock >= bios->fp.duallink_transition_clk;
90263221755SBen Skeggs
90363221755SBen Skeggs if ((!duallink && (bios->fp.strapless_is_24bit & 1)) ||
90463221755SBen Skeggs ( duallink && (bios->fp.strapless_is_24bit & 2)))
90563221755SBen Skeggs connector->display_info.bpc = 8;
90663221755SBen Skeggs }
90763221755SBen Skeggs
9086ee73861SBen Skeggs static int
nouveau_connector_late_register(struct drm_connector * connector)9096d757753SLyude Paul nouveau_connector_late_register(struct drm_connector *connector)
9106d757753SLyude Paul {
9116d757753SLyude Paul int ret;
9126d757753SLyude Paul
9136d757753SLyude Paul ret = nouveau_backlight_init(connector);
914fd43ad9dSLyude Paul if (ret)
915fd43ad9dSLyude Paul return ret;
9166d757753SLyude Paul
917fd43ad9dSLyude Paul if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
918fd43ad9dSLyude Paul connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
919fd43ad9dSLyude Paul ret = drm_dp_aux_register(&nouveau_connector(connector)->aux);
920fd43ad9dSLyude Paul if (ret)
921fd43ad9dSLyude Paul goto backlight_fini;
922fd43ad9dSLyude Paul }
923fd43ad9dSLyude Paul
924fd43ad9dSLyude Paul return 0;
925fd43ad9dSLyude Paul backlight_fini:
926fd43ad9dSLyude Paul nouveau_backlight_fini(connector);
9276d757753SLyude Paul return ret;
9286d757753SLyude Paul }
9296d757753SLyude Paul
9306d757753SLyude Paul static void
nouveau_connector_early_unregister(struct drm_connector * connector)9316d757753SLyude Paul nouveau_connector_early_unregister(struct drm_connector *connector)
9326d757753SLyude Paul {
933fd43ad9dSLyude Paul if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
934fd43ad9dSLyude Paul connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
935fd43ad9dSLyude Paul drm_dp_aux_unregister(&nouveau_connector(connector)->aux);
936fd43ad9dSLyude Paul
937a4e05f41SLyude Paul nouveau_backlight_fini(connector);
9386d757753SLyude Paul }
9396d757753SLyude Paul
9406d757753SLyude Paul static int
nouveau_connector_get_modes(struct drm_connector * connector)9416ee73861SBen Skeggs nouveau_connector_get_modes(struct drm_connector *connector)
9426ee73861SBen Skeggs {
9436ee73861SBen Skeggs struct drm_device *dev = connector->dev;
94477145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev);
9456ee73861SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
9466ee73861SBen Skeggs struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
9474a9f822fSFrancisco Jerez struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
9486ee73861SBen Skeggs int ret = 0;
9496ee73861SBen Skeggs
950d17f395cSBen Skeggs /* destroy the native mode, the attached monitor could have changed.
9516ee73861SBen Skeggs */
952d17f395cSBen Skeggs if (nv_connector->native_mode) {
9536ee73861SBen Skeggs drm_mode_destroy(dev, nv_connector->native_mode);
9546ee73861SBen Skeggs nv_connector->native_mode = NULL;
9556ee73861SBen Skeggs }
9566ee73861SBen Skeggs
9576ee73861SBen Skeggs if (nv_connector->edid)
9586ee73861SBen Skeggs ret = drm_add_edid_modes(connector, nv_connector->edid);
959d17f395cSBen Skeggs else
960cb75d97eSBen Skeggs if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS &&
961d17f395cSBen Skeggs (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
96277145f1cSBen Skeggs drm->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
96380dad869SBen Skeggs struct drm_display_mode mode;
96480dad869SBen Skeggs
96580dad869SBen Skeggs nouveau_bios_fp_mode(dev, &mode);
96680dad869SBen Skeggs nv_connector->native_mode = drm_mode_duplicate(dev, &mode);
967d17f395cSBen Skeggs }
9686ee73861SBen Skeggs
969d4c2c99bSBen Skeggs /* Determine display colour depth for everything except LVDS now,
970d4c2c99bSBen Skeggs * DP requires this before mode_valid() is called.
971d4c2c99bSBen Skeggs */
972d5712cd2SKarol Herbst if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
973d4c2c99bSBen Skeggs nouveau_connector_detect_depth(connector);
974d4c2c99bSBen Skeggs
9756ee73861SBen Skeggs /* Find the native mode if this is a digital panel, if we didn't
9766ee73861SBen Skeggs * find any modes through DDC previously add the native mode to
9776ee73861SBen Skeggs * the list of modes.
9786ee73861SBen Skeggs */
9796ee73861SBen Skeggs if (!nv_connector->native_mode)
980616915ecSBen Skeggs nv_connector->native_mode = nouveau_conn_native_mode(connector);
9816ee73861SBen Skeggs if (ret == 0 && nv_connector->native_mode) {
9826ee73861SBen Skeggs struct drm_display_mode *mode;
9836ee73861SBen Skeggs
9846ee73861SBen Skeggs mode = drm_mode_duplicate(dev, nv_connector->native_mode);
985*744b229fSMa Ke if (!mode)
986*744b229fSMa Ke return 0;
987*744b229fSMa Ke
9886ee73861SBen Skeggs drm_mode_probed_add(connector, mode);
9896ee73861SBen Skeggs ret = 1;
9906ee73861SBen Skeggs }
9916ee73861SBen Skeggs
992d4c2c99bSBen Skeggs /* Determine LVDS colour depth, must happen after determining
993d4c2c99bSBen Skeggs * "native" mode as some VBIOS tables require us to use the
994d4c2c99bSBen Skeggs * pixel clock as part of the lookup...
99563221755SBen Skeggs */
99620a2ce87SNatalia Petrova if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS && nv_connector->native_mode)
99763221755SBen Skeggs nouveau_connector_detect_depth(connector);
99863221755SBen Skeggs
999cb75d97eSBen Skeggs if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
10004a9f822fSFrancisco Jerez ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
10016ee73861SBen Skeggs
1002befb51e9SBen Skeggs if (nv_connector->type == DCB_CONNECTOR_LVDS ||
1003befb51e9SBen Skeggs nv_connector->type == DCB_CONNECTOR_LVDS_SPWG ||
1004befb51e9SBen Skeggs nv_connector->type == DCB_CONNECTOR_eDP)
10056ee73861SBen Skeggs ret += nouveau_connector_scaler_modes_add(connector);
10066ee73861SBen Skeggs
10076ee73861SBen Skeggs return ret;
10086ee73861SBen Skeggs }
10096ee73861SBen Skeggs
10101f5bd443SFrancisco Jerez static unsigned
get_tmds_link_bandwidth(struct drm_connector * connector)10119340d77fSIlia Mirkin get_tmds_link_bandwidth(struct drm_connector *connector)
10121f5bd443SFrancisco Jerez {
10131f5bd443SFrancisco Jerez struct nouveau_connector *nv_connector = nouveau_connector(connector);
10149340d77fSIlia Mirkin struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
101577145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(connector->dev);
1016cb75d97eSBen Skeggs struct dcb_output *dcb = nv_connector->detected_encoder->dcb;
10179340d77fSIlia Mirkin struct drm_display_info *info = NULL;
1018d1084184SBen Skeggs unsigned duallink_scale =
10199340d77fSIlia Mirkin nouveau_duallink && nv_encoder->dcb->duallink_possible ? 2 : 1;
10201f5bd443SFrancisco Jerez
1021d1084184SBen Skeggs if (drm_detect_hdmi_monitor(nv_connector->edid)) {
10229340d77fSIlia Mirkin info = &nv_connector->base.display_info;
1023d1084184SBen Skeggs duallink_scale = 1;
1024d1084184SBen Skeggs }
10259340d77fSIlia Mirkin
10269340d77fSIlia Mirkin if (info) {
10271a0c96c0SIlia Mirkin if (nouveau_hdmimhz > 0)
10281a0c96c0SIlia Mirkin return nouveau_hdmimhz * 1000;
10291a0c96c0SIlia Mirkin /* Note: these limits are conservative, some Fermi's
10301a0c96c0SIlia Mirkin * can do 297 MHz. Unclear how this can be determined.
10311a0c96c0SIlia Mirkin */
10329340d77fSIlia Mirkin if (drm->client.device.info.chipset >= 0x120) {
10339340d77fSIlia Mirkin const int max_tmds_clock =
10349340d77fSIlia Mirkin info->hdmi.scdc.scrambling.supported ?
10359340d77fSIlia Mirkin 594000 : 340000;
10369340d77fSIlia Mirkin return info->max_tmds_clock ?
10379340d77fSIlia Mirkin min(info->max_tmds_clock, max_tmds_clock) :
10389340d77fSIlia Mirkin max_tmds_clock;
10399340d77fSIlia Mirkin }
10401167c6bcSBen Skeggs if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_KEPLER)
10411a0c96c0SIlia Mirkin return 297000;
10421167c6bcSBen Skeggs if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_FERMI)
10431a0c96c0SIlia Mirkin return 225000;
10441a0c96c0SIlia Mirkin }
1045d1084184SBen Skeggs
10461f5bd443SFrancisco Jerez if (dcb->location != DCB_LOC_ON_CHIP ||
10471167c6bcSBen Skeggs drm->client.device.info.chipset >= 0x46)
10489340d77fSIlia Mirkin return 165000 * duallink_scale;
10491167c6bcSBen Skeggs else if (drm->client.device.info.chipset >= 0x40)
10509340d77fSIlia Mirkin return 155000 * duallink_scale;
10511167c6bcSBen Skeggs else if (drm->client.device.info.chipset >= 0x18)
10529340d77fSIlia Mirkin return 135000 * duallink_scale;
10531f5bd443SFrancisco Jerez else
10549340d77fSIlia Mirkin return 112000 * duallink_scale;
10551f5bd443SFrancisco Jerez }
10561f5bd443SFrancisco Jerez
105754b202f1SLuc Van Oostenryck static enum drm_mode_status
nouveau_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)10586ee73861SBen Skeggs nouveau_connector_mode_valid(struct drm_connector *connector,
10596ee73861SBen Skeggs struct drm_display_mode *mode)
10606ee73861SBen Skeggs {
10616ee73861SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
10626ee73861SBen Skeggs struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
10634a9f822fSFrancisco Jerez struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
10642d831155SLyude Paul unsigned int min_clock = 25000, max_clock = min_clock, clock = mode->clock;
10656ee73861SBen Skeggs
10666ee73861SBen Skeggs switch (nv_encoder->dcb->type) {
1067cb75d97eSBen Skeggs case DCB_OUTPUT_LVDS:
106826099a74SBen Skeggs if (nv_connector->native_mode &&
106926099a74SBen Skeggs (mode->hdisplay > nv_connector->native_mode->hdisplay ||
107026099a74SBen Skeggs mode->vdisplay > nv_connector->native_mode->vdisplay))
10716ee73861SBen Skeggs return MODE_PANEL;
10726ee73861SBen Skeggs
10736ee73861SBen Skeggs min_clock = 0;
10746ee73861SBen Skeggs max_clock = 400000;
10756ee73861SBen Skeggs break;
1076cb75d97eSBen Skeggs case DCB_OUTPUT_TMDS:
10779340d77fSIlia Mirkin max_clock = get_tmds_link_bandwidth(connector);
10786ee73861SBen Skeggs break;
1079cb75d97eSBen Skeggs case DCB_OUTPUT_ANALOG:
10806ee73861SBen Skeggs max_clock = nv_encoder->dcb->crtconf.maxfreq;
10816ee73861SBen Skeggs if (!max_clock)
10826ee73861SBen Skeggs max_clock = 350000;
10836ee73861SBen Skeggs break;
1084cb75d97eSBen Skeggs case DCB_OUTPUT_TV:
10854a9f822fSFrancisco Jerez return get_slave_funcs(encoder)->mode_valid(encoder, mode);
1086cb75d97eSBen Skeggs case DCB_OUTPUT_DP:
1087949ab38aSKarol Herbst return nv50_dp_mode_valid(nv_encoder, mode, NULL);
1088e7cc51c5SBen Skeggs default:
1089af7db03eSBen Skeggs BUG();
1090e7cc51c5SBen Skeggs return MODE_BAD;
10916ee73861SBen Skeggs }
10926ee73861SBen Skeggs
10932d831155SLyude Paul if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
10942d831155SLyude Paul clock *= 2;
10952d831155SLyude Paul
10962d831155SLyude Paul if (clock < min_clock)
10972d831155SLyude Paul return MODE_CLOCK_LOW;
10982d831155SLyude Paul if (clock > max_clock)
10992d831155SLyude Paul return MODE_CLOCK_HIGH;
11002d831155SLyude Paul
11012d831155SLyude Paul return MODE_OK;
11026ee73861SBen Skeggs }
11036ee73861SBen Skeggs
11046ee73861SBen Skeggs static struct drm_encoder *
nouveau_connector_best_encoder(struct drm_connector * connector)11056ee73861SBen Skeggs nouveau_connector_best_encoder(struct drm_connector *connector)
11066ee73861SBen Skeggs {
11076ee73861SBen Skeggs struct nouveau_connector *nv_connector = nouveau_connector(connector);
11086ee73861SBen Skeggs
11096ee73861SBen Skeggs if (nv_connector->detected_encoder)
11106ee73861SBen Skeggs return to_drm_encoder(nv_connector->detected_encoder);
11116ee73861SBen Skeggs
11126ee73861SBen Skeggs return NULL;
11136ee73861SBen Skeggs }
11146ee73861SBen Skeggs
1115a76eb429SLyude Paul static int
nouveau_connector_atomic_check(struct drm_connector * connector,struct drm_atomic_state * state)1116a76eb429SLyude Paul nouveau_connector_atomic_check(struct drm_connector *connector, struct drm_atomic_state *state)
1117a76eb429SLyude Paul {
1118a76eb429SLyude Paul struct nouveau_connector *nv_conn = nouveau_connector(connector);
1119a76eb429SLyude Paul struct drm_connector_state *conn_state =
1120a76eb429SLyude Paul drm_atomic_get_new_connector_state(state, connector);
1121a76eb429SLyude Paul
1122a76eb429SLyude Paul if (!nv_conn->dp_encoder || !nv50_has_mst(nouveau_drm(connector->dev)))
1123a76eb429SLyude Paul return 0;
1124a76eb429SLyude Paul
1125a76eb429SLyude Paul return drm_dp_mst_root_conn_atomic_check(conn_state, &nv_conn->dp_encoder->dp.mstm->mgr);
1126a76eb429SLyude Paul }
1127a76eb429SLyude Paul
11286ee73861SBen Skeggs static const struct drm_connector_helper_funcs
11296ee73861SBen Skeggs nouveau_connector_helper_funcs = {
11306ee73861SBen Skeggs .get_modes = nouveau_connector_get_modes,
11316ee73861SBen Skeggs .mode_valid = nouveau_connector_mode_valid,
11326ee73861SBen Skeggs .best_encoder = nouveau_connector_best_encoder,
1133a76eb429SLyude Paul .atomic_check = nouveau_connector_atomic_check,
11346ee73861SBen Skeggs };
11356ee73861SBen Skeggs
11366ee73861SBen Skeggs static const struct drm_connector_funcs
11376ee73861SBen Skeggs nouveau_connector_funcs = {
11387d902c05SDaniel Vetter .dpms = drm_helper_connector_dpms,
1139616915ecSBen Skeggs .reset = nouveau_conn_reset,
11406ee73861SBen Skeggs .detect = nouveau_connector_detect,
1141616915ecSBen Skeggs .force = nouveau_connector_force,
11426ee73861SBen Skeggs .fill_modes = drm_helper_probe_single_connector_modes,
11436ee73861SBen Skeggs .set_property = nouveau_connector_set_property,
1144616915ecSBen Skeggs .destroy = nouveau_connector_destroy,
1145616915ecSBen Skeggs .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
1146616915ecSBen Skeggs .atomic_destroy_state = nouveau_conn_atomic_destroy_state,
1147616915ecSBen Skeggs .atomic_set_property = nouveau_conn_atomic_set_property,
1148616915ecSBen Skeggs .atomic_get_property = nouveau_conn_atomic_get_property,
11496d757753SLyude Paul .late_register = nouveau_connector_late_register,
11506d757753SLyude Paul .early_unregister = nouveau_connector_early_unregister,
11516ee73861SBen Skeggs };
11526ee73861SBen Skeggs
1153d17f395cSBen Skeggs static const struct drm_connector_funcs
1154d17f395cSBen Skeggs nouveau_connector_funcs_lvds = {
11557d902c05SDaniel Vetter .dpms = drm_helper_connector_dpms,
1156616915ecSBen Skeggs .reset = nouveau_conn_reset,
1157d17f395cSBen Skeggs .detect = nouveau_connector_detect_lvds,
1158616915ecSBen Skeggs .force = nouveau_connector_force,
1159d17f395cSBen Skeggs .fill_modes = drm_helper_probe_single_connector_modes,
1160d17f395cSBen Skeggs .set_property = nouveau_connector_set_property,
1161616915ecSBen Skeggs .destroy = nouveau_connector_destroy,
1162616915ecSBen Skeggs .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
1163616915ecSBen Skeggs .atomic_destroy_state = nouveau_conn_atomic_destroy_state,
1164616915ecSBen Skeggs .atomic_set_property = nouveau_conn_atomic_set_property,
1165616915ecSBen Skeggs .atomic_get_property = nouveau_conn_atomic_get_property,
11666d757753SLyude Paul .late_register = nouveau_connector_late_register,
11676d757753SLyude Paul .early_unregister = nouveau_connector_early_unregister,
1168d17f395cSBen Skeggs };
11696ee73861SBen Skeggs
1170d297ce4bSLyude Paul void
nouveau_connector_hpd(struct nouveau_connector * nv_connector,u64 bits)1171016dacb6SBen Skeggs nouveau_connector_hpd(struct nouveau_connector *nv_connector, u64 bits)
1172d297ce4bSLyude Paul {
1173016dacb6SBen Skeggs struct nouveau_drm *drm = nouveau_drm(nv_connector->base.dev);
1174016dacb6SBen Skeggs u32 mask = drm_connector_mask(&nv_connector->base);
1175d62f8e98SBen Skeggs unsigned long flags;
1176d297ce4bSLyude Paul
1177d62f8e98SBen Skeggs spin_lock_irqsave(&drm->hpd_lock, flags);
1178d297ce4bSLyude Paul if (!(drm->hpd_pending & mask)) {
1179016dacb6SBen Skeggs nv_connector->hpd_pending |= bits;
1180d297ce4bSLyude Paul drm->hpd_pending |= mask;
1181d297ce4bSLyude Paul schedule_work(&drm->hpd_work);
1182d297ce4bSLyude Paul }
1183d62f8e98SBen Skeggs spin_unlock_irqrestore(&drm->hpd_lock, flags);
1184d297ce4bSLyude Paul }
1185d297ce4bSLyude Paul
11869a69a9acSMaarten Lankhorst static int
nouveau_connector_irq(struct nvif_event * event,void * repv,u32 repc)1187773eb04dSBen Skeggs nouveau_connector_irq(struct nvif_event *event, void *repv, u32 repc)
11884f47643dSBen Skeggs {
1189773eb04dSBen Skeggs struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), irq);
119009e53065SLyude Paul
1191773eb04dSBen Skeggs schedule_work(&nv_connector->irq_work);
1192773eb04dSBen Skeggs return NVIF_EVENT_KEEP;
119309e53065SLyude Paul }
11943e1a1275SLyude Paul
1195773eb04dSBen Skeggs static int
nouveau_connector_hotplug(struct nvif_event * event,void * repv,u32 repc)1196773eb04dSBen Skeggs nouveau_connector_hotplug(struct nvif_event *event, void *repv, u32 repc)
1197773eb04dSBen Skeggs {
1198773eb04dSBen Skeggs struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), hpd);
1199773eb04dSBen Skeggs struct nvif_conn_event_v0 *rep = repv;
12003e1a1275SLyude Paul
1201773eb04dSBen Skeggs nouveau_connector_hpd(nv_connector, rep->types);
1202773eb04dSBen Skeggs return NVIF_EVENT_KEEP;
12034f47643dSBen Skeggs }
12044f47643dSBen Skeggs
12058894f491SBen Skeggs static ssize_t
nouveau_connector_aux_xfer(struct drm_dp_aux * obj,struct drm_dp_aux_msg * msg)12062aa5eac5SBen Skeggs nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg)
12078894f491SBen Skeggs {
12088894f491SBen Skeggs struct nouveau_connector *nv_connector =
12092aa5eac5SBen Skeggs container_of(obj, typeof(*nv_connector), aux);
12108894f491SBen Skeggs struct nouveau_encoder *nv_encoder;
12112aa5eac5SBen Skeggs struct nvkm_i2c_aux *aux;
12121af5c410SBen Skeggs u8 size = msg->size;
12138894f491SBen Skeggs int ret;
12148894f491SBen Skeggs
12158894f491SBen Skeggs nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
12162aa5eac5SBen Skeggs if (!nv_encoder || !(aux = nv_encoder->aux))
12178894f491SBen Skeggs return -ENODEV;
12188894f491SBen Skeggs if (WARN_ON(msg->size > 16))
12198894f491SBen Skeggs return -E2BIG;
12208894f491SBen Skeggs
12212aa5eac5SBen Skeggs ret = nvkm_i2c_aux_acquire(aux);
12228894f491SBen Skeggs if (ret)
12238894f491SBen Skeggs return ret;
12248894f491SBen Skeggs
12252aa5eac5SBen Skeggs ret = nvkm_i2c_aux_xfer(aux, false, msg->request, msg->address,
12261af5c410SBen Skeggs msg->buffer, &size);
12272aa5eac5SBen Skeggs nvkm_i2c_aux_release(aux);
12288894f491SBen Skeggs if (ret >= 0) {
12298894f491SBen Skeggs msg->reply = ret;
12301af5c410SBen Skeggs return size;
12318894f491SBen Skeggs }
12328894f491SBen Skeggs
12338894f491SBen Skeggs return ret;
12348894f491SBen Skeggs }
12358894f491SBen Skeggs
1236befb51e9SBen Skeggs static int
drm_conntype_from_dcb(enum dcb_connector_type dcb)1237befb51e9SBen Skeggs drm_conntype_from_dcb(enum dcb_connector_type dcb)
1238befb51e9SBen Skeggs {
1239befb51e9SBen Skeggs switch (dcb) {
1240befb51e9SBen Skeggs case DCB_CONNECTOR_VGA : return DRM_MODE_CONNECTOR_VGA;
1241befb51e9SBen Skeggs case DCB_CONNECTOR_TV_0 :
1242befb51e9SBen Skeggs case DCB_CONNECTOR_TV_1 :
1243befb51e9SBen Skeggs case DCB_CONNECTOR_TV_3 : return DRM_MODE_CONNECTOR_TV;
1244fa2c113aSBen Skeggs case DCB_CONNECTOR_DMS59_0 :
1245fa2c113aSBen Skeggs case DCB_CONNECTOR_DMS59_1 :
1246befb51e9SBen Skeggs case DCB_CONNECTOR_DVI_I : return DRM_MODE_CONNECTOR_DVII;
1247befb51e9SBen Skeggs case DCB_CONNECTOR_DVI_D : return DRM_MODE_CONNECTOR_DVID;
1248befb51e9SBen Skeggs case DCB_CONNECTOR_LVDS :
1249befb51e9SBen Skeggs case DCB_CONNECTOR_LVDS_SPWG: return DRM_MODE_CONNECTOR_LVDS;
12504abb410aSBen Skeggs case DCB_CONNECTOR_DMS59_DP0:
12514abb410aSBen Skeggs case DCB_CONNECTOR_DMS59_DP1:
12527919faabSBen Skeggs case DCB_CONNECTOR_DP :
1253d1f5a3fcSKarol Herbst case DCB_CONNECTOR_mDP :
12547919faabSBen Skeggs case DCB_CONNECTOR_USB_C : return DRM_MODE_CONNECTOR_DisplayPort;
1255befb51e9SBen Skeggs case DCB_CONNECTOR_eDP : return DRM_MODE_CONNECTOR_eDP;
1256befb51e9SBen Skeggs case DCB_CONNECTOR_HDMI_0 :
12576bd9293eSBen Skeggs case DCB_CONNECTOR_HDMI_1 :
12586bd9293eSBen Skeggs case DCB_CONNECTOR_HDMI_C : return DRM_MODE_CONNECTOR_HDMIA;
1259df00d5daSRosen Penev case DCB_CONNECTOR_WFD : return DRM_MODE_CONNECTOR_VIRTUAL;
1260befb51e9SBen Skeggs default:
1261befb51e9SBen Skeggs break;
1262befb51e9SBen Skeggs }
1263befb51e9SBen Skeggs
1264befb51e9SBen Skeggs return DRM_MODE_CONNECTOR_Unknown;
1265befb51e9SBen Skeggs }
1266befb51e9SBen Skeggs
12678f1a6086SBen Skeggs struct drm_connector *
nouveau_connector_create(struct drm_device * dev,const struct dcb_output * dcbe)12683c7fc252SLyude Paul nouveau_connector_create(struct drm_device *dev,
12693c7fc252SLyude Paul const struct dcb_output *dcbe)
12706ee73861SBen Skeggs {
1271d17f395cSBen Skeggs const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
127277145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev);
127377145f1cSBen Skeggs struct nouveau_display *disp = nouveau_display(dev);
12746ee73861SBen Skeggs struct nouveau_connector *nv_connector = NULL;
12756ee73861SBen Skeggs struct drm_connector *connector;
127622b76bbeSLyude Paul struct drm_connector_list_iter conn_iter;
12773c7fc252SLyude Paul char aux_name[48] = {0};
12783c7fc252SLyude Paul int index = dcbe->connector;
12792fa67f12SFrancisco Jerez int type, ret = 0;
1280befb51e9SBen Skeggs bool dummy;
12816ee73861SBen Skeggs
128222b76bbeSLyude Paul drm_connector_list_iter_begin(dev, &conn_iter);
128337afe55bSLyude Paul nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
1284befb51e9SBen Skeggs nv_connector = nouveau_connector(connector);
128522b76bbeSLyude Paul if (nv_connector->index == index) {
128622b76bbeSLyude Paul drm_connector_list_iter_end(&conn_iter);
1287befb51e9SBen Skeggs return connector;
12887f612d87SBen Skeggs }
128922b76bbeSLyude Paul }
129022b76bbeSLyude Paul drm_connector_list_iter_end(&conn_iter);
12917f612d87SBen Skeggs
12926ee73861SBen Skeggs nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
12936ee73861SBen Skeggs if (!nv_connector)
12948f1a6086SBen Skeggs return ERR_PTR(-ENOMEM);
1295befb51e9SBen Skeggs
12966ee73861SBen Skeggs connector = &nv_connector->base;
1297befb51e9SBen Skeggs nv_connector->index = index;
1298773eb04dSBen Skeggs INIT_WORK(&nv_connector->irq_work, nouveau_dp_irq);
1299befb51e9SBen Skeggs
1300befb51e9SBen Skeggs /* attempt to parse vbios connector type and hotplug gpio */
1301cb75d97eSBen Skeggs nv_connector->dcb = olddcb_conn(dev, index);
1302befb51e9SBen Skeggs if (nv_connector->dcb) {
1303befb51e9SBen Skeggs u32 entry = ROM16(nv_connector->dcb[0]);
1304cb75d97eSBen Skeggs if (olddcb_conntab(dev)[3] >= 4)
1305befb51e9SBen Skeggs entry |= (u32)ROM16(nv_connector->dcb[2]) << 16;
1306befb51e9SBen Skeggs
1307befb51e9SBen Skeggs nv_connector->type = nv_connector->dcb[0];
1308befb51e9SBen Skeggs if (drm_conntype_from_dcb(nv_connector->type) ==
1309befb51e9SBen Skeggs DRM_MODE_CONNECTOR_Unknown) {
131077145f1cSBen Skeggs NV_WARN(drm, "unknown connector type %02x\n",
1311befb51e9SBen Skeggs nv_connector->type);
1312befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_NONE;
1313befb51e9SBen Skeggs }
1314befb51e9SBen Skeggs
1315befb51e9SBen Skeggs /* Gigabyte NX85T */
1316befb51e9SBen Skeggs if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) {
1317befb51e9SBen Skeggs if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
1318befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_DVI_I;
1319befb51e9SBen Skeggs }
1320befb51e9SBen Skeggs
1321befb51e9SBen Skeggs /* Gigabyte GV-NX86T512H */
1322befb51e9SBen Skeggs if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) {
1323befb51e9SBen Skeggs if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
1324befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_DVI_I;
1325befb51e9SBen Skeggs }
1326befb51e9SBen Skeggs } else {
1327befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_NONE;
1328befb51e9SBen Skeggs }
1329befb51e9SBen Skeggs
1330befb51e9SBen Skeggs /* no vbios data, or an unknown dcb connector type - attempt to
1331befb51e9SBen Skeggs * figure out something suitable ourselves
1332befb51e9SBen Skeggs */
1333befb51e9SBen Skeggs if (nv_connector->type == DCB_CONNECTOR_NONE) {
133477145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev);
133577145f1cSBen Skeggs struct dcb_table *dcbt = &drm->vbios.dcb;
1336befb51e9SBen Skeggs u32 encoders = 0;
1337befb51e9SBen Skeggs int i;
1338befb51e9SBen Skeggs
1339befb51e9SBen Skeggs for (i = 0; i < dcbt->entries; i++) {
1340befb51e9SBen Skeggs if (dcbt->entry[i].connector == nv_connector->index)
1341befb51e9SBen Skeggs encoders |= (1 << dcbt->entry[i].type);
1342befb51e9SBen Skeggs }
1343befb51e9SBen Skeggs
1344cb75d97eSBen Skeggs if (encoders & (1 << DCB_OUTPUT_DP)) {
1345cb75d97eSBen Skeggs if (encoders & (1 << DCB_OUTPUT_TMDS))
1346befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_DP;
1347befb51e9SBen Skeggs else
1348befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_eDP;
1349befb51e9SBen Skeggs } else
1350cb75d97eSBen Skeggs if (encoders & (1 << DCB_OUTPUT_TMDS)) {
1351cb75d97eSBen Skeggs if (encoders & (1 << DCB_OUTPUT_ANALOG))
1352befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_DVI_I;
1353befb51e9SBen Skeggs else
1354befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_DVI_D;
1355befb51e9SBen Skeggs } else
1356cb75d97eSBen Skeggs if (encoders & (1 << DCB_OUTPUT_ANALOG)) {
1357befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_VGA;
1358befb51e9SBen Skeggs } else
1359cb75d97eSBen Skeggs if (encoders & (1 << DCB_OUTPUT_LVDS)) {
1360befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_LVDS;
1361befb51e9SBen Skeggs } else
1362cb75d97eSBen Skeggs if (encoders & (1 << DCB_OUTPUT_TV)) {
1363befb51e9SBen Skeggs nv_connector->type = DCB_CONNECTOR_TV_0;
1364befb51e9SBen Skeggs }
1365befb51e9SBen Skeggs }
1366befb51e9SBen Skeggs
13678894f491SBen Skeggs switch ((type = drm_conntype_from_dcb(nv_connector->type))) {
13688894f491SBen Skeggs case DRM_MODE_CONNECTOR_LVDS:
1369befb51e9SBen Skeggs ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy);
1370befb51e9SBen Skeggs if (ret) {
137177145f1cSBen Skeggs NV_ERROR(drm, "Error parsing LVDS table, disabling\n");
1372befb51e9SBen Skeggs kfree(nv_connector);
1373befb51e9SBen Skeggs return ERR_PTR(ret);
1374befb51e9SBen Skeggs }
1375befb51e9SBen Skeggs
1376befb51e9SBen Skeggs funcs = &nouveau_connector_funcs_lvds;
13778894f491SBen Skeggs break;
13788894f491SBen Skeggs case DRM_MODE_CONNECTOR_DisplayPort:
13798894f491SBen Skeggs case DRM_MODE_CONNECTOR_eDP:
13807713c0f1SLeo Li nv_connector->aux.dev = connector->kdev;
13816cba3fe4SLyude Paul nv_connector->aux.drm_dev = dev;
13828894f491SBen Skeggs nv_connector->aux.transfer = nouveau_connector_aux_xfer;
13833c7fc252SLyude Paul snprintf(aux_name, sizeof(aux_name), "sor-%04x-%04x",
13843c7fc252SLyude Paul dcbe->hasht, dcbe->hashm);
13853c7fc252SLyude Paul nv_connector->aux.name = kstrdup(aux_name, GFP_KERNEL);
1386ca0367caSLyude Paul if (!nv_connector->aux.name) {
13878894f491SBen Skeggs kfree(nv_connector);
1388ca0367caSLyude Paul return ERR_PTR(-ENOMEM);
13898894f491SBen Skeggs }
1390ca0367caSLyude Paul drm_dp_aux_init(&nv_connector->aux);
139111d27389SLyude Paul break;
13928894f491SBen Skeggs default:
13938894f491SBen Skeggs funcs = &nouveau_connector_funcs;
13948894f491SBen Skeggs break;
1395befb51e9SBen Skeggs }
13966ee73861SBen Skeggs
13970f18d276SAlastair Bridgewater /* HDMI 3D support */
13980d4a2c57SBen Skeggs if ((disp->disp.object.oclass >= G82_DISP)
13990f18d276SAlastair Bridgewater && ((type == DRM_MODE_CONNECTOR_DisplayPort)
14000f18d276SAlastair Bridgewater || (type == DRM_MODE_CONNECTOR_eDP)
14010f18d276SAlastair Bridgewater || (type == DRM_MODE_CONNECTOR_HDMIA)))
14020f18d276SAlastair Bridgewater connector->stereo_allowed = true;
14030f18d276SAlastair Bridgewater
14046ee73861SBen Skeggs /* defaults, will get overridden in detect() */
14056ee73861SBen Skeggs connector->interlace_allowed = false;
14066ee73861SBen Skeggs connector->doublescan_allowed = false;
14076ee73861SBen Skeggs
1408d17f395cSBen Skeggs drm_connector_init(dev, connector, funcs, type);
14096ee73861SBen Skeggs drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
1410773eb04dSBen Skeggs connector->polled = DRM_CONNECTOR_POLL_CONNECT;
14116ee73861SBen Skeggs
141295983aeaSBen Skeggs if (nv_connector->dcb && (disp->disp.conn_mask & BIT(nv_connector->index))) {
141395983aeaSBen Skeggs ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index,
141495983aeaSBen Skeggs &nv_connector->conn);
141595983aeaSBen Skeggs if (ret) {
14161b254b79SKarol Herbst goto drm_conn_err;
141795983aeaSBen Skeggs }
1418773eb04dSBen Skeggs
1419773eb04dSBen Skeggs ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsHotplug",
1420773eb04dSBen Skeggs nouveau_connector_hotplug,
1421773eb04dSBen Skeggs NVIF_CONN_EVENT_V0_PLUG | NVIF_CONN_EVENT_V0_UNPLUG,
1422773eb04dSBen Skeggs &nv_connector->hpd);
1423773eb04dSBen Skeggs if (ret == 0)
1424773eb04dSBen Skeggs connector->polled = DRM_CONNECTOR_POLL_HPD;
1425773eb04dSBen Skeggs
1426773eb04dSBen Skeggs if (nv_connector->aux.transfer) {
1427773eb04dSBen Skeggs ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsDpIrq",
1428773eb04dSBen Skeggs nouveau_connector_irq, NVIF_CONN_EVENT_V0_IRQ,
1429773eb04dSBen Skeggs &nv_connector->irq);
1430773eb04dSBen Skeggs if (ret) {
1431773eb04dSBen Skeggs nvif_event_dtor(&nv_connector->hpd);
1432773eb04dSBen Skeggs nvif_conn_dtor(&nv_connector->conn);
14331b254b79SKarol Herbst goto drm_conn_err;
1434773eb04dSBen Skeggs }
1435773eb04dSBen Skeggs }
143695983aeaSBen Skeggs }
143795983aeaSBen Skeggs
143856182b8bSBen Skeggs connector->funcs->reset(connector);
143956182b8bSBen Skeggs nouveau_conn_attach_properties(connector);
14406ee73861SBen Skeggs
144156182b8bSBen Skeggs /* Default scaling mode */
1442befb51e9SBen Skeggs switch (nv_connector->type) {
14430ea5fe8aSBen Skeggs case DCB_CONNECTOR_LVDS:
14440ea5fe8aSBen Skeggs case DCB_CONNECTOR_LVDS_SPWG:
14450ea5fe8aSBen Skeggs case DCB_CONNECTOR_eDP:
14460ea5fe8aSBen Skeggs /* see note in nouveau_connector_set_property() */
14470d4a2c57SBen Skeggs if (disp->disp.object.oclass < NV50_DISP) {
14480ea5fe8aSBen Skeggs nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
14490ea5fe8aSBen Skeggs break;
14500ea5fe8aSBen Skeggs }
1451be079e97SBen Skeggs nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
1452be079e97SBen Skeggs break;
1453be079e97SBen Skeggs default:
14540ea5fe8aSBen Skeggs nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
14557d95216eSBen Skeggs break;
14567d95216eSBen Skeggs }
1457be079e97SBen Skeggs
14587d95216eSBen Skeggs /* dithering properties */
14597d95216eSBen Skeggs switch (nv_connector->type) {
14607d95216eSBen Skeggs case DCB_CONNECTOR_TV_0:
14617d95216eSBen Skeggs case DCB_CONNECTOR_TV_1:
14627d95216eSBen Skeggs case DCB_CONNECTOR_TV_3:
14637d95216eSBen Skeggs case DCB_CONNECTOR_VGA:
14647d95216eSBen Skeggs break;
14657d95216eSBen Skeggs default:
146638bdcfc1SBen Skeggs nv_connector->dithering_mode = DITHERING_MODE_AUTO;
1467be079e97SBen Skeggs break;
14686ee73861SBen Skeggs }
14696ee73861SBen Skeggs
147046094b2bSHans Verkuil switch (type) {
147146094b2bSHans Verkuil case DRM_MODE_CONNECTOR_DisplayPort:
147211d27389SLyude Paul nv_connector->dp_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
147311d27389SLyude Paul fallthrough;
147446094b2bSHans Verkuil case DRM_MODE_CONNECTOR_eDP:
1475ae85b0dfSDariusz Marcinkiewicz drm_dp_cec_register_connector(&nv_connector->aux, connector);
147646094b2bSHans Verkuil break;
147746094b2bSHans Verkuil }
147846094b2bSHans Verkuil
147934ea3d38SThomas Wood drm_connector_register(connector);
1480befb51e9SBen Skeggs return connector;
14811b254b79SKarol Herbst
14821b254b79SKarol Herbst drm_conn_err:
14831b254b79SKarol Herbst drm_connector_cleanup(connector);
14841b254b79SKarol Herbst kfree(nv_connector);
14851b254b79SKarol Herbst return ERR_PTR(ret);
14866ee73861SBen Skeggs }
1487