1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2008 Maarten Maathuis.
3*4882a593Smuzhiyun * All Rights Reserved.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining
6*4882a593Smuzhiyun * a copy of this software and associated documentation files (the
7*4882a593Smuzhiyun * "Software"), to deal in the Software without restriction, including
8*4882a593Smuzhiyun * without limitation the rights to use, copy, modify, merge, publish,
9*4882a593Smuzhiyun * distribute, sublicense, and/or sell copies of the Software, and to
10*4882a593Smuzhiyun * permit persons to whom the Software is furnished to do so, subject to
11*4882a593Smuzhiyun * the following conditions:
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * The above copyright notice and this permission notice (including the
14*4882a593Smuzhiyun * next paragraph) shall be included in all copies or substantial
15*4882a593Smuzhiyun * portions of the Software.
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18*4882a593Smuzhiyun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19*4882a593Smuzhiyun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20*4882a593Smuzhiyun * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21*4882a593Smuzhiyun * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22*4882a593Smuzhiyun * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23*4882a593Smuzhiyun * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun */
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include <acpi/button.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #include <linux/pm_runtime.h>
30*4882a593Smuzhiyun #include <linux/vga_switcheroo.h>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #include <drm/drm_atomic_helper.h>
33*4882a593Smuzhiyun #include <drm/drm_edid.h>
34*4882a593Smuzhiyun #include <drm/drm_crtc_helper.h>
35*4882a593Smuzhiyun #include <drm/drm_probe_helper.h>
36*4882a593Smuzhiyun #include <drm/drm_atomic.h>
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #include "nouveau_reg.h"
39*4882a593Smuzhiyun #include "nouveau_drv.h"
40*4882a593Smuzhiyun #include "dispnv04/hw.h"
41*4882a593Smuzhiyun #include "dispnv50/disp.h"
42*4882a593Smuzhiyun #include "nouveau_acpi.h"
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #include "nouveau_display.h"
45*4882a593Smuzhiyun #include "nouveau_connector.h"
46*4882a593Smuzhiyun #include "nouveau_encoder.h"
47*4882a593Smuzhiyun #include "nouveau_crtc.h"
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #include <nvif/class.h>
50*4882a593Smuzhiyun #include <nvif/cl0046.h>
51*4882a593Smuzhiyun #include <nvif/event.h>
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun struct drm_display_mode *
nouveau_conn_native_mode(struct drm_connector * connector)54*4882a593Smuzhiyun nouveau_conn_native_mode(struct drm_connector *connector)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun const struct drm_connector_helper_funcs *helper = connector->helper_private;
57*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(connector->dev);
58*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
59*4882a593Smuzhiyun struct drm_display_mode *mode, *largest = NULL;
60*4882a593Smuzhiyun int high_w = 0, high_h = 0, high_v = 0;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun list_for_each_entry(mode, &connector->probed_modes, head) {
63*4882a593Smuzhiyun if (helper->mode_valid(connector, mode) != MODE_OK ||
64*4882a593Smuzhiyun (mode->flags & DRM_MODE_FLAG_INTERLACE))
65*4882a593Smuzhiyun continue;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* Use preferred mode if there is one.. */
68*4882a593Smuzhiyun if (mode->type & DRM_MODE_TYPE_PREFERRED) {
69*4882a593Smuzhiyun NV_DEBUG(drm, "native mode from preferred\n");
70*4882a593Smuzhiyun return drm_mode_duplicate(dev, mode);
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* Otherwise, take the resolution with the largest width, then
74*4882a593Smuzhiyun * height, then vertical refresh
75*4882a593Smuzhiyun */
76*4882a593Smuzhiyun if (mode->hdisplay < high_w)
77*4882a593Smuzhiyun continue;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun if (mode->hdisplay == high_w && mode->vdisplay < high_h)
80*4882a593Smuzhiyun continue;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun if (mode->hdisplay == high_w && mode->vdisplay == high_h &&
83*4882a593Smuzhiyun drm_mode_vrefresh(mode) < high_v)
84*4882a593Smuzhiyun continue;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun high_w = mode->hdisplay;
87*4882a593Smuzhiyun high_h = mode->vdisplay;
88*4882a593Smuzhiyun high_v = drm_mode_vrefresh(mode);
89*4882a593Smuzhiyun largest = mode;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun NV_DEBUG(drm, "native mode from largest: %dx%d@%d\n",
93*4882a593Smuzhiyun high_w, high_h, high_v);
94*4882a593Smuzhiyun return largest ? drm_mode_duplicate(dev, largest) : NULL;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun int
nouveau_conn_atomic_get_property(struct drm_connector * connector,const struct drm_connector_state * state,struct drm_property * property,u64 * val)98*4882a593Smuzhiyun nouveau_conn_atomic_get_property(struct drm_connector *connector,
99*4882a593Smuzhiyun const struct drm_connector_state *state,
100*4882a593Smuzhiyun struct drm_property *property, u64 *val)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun struct nouveau_conn_atom *asyc = nouveau_conn_atom(state);
103*4882a593Smuzhiyun struct nouveau_display *disp = nouveau_display(connector->dev);
104*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (property == dev->mode_config.scaling_mode_property)
107*4882a593Smuzhiyun *val = asyc->scaler.mode;
108*4882a593Smuzhiyun else if (property == disp->underscan_property)
109*4882a593Smuzhiyun *val = asyc->scaler.underscan.mode;
110*4882a593Smuzhiyun else if (property == disp->underscan_hborder_property)
111*4882a593Smuzhiyun *val = asyc->scaler.underscan.hborder;
112*4882a593Smuzhiyun else if (property == disp->underscan_vborder_property)
113*4882a593Smuzhiyun *val = asyc->scaler.underscan.vborder;
114*4882a593Smuzhiyun else if (property == disp->dithering_mode)
115*4882a593Smuzhiyun *val = asyc->dither.mode;
116*4882a593Smuzhiyun else if (property == disp->dithering_depth)
117*4882a593Smuzhiyun *val = asyc->dither.depth;
118*4882a593Smuzhiyun else if (property == disp->vibrant_hue_property)
119*4882a593Smuzhiyun *val = asyc->procamp.vibrant_hue;
120*4882a593Smuzhiyun else if (property == disp->color_vibrance_property)
121*4882a593Smuzhiyun *val = asyc->procamp.color_vibrance;
122*4882a593Smuzhiyun else
123*4882a593Smuzhiyun return -EINVAL;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun return 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun int
nouveau_conn_atomic_set_property(struct drm_connector * connector,struct drm_connector_state * state,struct drm_property * property,u64 val)129*4882a593Smuzhiyun nouveau_conn_atomic_set_property(struct drm_connector *connector,
130*4882a593Smuzhiyun struct drm_connector_state *state,
131*4882a593Smuzhiyun struct drm_property *property, u64 val)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
134*4882a593Smuzhiyun struct nouveau_conn_atom *asyc = nouveau_conn_atom(state);
135*4882a593Smuzhiyun struct nouveau_display *disp = nouveau_display(dev);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (property == dev->mode_config.scaling_mode_property) {
138*4882a593Smuzhiyun switch (val) {
139*4882a593Smuzhiyun case DRM_MODE_SCALE_NONE:
140*4882a593Smuzhiyun /* We allow 'None' for EDID modes, even on a fixed
141*4882a593Smuzhiyun * panel (some exist with support for lower refresh
142*4882a593Smuzhiyun * rates, which people might want to use for power-
143*4882a593Smuzhiyun * saving purposes).
144*4882a593Smuzhiyun *
145*4882a593Smuzhiyun * Non-EDID modes will force the use of GPU scaling
146*4882a593Smuzhiyun * to the native mode regardless of this setting.
147*4882a593Smuzhiyun */
148*4882a593Smuzhiyun switch (connector->connector_type) {
149*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_LVDS:
150*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_eDP:
151*4882a593Smuzhiyun /* ... except prior to G80, where the code
152*4882a593Smuzhiyun * doesn't support such things.
153*4882a593Smuzhiyun */
154*4882a593Smuzhiyun if (disp->disp.object.oclass < NV50_DISP)
155*4882a593Smuzhiyun return -EINVAL;
156*4882a593Smuzhiyun break;
157*4882a593Smuzhiyun default:
158*4882a593Smuzhiyun break;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun case DRM_MODE_SCALE_FULLSCREEN:
161*4882a593Smuzhiyun case DRM_MODE_SCALE_CENTER:
162*4882a593Smuzhiyun case DRM_MODE_SCALE_ASPECT:
163*4882a593Smuzhiyun break;
164*4882a593Smuzhiyun default:
165*4882a593Smuzhiyun return -EINVAL;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun if (asyc->scaler.mode != val) {
169*4882a593Smuzhiyun asyc->scaler.mode = val;
170*4882a593Smuzhiyun asyc->set.scaler = true;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun } else
173*4882a593Smuzhiyun if (property == disp->underscan_property) {
174*4882a593Smuzhiyun if (asyc->scaler.underscan.mode != val) {
175*4882a593Smuzhiyun asyc->scaler.underscan.mode = val;
176*4882a593Smuzhiyun asyc->set.scaler = true;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun } else
179*4882a593Smuzhiyun if (property == disp->underscan_hborder_property) {
180*4882a593Smuzhiyun if (asyc->scaler.underscan.hborder != val) {
181*4882a593Smuzhiyun asyc->scaler.underscan.hborder = val;
182*4882a593Smuzhiyun asyc->set.scaler = true;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun } else
185*4882a593Smuzhiyun if (property == disp->underscan_vborder_property) {
186*4882a593Smuzhiyun if (asyc->scaler.underscan.vborder != val) {
187*4882a593Smuzhiyun asyc->scaler.underscan.vborder = val;
188*4882a593Smuzhiyun asyc->set.scaler = true;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun } else
191*4882a593Smuzhiyun if (property == disp->dithering_mode) {
192*4882a593Smuzhiyun if (asyc->dither.mode != val) {
193*4882a593Smuzhiyun asyc->dither.mode = val;
194*4882a593Smuzhiyun asyc->set.dither = true;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun } else
197*4882a593Smuzhiyun if (property == disp->dithering_depth) {
198*4882a593Smuzhiyun if (asyc->dither.mode != val) {
199*4882a593Smuzhiyun asyc->dither.depth = val;
200*4882a593Smuzhiyun asyc->set.dither = true;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun } else
203*4882a593Smuzhiyun if (property == disp->vibrant_hue_property) {
204*4882a593Smuzhiyun if (asyc->procamp.vibrant_hue != val) {
205*4882a593Smuzhiyun asyc->procamp.vibrant_hue = val;
206*4882a593Smuzhiyun asyc->set.procamp = true;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun } else
209*4882a593Smuzhiyun if (property == disp->color_vibrance_property) {
210*4882a593Smuzhiyun if (asyc->procamp.color_vibrance != val) {
211*4882a593Smuzhiyun asyc->procamp.color_vibrance = val;
212*4882a593Smuzhiyun asyc->set.procamp = true;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun } else {
215*4882a593Smuzhiyun return -EINVAL;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun return 0;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun void
nouveau_conn_atomic_destroy_state(struct drm_connector * connector,struct drm_connector_state * state)222*4882a593Smuzhiyun nouveau_conn_atomic_destroy_state(struct drm_connector *connector,
223*4882a593Smuzhiyun struct drm_connector_state *state)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun struct nouveau_conn_atom *asyc = nouveau_conn_atom(state);
226*4882a593Smuzhiyun __drm_atomic_helper_connector_destroy_state(&asyc->state);
227*4882a593Smuzhiyun kfree(asyc);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun struct drm_connector_state *
nouveau_conn_atomic_duplicate_state(struct drm_connector * connector)231*4882a593Smuzhiyun nouveau_conn_atomic_duplicate_state(struct drm_connector *connector)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state);
234*4882a593Smuzhiyun struct nouveau_conn_atom *asyc;
235*4882a593Smuzhiyun if (!(asyc = kmalloc(sizeof(*asyc), GFP_KERNEL)))
236*4882a593Smuzhiyun return NULL;
237*4882a593Smuzhiyun __drm_atomic_helper_connector_duplicate_state(connector, &asyc->state);
238*4882a593Smuzhiyun asyc->dither = armc->dither;
239*4882a593Smuzhiyun asyc->scaler = armc->scaler;
240*4882a593Smuzhiyun asyc->procamp = armc->procamp;
241*4882a593Smuzhiyun asyc->set.mask = 0;
242*4882a593Smuzhiyun return &asyc->state;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun void
nouveau_conn_reset(struct drm_connector * connector)246*4882a593Smuzhiyun nouveau_conn_reset(struct drm_connector *connector)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
249*4882a593Smuzhiyun struct nouveau_conn_atom *asyc;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun if (drm_drv_uses_atomic_modeset(connector->dev)) {
252*4882a593Smuzhiyun if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL))))
253*4882a593Smuzhiyun return;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun if (connector->state)
256*4882a593Smuzhiyun nouveau_conn_atomic_destroy_state(connector,
257*4882a593Smuzhiyun connector->state);
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun __drm_atomic_helper_connector_reset(connector, &asyc->state);
260*4882a593Smuzhiyun } else {
261*4882a593Smuzhiyun asyc = &nv_connector->properties_state;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun asyc->dither.mode = DITHERING_MODE_AUTO;
265*4882a593Smuzhiyun asyc->dither.depth = DITHERING_DEPTH_AUTO;
266*4882a593Smuzhiyun asyc->scaler.mode = DRM_MODE_SCALE_NONE;
267*4882a593Smuzhiyun asyc->scaler.underscan.mode = UNDERSCAN_OFF;
268*4882a593Smuzhiyun asyc->procamp.color_vibrance = 150;
269*4882a593Smuzhiyun asyc->procamp.vibrant_hue = 90;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun if (nouveau_display(connector->dev)->disp.object.oclass < NV50_DISP) {
272*4882a593Smuzhiyun switch (connector->connector_type) {
273*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_LVDS:
274*4882a593Smuzhiyun /* See note in nouveau_conn_atomic_set_property(). */
275*4882a593Smuzhiyun asyc->scaler.mode = DRM_MODE_SCALE_FULLSCREEN;
276*4882a593Smuzhiyun break;
277*4882a593Smuzhiyun default:
278*4882a593Smuzhiyun break;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun void
nouveau_conn_attach_properties(struct drm_connector * connector)284*4882a593Smuzhiyun nouveau_conn_attach_properties(struct drm_connector *connector)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
287*4882a593Smuzhiyun struct nouveau_display *disp = nouveau_display(dev);
288*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
289*4882a593Smuzhiyun struct nouveau_conn_atom *armc;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (drm_drv_uses_atomic_modeset(connector->dev))
292*4882a593Smuzhiyun armc = nouveau_conn_atom(connector->state);
293*4882a593Smuzhiyun else
294*4882a593Smuzhiyun armc = &nv_connector->properties_state;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /* Init DVI-I specific properties. */
297*4882a593Smuzhiyun if (connector->connector_type == DRM_MODE_CONNECTOR_DVII)
298*4882a593Smuzhiyun drm_object_attach_property(&connector->base, dev->mode_config.
299*4882a593Smuzhiyun dvi_i_subconnector_property, 0);
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* Add overscan compensation options to digital outputs. */
302*4882a593Smuzhiyun if (disp->underscan_property &&
303*4882a593Smuzhiyun (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
304*4882a593Smuzhiyun connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
305*4882a593Smuzhiyun connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
306*4882a593Smuzhiyun connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)) {
307*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
308*4882a593Smuzhiyun disp->underscan_property,
309*4882a593Smuzhiyun UNDERSCAN_OFF);
310*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
311*4882a593Smuzhiyun disp->underscan_hborder_property, 0);
312*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
313*4882a593Smuzhiyun disp->underscan_vborder_property, 0);
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun /* Add hue and saturation options. */
317*4882a593Smuzhiyun if (disp->vibrant_hue_property)
318*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
319*4882a593Smuzhiyun disp->vibrant_hue_property,
320*4882a593Smuzhiyun armc->procamp.vibrant_hue);
321*4882a593Smuzhiyun if (disp->color_vibrance_property)
322*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
323*4882a593Smuzhiyun disp->color_vibrance_property,
324*4882a593Smuzhiyun armc->procamp.color_vibrance);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /* Scaling mode property. */
327*4882a593Smuzhiyun switch (connector->connector_type) {
328*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_TV:
329*4882a593Smuzhiyun break;
330*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_VGA:
331*4882a593Smuzhiyun if (disp->disp.object.oclass < NV50_DISP)
332*4882a593Smuzhiyun break; /* Can only scale on DFPs. */
333*4882a593Smuzhiyun fallthrough;
334*4882a593Smuzhiyun default:
335*4882a593Smuzhiyun drm_object_attach_property(&connector->base, dev->mode_config.
336*4882a593Smuzhiyun scaling_mode_property,
337*4882a593Smuzhiyun armc->scaler.mode);
338*4882a593Smuzhiyun break;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun /* Dithering properties. */
342*4882a593Smuzhiyun switch (connector->connector_type) {
343*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_TV:
344*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_VGA:
345*4882a593Smuzhiyun break;
346*4882a593Smuzhiyun default:
347*4882a593Smuzhiyun if (disp->dithering_mode) {
348*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
349*4882a593Smuzhiyun disp->dithering_mode,
350*4882a593Smuzhiyun armc->dither.mode);
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun if (disp->dithering_depth) {
353*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
354*4882a593Smuzhiyun disp->dithering_depth,
355*4882a593Smuzhiyun armc->dither.depth);
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun break;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
362*4882a593Smuzhiyun int nouveau_tv_disable = 0;
363*4882a593Smuzhiyun module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
366*4882a593Smuzhiyun int nouveau_ignorelid = 0;
367*4882a593Smuzhiyun module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)");
370*4882a593Smuzhiyun int nouveau_duallink = 1;
371*4882a593Smuzhiyun module_param_named(duallink, nouveau_duallink, int, 0400);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun MODULE_PARM_DESC(hdmimhz, "Force a maximum HDMI pixel clock (in MHz)");
374*4882a593Smuzhiyun int nouveau_hdmimhz = 0;
375*4882a593Smuzhiyun module_param_named(hdmimhz, nouveau_hdmimhz, int, 0400);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun struct nouveau_encoder *
find_encoder(struct drm_connector * connector,int type)378*4882a593Smuzhiyun find_encoder(struct drm_connector *connector, int type)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder;
381*4882a593Smuzhiyun struct drm_encoder *enc;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun drm_connector_for_each_possible_encoder(connector, enc) {
384*4882a593Smuzhiyun nv_encoder = nouveau_encoder(enc);
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun if (type == DCB_OUTPUT_ANY ||
387*4882a593Smuzhiyun (nv_encoder->dcb && nv_encoder->dcb->type == type))
388*4882a593Smuzhiyun return nv_encoder;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun return NULL;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun static void
nouveau_connector_destroy(struct drm_connector * connector)395*4882a593Smuzhiyun nouveau_connector_destroy(struct drm_connector *connector)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
398*4882a593Smuzhiyun nvif_notify_dtor(&nv_connector->hpd);
399*4882a593Smuzhiyun kfree(nv_connector->edid);
400*4882a593Smuzhiyun drm_connector_unregister(connector);
401*4882a593Smuzhiyun drm_connector_cleanup(connector);
402*4882a593Smuzhiyun if (nv_connector->aux.transfer) {
403*4882a593Smuzhiyun drm_dp_cec_unregister_connector(&nv_connector->aux);
404*4882a593Smuzhiyun drm_dp_aux_unregister(&nv_connector->aux);
405*4882a593Smuzhiyun kfree(nv_connector->aux.name);
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun kfree(connector);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun static struct nouveau_encoder *
nouveau_connector_ddc_detect(struct drm_connector * connector)411*4882a593Smuzhiyun nouveau_connector_ddc_detect(struct drm_connector *connector)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
414*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder = NULL, *found = NULL;
415*4882a593Smuzhiyun struct drm_encoder *encoder;
416*4882a593Smuzhiyun int ret;
417*4882a593Smuzhiyun bool switcheroo_ddc = false;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun drm_connector_for_each_possible_encoder(connector, encoder) {
420*4882a593Smuzhiyun nv_encoder = nouveau_encoder(encoder);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun switch (nv_encoder->dcb->type) {
423*4882a593Smuzhiyun case DCB_OUTPUT_DP:
424*4882a593Smuzhiyun ret = nouveau_dp_detect(nouveau_connector(connector),
425*4882a593Smuzhiyun nv_encoder);
426*4882a593Smuzhiyun if (ret == NOUVEAU_DP_MST)
427*4882a593Smuzhiyun return NULL;
428*4882a593Smuzhiyun else if (ret == NOUVEAU_DP_SST)
429*4882a593Smuzhiyun found = nv_encoder;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun break;
432*4882a593Smuzhiyun case DCB_OUTPUT_LVDS:
433*4882a593Smuzhiyun switcheroo_ddc = !!(vga_switcheroo_handler_flags() &
434*4882a593Smuzhiyun VGA_SWITCHEROO_CAN_SWITCH_DDC);
435*4882a593Smuzhiyun fallthrough;
436*4882a593Smuzhiyun default:
437*4882a593Smuzhiyun if (!nv_encoder->i2c)
438*4882a593Smuzhiyun break;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if (switcheroo_ddc)
441*4882a593Smuzhiyun vga_switcheroo_lock_ddc(dev->pdev);
442*4882a593Smuzhiyun if (nvkm_probe_i2c(nv_encoder->i2c, 0x50))
443*4882a593Smuzhiyun found = nv_encoder;
444*4882a593Smuzhiyun if (switcheroo_ddc)
445*4882a593Smuzhiyun vga_switcheroo_unlock_ddc(dev->pdev);
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun break;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun if (found)
450*4882a593Smuzhiyun break;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun return found;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun static struct nouveau_encoder *
nouveau_connector_of_detect(struct drm_connector * connector)457*4882a593Smuzhiyun nouveau_connector_of_detect(struct drm_connector *connector)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun #ifdef __powerpc__
460*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
461*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
462*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder;
463*4882a593Smuzhiyun struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun if (!dn ||
466*4882a593Smuzhiyun !((nv_encoder = find_encoder(connector, DCB_OUTPUT_TMDS)) ||
467*4882a593Smuzhiyun (nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG))))
468*4882a593Smuzhiyun return NULL;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun for_each_child_of_node(dn, cn) {
471*4882a593Smuzhiyun const char *name = of_get_property(cn, "name", NULL);
472*4882a593Smuzhiyun const void *edid = of_get_property(cn, "EDID", NULL);
473*4882a593Smuzhiyun int idx = name ? name[strlen(name) - 1] - 'A' : 0;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun if (nv_encoder->dcb->i2c_index == idx && edid) {
476*4882a593Smuzhiyun nv_connector->edid =
477*4882a593Smuzhiyun kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
478*4882a593Smuzhiyun of_node_put(cn);
479*4882a593Smuzhiyun return nv_encoder;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun #endif
483*4882a593Smuzhiyun return NULL;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun static void
nouveau_connector_set_encoder(struct drm_connector * connector,struct nouveau_encoder * nv_encoder)487*4882a593Smuzhiyun nouveau_connector_set_encoder(struct drm_connector *connector,
488*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
491*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(connector->dev);
492*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun if (nv_connector->detected_encoder == nv_encoder)
495*4882a593Smuzhiyun return;
496*4882a593Smuzhiyun nv_connector->detected_encoder = nv_encoder;
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
499*4882a593Smuzhiyun if (nv_encoder->dcb->type == DCB_OUTPUT_DP)
500*4882a593Smuzhiyun connector->interlace_allowed =
501*4882a593Smuzhiyun nv_encoder->caps.dp_interlace;
502*4882a593Smuzhiyun else
503*4882a593Smuzhiyun connector->interlace_allowed =
504*4882a593Smuzhiyun drm->client.device.info.family < NV_DEVICE_INFO_V0_VOLTA;
505*4882a593Smuzhiyun connector->doublescan_allowed = true;
506*4882a593Smuzhiyun } else
507*4882a593Smuzhiyun if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS ||
508*4882a593Smuzhiyun nv_encoder->dcb->type == DCB_OUTPUT_TMDS) {
509*4882a593Smuzhiyun connector->doublescan_allowed = false;
510*4882a593Smuzhiyun connector->interlace_allowed = false;
511*4882a593Smuzhiyun } else {
512*4882a593Smuzhiyun connector->doublescan_allowed = true;
513*4882a593Smuzhiyun if (drm->client.device.info.family == NV_DEVICE_INFO_V0_KELVIN ||
514*4882a593Smuzhiyun (drm->client.device.info.family == NV_DEVICE_INFO_V0_CELSIUS &&
515*4882a593Smuzhiyun (dev->pdev->device & 0x0ff0) != 0x0100 &&
516*4882a593Smuzhiyun (dev->pdev->device & 0x0ff0) != 0x0150))
517*4882a593Smuzhiyun /* HW is broken */
518*4882a593Smuzhiyun connector->interlace_allowed = false;
519*4882a593Smuzhiyun else
520*4882a593Smuzhiyun connector->interlace_allowed = true;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
524*4882a593Smuzhiyun drm_object_property_set_value(&connector->base,
525*4882a593Smuzhiyun dev->mode_config.dvi_i_subconnector_property,
526*4882a593Smuzhiyun nv_encoder->dcb->type == DCB_OUTPUT_TMDS ?
527*4882a593Smuzhiyun DRM_MODE_SUBCONNECTOR_DVID :
528*4882a593Smuzhiyun DRM_MODE_SUBCONNECTOR_DVIA);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun static void
nouveau_connector_set_edid(struct nouveau_connector * nv_connector,struct edid * edid)533*4882a593Smuzhiyun nouveau_connector_set_edid(struct nouveau_connector *nv_connector,
534*4882a593Smuzhiyun struct edid *edid)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun if (nv_connector->edid != edid) {
537*4882a593Smuzhiyun struct edid *old_edid = nv_connector->edid;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun drm_connector_update_edid_property(&nv_connector->base, edid);
540*4882a593Smuzhiyun kfree(old_edid);
541*4882a593Smuzhiyun nv_connector->edid = edid;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun static enum drm_connector_status
nouveau_connector_detect(struct drm_connector * connector,bool force)546*4882a593Smuzhiyun nouveau_connector_detect(struct drm_connector *connector, bool force)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
549*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(dev);
550*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
551*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder = NULL;
552*4882a593Smuzhiyun struct nouveau_encoder *nv_partner;
553*4882a593Smuzhiyun struct i2c_adapter *i2c;
554*4882a593Smuzhiyun int type;
555*4882a593Smuzhiyun int ret;
556*4882a593Smuzhiyun enum drm_connector_status conn_status = connector_status_disconnected;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun /* Outputs are only polled while runtime active, so resuming the
559*4882a593Smuzhiyun * device here is unnecessary (and would deadlock upon runtime suspend
560*4882a593Smuzhiyun * because it waits for polling to finish). We do however, want to
561*4882a593Smuzhiyun * prevent the autosuspend timer from elapsing during this operation
562*4882a593Smuzhiyun * if possible.
563*4882a593Smuzhiyun */
564*4882a593Smuzhiyun if (drm_kms_helper_is_poll_worker()) {
565*4882a593Smuzhiyun pm_runtime_get_noresume(dev->dev);
566*4882a593Smuzhiyun } else {
567*4882a593Smuzhiyun ret = pm_runtime_get_sync(dev->dev);
568*4882a593Smuzhiyun if (ret < 0 && ret != -EACCES) {
569*4882a593Smuzhiyun pm_runtime_put_autosuspend(dev->dev);
570*4882a593Smuzhiyun nouveau_connector_set_edid(nv_connector, NULL);
571*4882a593Smuzhiyun return conn_status;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun nv_encoder = nouveau_connector_ddc_detect(connector);
576*4882a593Smuzhiyun if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
577*4882a593Smuzhiyun struct edid *new_edid;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun if ((vga_switcheroo_handler_flags() &
580*4882a593Smuzhiyun VGA_SWITCHEROO_CAN_SWITCH_DDC) &&
581*4882a593Smuzhiyun nv_connector->type == DCB_CONNECTOR_LVDS)
582*4882a593Smuzhiyun new_edid = drm_get_edid_switcheroo(connector, i2c);
583*4882a593Smuzhiyun else
584*4882a593Smuzhiyun new_edid = drm_get_edid(connector, i2c);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun nouveau_connector_set_edid(nv_connector, new_edid);
587*4882a593Smuzhiyun if (!nv_connector->edid) {
588*4882a593Smuzhiyun NV_ERROR(drm, "DDC responded, but no EDID for %s\n",
589*4882a593Smuzhiyun connector->name);
590*4882a593Smuzhiyun goto detect_analog;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun /* Override encoder type for DVI-I based on whether EDID
594*4882a593Smuzhiyun * says the display is digital or analog, both use the
595*4882a593Smuzhiyun * same i2c channel so the value returned from ddc_detect
596*4882a593Smuzhiyun * isn't necessarily correct.
597*4882a593Smuzhiyun */
598*4882a593Smuzhiyun nv_partner = NULL;
599*4882a593Smuzhiyun if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS)
600*4882a593Smuzhiyun nv_partner = find_encoder(connector, DCB_OUTPUT_ANALOG);
601*4882a593Smuzhiyun if (nv_encoder->dcb->type == DCB_OUTPUT_ANALOG)
602*4882a593Smuzhiyun nv_partner = find_encoder(connector, DCB_OUTPUT_TMDS);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun if (nv_partner && ((nv_encoder->dcb->type == DCB_OUTPUT_ANALOG &&
605*4882a593Smuzhiyun nv_partner->dcb->type == DCB_OUTPUT_TMDS) ||
606*4882a593Smuzhiyun (nv_encoder->dcb->type == DCB_OUTPUT_TMDS &&
607*4882a593Smuzhiyun nv_partner->dcb->type == DCB_OUTPUT_ANALOG))) {
608*4882a593Smuzhiyun if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
609*4882a593Smuzhiyun type = DCB_OUTPUT_TMDS;
610*4882a593Smuzhiyun else
611*4882a593Smuzhiyun type = DCB_OUTPUT_ANALOG;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun nv_encoder = find_encoder(connector, type);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun nouveau_connector_set_encoder(connector, nv_encoder);
617*4882a593Smuzhiyun conn_status = connector_status_connected;
618*4882a593Smuzhiyun drm_dp_cec_set_edid(&nv_connector->aux, nv_connector->edid);
619*4882a593Smuzhiyun goto out;
620*4882a593Smuzhiyun } else {
621*4882a593Smuzhiyun nouveau_connector_set_edid(nv_connector, NULL);
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun nv_encoder = nouveau_connector_of_detect(connector);
625*4882a593Smuzhiyun if (nv_encoder) {
626*4882a593Smuzhiyun nouveau_connector_set_encoder(connector, nv_encoder);
627*4882a593Smuzhiyun conn_status = connector_status_connected;
628*4882a593Smuzhiyun goto out;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun detect_analog:
632*4882a593Smuzhiyun nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG);
633*4882a593Smuzhiyun if (!nv_encoder && !nouveau_tv_disable)
634*4882a593Smuzhiyun nv_encoder = find_encoder(connector, DCB_OUTPUT_TV);
635*4882a593Smuzhiyun if (nv_encoder && force) {
636*4882a593Smuzhiyun struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
637*4882a593Smuzhiyun const struct drm_encoder_helper_funcs *helper =
638*4882a593Smuzhiyun encoder->helper_private;
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun if (helper->detect(encoder, connector) ==
641*4882a593Smuzhiyun connector_status_connected) {
642*4882a593Smuzhiyun nouveau_connector_set_encoder(connector, nv_encoder);
643*4882a593Smuzhiyun conn_status = connector_status_connected;
644*4882a593Smuzhiyun goto out;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun out:
649*4882a593Smuzhiyun if (!nv_connector->edid)
650*4882a593Smuzhiyun drm_dp_cec_unset_edid(&nv_connector->aux);
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun pm_runtime_mark_last_busy(dev->dev);
653*4882a593Smuzhiyun pm_runtime_put_autosuspend(dev->dev);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun return conn_status;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun static enum drm_connector_status
nouveau_connector_detect_lvds(struct drm_connector * connector,bool force)659*4882a593Smuzhiyun nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
660*4882a593Smuzhiyun {
661*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
662*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(dev);
663*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
664*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder = NULL;
665*4882a593Smuzhiyun struct edid *edid = NULL;
666*4882a593Smuzhiyun enum drm_connector_status status = connector_status_disconnected;
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
669*4882a593Smuzhiyun if (!nv_encoder)
670*4882a593Smuzhiyun goto out;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun /* Try retrieving EDID via DDC */
673*4882a593Smuzhiyun if (!drm->vbios.fp_no_ddc) {
674*4882a593Smuzhiyun status = nouveau_connector_detect(connector, force);
675*4882a593Smuzhiyun if (status == connector_status_connected) {
676*4882a593Smuzhiyun edid = nv_connector->edid;
677*4882a593Smuzhiyun goto out;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun /* On some laptops (Sony, i'm looking at you) there appears to
682*4882a593Smuzhiyun * be no direct way of accessing the panel's EDID. The only
683*4882a593Smuzhiyun * option available to us appears to be to ask ACPI for help..
684*4882a593Smuzhiyun *
685*4882a593Smuzhiyun * It's important this check's before trying straps, one of the
686*4882a593Smuzhiyun * said manufacturer's laptops are configured in such a way
687*4882a593Smuzhiyun * the nouveau decides an entry in the VBIOS FP mode table is
688*4882a593Smuzhiyun * valid - it's not (rh#613284)
689*4882a593Smuzhiyun */
690*4882a593Smuzhiyun if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
691*4882a593Smuzhiyun edid = nouveau_acpi_edid(dev, connector);
692*4882a593Smuzhiyun if (edid) {
693*4882a593Smuzhiyun status = connector_status_connected;
694*4882a593Smuzhiyun goto out;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun /* If no EDID found above, and the VBIOS indicates a hardcoded
699*4882a593Smuzhiyun * modeline is avalilable for the panel, set it as the panel's
700*4882a593Smuzhiyun * native mode and exit.
701*4882a593Smuzhiyun */
702*4882a593Smuzhiyun if (nouveau_bios_fp_mode(dev, NULL) && (drm->vbios.fp_no_ddc ||
703*4882a593Smuzhiyun nv_encoder->dcb->lvdsconf.use_straps_for_mode)) {
704*4882a593Smuzhiyun status = connector_status_connected;
705*4882a593Smuzhiyun goto out;
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun /* Still nothing, some VBIOS images have a hardcoded EDID block
709*4882a593Smuzhiyun * stored for the panel stored in them.
710*4882a593Smuzhiyun */
711*4882a593Smuzhiyun if (!drm->vbios.fp_no_ddc) {
712*4882a593Smuzhiyun edid = (struct edid *)nouveau_bios_embedded_edid(dev);
713*4882a593Smuzhiyun if (edid) {
714*4882a593Smuzhiyun edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
715*4882a593Smuzhiyun if (edid)
716*4882a593Smuzhiyun status = connector_status_connected;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun out:
721*4882a593Smuzhiyun #if defined(CONFIG_ACPI_BUTTON) || \
722*4882a593Smuzhiyun (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
723*4882a593Smuzhiyun if (status == connector_status_connected &&
724*4882a593Smuzhiyun !nouveau_ignorelid && !acpi_lid_open())
725*4882a593Smuzhiyun status = connector_status_unknown;
726*4882a593Smuzhiyun #endif
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun nouveau_connector_set_edid(nv_connector, edid);
729*4882a593Smuzhiyun nouveau_connector_set_encoder(connector, nv_encoder);
730*4882a593Smuzhiyun return status;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun static void
nouveau_connector_force(struct drm_connector * connector)734*4882a593Smuzhiyun nouveau_connector_force(struct drm_connector *connector)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(connector->dev);
737*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
738*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder;
739*4882a593Smuzhiyun int type;
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
742*4882a593Smuzhiyun if (connector->force == DRM_FORCE_ON_DIGITAL)
743*4882a593Smuzhiyun type = DCB_OUTPUT_TMDS;
744*4882a593Smuzhiyun else
745*4882a593Smuzhiyun type = DCB_OUTPUT_ANALOG;
746*4882a593Smuzhiyun } else
747*4882a593Smuzhiyun type = DCB_OUTPUT_ANY;
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun nv_encoder = find_encoder(connector, type);
750*4882a593Smuzhiyun if (!nv_encoder) {
751*4882a593Smuzhiyun NV_ERROR(drm, "can't find encoder to force %s on!\n",
752*4882a593Smuzhiyun connector->name);
753*4882a593Smuzhiyun connector->status = connector_status_disconnected;
754*4882a593Smuzhiyun return;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun nouveau_connector_set_encoder(connector, nv_encoder);
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun static int
nouveau_connector_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t value)761*4882a593Smuzhiyun nouveau_connector_set_property(struct drm_connector *connector,
762*4882a593Smuzhiyun struct drm_property *property, uint64_t value)
763*4882a593Smuzhiyun {
764*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
765*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
766*4882a593Smuzhiyun struct nouveau_conn_atom *asyc = &nv_connector->properties_state;
767*4882a593Smuzhiyun struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
768*4882a593Smuzhiyun int ret;
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun ret = connector->funcs->atomic_set_property(&nv_connector->base,
771*4882a593Smuzhiyun &asyc->state,
772*4882a593Smuzhiyun property, value);
773*4882a593Smuzhiyun if (ret) {
774*4882a593Smuzhiyun if (nv_encoder && nv_encoder->dcb->type == DCB_OUTPUT_TV)
775*4882a593Smuzhiyun return get_slave_funcs(encoder)->set_property(
776*4882a593Smuzhiyun encoder, connector, property, value);
777*4882a593Smuzhiyun return ret;
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun nv_connector->scaling_mode = asyc->scaler.mode;
781*4882a593Smuzhiyun nv_connector->dithering_mode = asyc->dither.mode;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun if (connector->encoder && connector->encoder->crtc) {
784*4882a593Smuzhiyun ret = drm_crtc_helper_set_mode(connector->encoder->crtc,
785*4882a593Smuzhiyun &connector->encoder->crtc->mode,
786*4882a593Smuzhiyun connector->encoder->crtc->x,
787*4882a593Smuzhiyun connector->encoder->crtc->y,
788*4882a593Smuzhiyun NULL);
789*4882a593Smuzhiyun if (!ret)
790*4882a593Smuzhiyun return -EINVAL;
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun return 0;
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun struct moderec {
797*4882a593Smuzhiyun int hdisplay;
798*4882a593Smuzhiyun int vdisplay;
799*4882a593Smuzhiyun };
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun static struct moderec scaler_modes[] = {
802*4882a593Smuzhiyun { 1920, 1200 },
803*4882a593Smuzhiyun { 1920, 1080 },
804*4882a593Smuzhiyun { 1680, 1050 },
805*4882a593Smuzhiyun { 1600, 1200 },
806*4882a593Smuzhiyun { 1400, 1050 },
807*4882a593Smuzhiyun { 1280, 1024 },
808*4882a593Smuzhiyun { 1280, 960 },
809*4882a593Smuzhiyun { 1152, 864 },
810*4882a593Smuzhiyun { 1024, 768 },
811*4882a593Smuzhiyun { 800, 600 },
812*4882a593Smuzhiyun { 720, 400 },
813*4882a593Smuzhiyun { 640, 480 },
814*4882a593Smuzhiyun { 640, 400 },
815*4882a593Smuzhiyun { 640, 350 },
816*4882a593Smuzhiyun {}
817*4882a593Smuzhiyun };
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun static int
nouveau_connector_scaler_modes_add(struct drm_connector * connector)820*4882a593Smuzhiyun nouveau_connector_scaler_modes_add(struct drm_connector *connector)
821*4882a593Smuzhiyun {
822*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
823*4882a593Smuzhiyun struct drm_display_mode *native = nv_connector->native_mode, *m;
824*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
825*4882a593Smuzhiyun struct moderec *mode = &scaler_modes[0];
826*4882a593Smuzhiyun int modes = 0;
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun if (!native)
829*4882a593Smuzhiyun return 0;
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun while (mode->hdisplay) {
832*4882a593Smuzhiyun if (mode->hdisplay <= native->hdisplay &&
833*4882a593Smuzhiyun mode->vdisplay <= native->vdisplay &&
834*4882a593Smuzhiyun (mode->hdisplay != native->hdisplay ||
835*4882a593Smuzhiyun mode->vdisplay != native->vdisplay)) {
836*4882a593Smuzhiyun m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay,
837*4882a593Smuzhiyun drm_mode_vrefresh(native), false,
838*4882a593Smuzhiyun false, false);
839*4882a593Smuzhiyun if (!m)
840*4882a593Smuzhiyun continue;
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun drm_mode_probed_add(connector, m);
843*4882a593Smuzhiyun modes++;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun mode++;
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun return modes;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun static void
nouveau_connector_detect_depth(struct drm_connector * connector)853*4882a593Smuzhiyun nouveau_connector_detect_depth(struct drm_connector *connector)
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(connector->dev);
856*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
857*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
858*4882a593Smuzhiyun struct nvbios *bios = &drm->vbios;
859*4882a593Smuzhiyun struct drm_display_mode *mode = nv_connector->native_mode;
860*4882a593Smuzhiyun bool duallink;
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun /* if the edid is feeling nice enough to provide this info, use it */
863*4882a593Smuzhiyun if (nv_connector->edid && connector->display_info.bpc)
864*4882a593Smuzhiyun return;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun /* EDID 1.4 is *supposed* to be supported on eDP, but, Apple... */
867*4882a593Smuzhiyun if (nv_connector->type == DCB_CONNECTOR_eDP) {
868*4882a593Smuzhiyun connector->display_info.bpc = 6;
869*4882a593Smuzhiyun return;
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun /* we're out of options unless we're LVDS, default to 8bpc */
873*4882a593Smuzhiyun if (nv_encoder->dcb->type != DCB_OUTPUT_LVDS) {
874*4882a593Smuzhiyun connector->display_info.bpc = 8;
875*4882a593Smuzhiyun return;
876*4882a593Smuzhiyun }
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun connector->display_info.bpc = 6;
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun /* LVDS: panel straps */
881*4882a593Smuzhiyun if (bios->fp_no_ddc) {
882*4882a593Smuzhiyun if (bios->fp.if_is_24bit)
883*4882a593Smuzhiyun connector->display_info.bpc = 8;
884*4882a593Smuzhiyun return;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun /* LVDS: DDC panel, need to first determine the number of links to
888*4882a593Smuzhiyun * know which if_is_24bit flag to check...
889*4882a593Smuzhiyun */
890*4882a593Smuzhiyun if (nv_connector->edid &&
891*4882a593Smuzhiyun nv_connector->type == DCB_CONNECTOR_LVDS_SPWG)
892*4882a593Smuzhiyun duallink = ((u8 *)nv_connector->edid)[121] == 2;
893*4882a593Smuzhiyun else
894*4882a593Smuzhiyun duallink = mode->clock >= bios->fp.duallink_transition_clk;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun if ((!duallink && (bios->fp.strapless_is_24bit & 1)) ||
897*4882a593Smuzhiyun ( duallink && (bios->fp.strapless_is_24bit & 2)))
898*4882a593Smuzhiyun connector->display_info.bpc = 8;
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun static int
nouveau_connector_late_register(struct drm_connector * connector)902*4882a593Smuzhiyun nouveau_connector_late_register(struct drm_connector *connector)
903*4882a593Smuzhiyun {
904*4882a593Smuzhiyun int ret;
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun ret = nouveau_backlight_init(connector);
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun return ret;
909*4882a593Smuzhiyun }
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun static void
nouveau_connector_early_unregister(struct drm_connector * connector)912*4882a593Smuzhiyun nouveau_connector_early_unregister(struct drm_connector *connector)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun nouveau_backlight_fini(connector);
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun static int
nouveau_connector_get_modes(struct drm_connector * connector)918*4882a593Smuzhiyun nouveau_connector_get_modes(struct drm_connector *connector)
919*4882a593Smuzhiyun {
920*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
921*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(dev);
922*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
923*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
924*4882a593Smuzhiyun struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
925*4882a593Smuzhiyun int ret = 0;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun /* destroy the native mode, the attached monitor could have changed.
928*4882a593Smuzhiyun */
929*4882a593Smuzhiyun if (nv_connector->native_mode) {
930*4882a593Smuzhiyun drm_mode_destroy(dev, nv_connector->native_mode);
931*4882a593Smuzhiyun nv_connector->native_mode = NULL;
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun if (nv_connector->edid)
935*4882a593Smuzhiyun ret = drm_add_edid_modes(connector, nv_connector->edid);
936*4882a593Smuzhiyun else
937*4882a593Smuzhiyun if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS &&
938*4882a593Smuzhiyun (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
939*4882a593Smuzhiyun drm->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
940*4882a593Smuzhiyun struct drm_display_mode mode;
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun nouveau_bios_fp_mode(dev, &mode);
943*4882a593Smuzhiyun nv_connector->native_mode = drm_mode_duplicate(dev, &mode);
944*4882a593Smuzhiyun }
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun /* Determine display colour depth for everything except LVDS now,
947*4882a593Smuzhiyun * DP requires this before mode_valid() is called.
948*4882a593Smuzhiyun */
949*4882a593Smuzhiyun if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
950*4882a593Smuzhiyun nouveau_connector_detect_depth(connector);
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun /* Find the native mode if this is a digital panel, if we didn't
953*4882a593Smuzhiyun * find any modes through DDC previously add the native mode to
954*4882a593Smuzhiyun * the list of modes.
955*4882a593Smuzhiyun */
956*4882a593Smuzhiyun if (!nv_connector->native_mode)
957*4882a593Smuzhiyun nv_connector->native_mode = nouveau_conn_native_mode(connector);
958*4882a593Smuzhiyun if (ret == 0 && nv_connector->native_mode) {
959*4882a593Smuzhiyun struct drm_display_mode *mode;
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun mode = drm_mode_duplicate(dev, nv_connector->native_mode);
962*4882a593Smuzhiyun drm_mode_probed_add(connector, mode);
963*4882a593Smuzhiyun ret = 1;
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun /* Determine LVDS colour depth, must happen after determining
967*4882a593Smuzhiyun * "native" mode as some VBIOS tables require us to use the
968*4882a593Smuzhiyun * pixel clock as part of the lookup...
969*4882a593Smuzhiyun */
970*4882a593Smuzhiyun if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
971*4882a593Smuzhiyun nouveau_connector_detect_depth(connector);
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
974*4882a593Smuzhiyun ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun if (nv_connector->type == DCB_CONNECTOR_LVDS ||
977*4882a593Smuzhiyun nv_connector->type == DCB_CONNECTOR_LVDS_SPWG ||
978*4882a593Smuzhiyun nv_connector->type == DCB_CONNECTOR_eDP)
979*4882a593Smuzhiyun ret += nouveau_connector_scaler_modes_add(connector);
980*4882a593Smuzhiyun
981*4882a593Smuzhiyun return ret;
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun static unsigned
get_tmds_link_bandwidth(struct drm_connector * connector)985*4882a593Smuzhiyun get_tmds_link_bandwidth(struct drm_connector *connector)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
988*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
989*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(connector->dev);
990*4882a593Smuzhiyun struct dcb_output *dcb = nv_connector->detected_encoder->dcb;
991*4882a593Smuzhiyun struct drm_display_info *info = NULL;
992*4882a593Smuzhiyun unsigned duallink_scale =
993*4882a593Smuzhiyun nouveau_duallink && nv_encoder->dcb->duallink_possible ? 2 : 1;
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun if (drm_detect_hdmi_monitor(nv_connector->edid)) {
996*4882a593Smuzhiyun info = &nv_connector->base.display_info;
997*4882a593Smuzhiyun duallink_scale = 1;
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun if (info) {
1001*4882a593Smuzhiyun if (nouveau_hdmimhz > 0)
1002*4882a593Smuzhiyun return nouveau_hdmimhz * 1000;
1003*4882a593Smuzhiyun /* Note: these limits are conservative, some Fermi's
1004*4882a593Smuzhiyun * can do 297 MHz. Unclear how this can be determined.
1005*4882a593Smuzhiyun */
1006*4882a593Smuzhiyun if (drm->client.device.info.chipset >= 0x120) {
1007*4882a593Smuzhiyun const int max_tmds_clock =
1008*4882a593Smuzhiyun info->hdmi.scdc.scrambling.supported ?
1009*4882a593Smuzhiyun 594000 : 340000;
1010*4882a593Smuzhiyun return info->max_tmds_clock ?
1011*4882a593Smuzhiyun min(info->max_tmds_clock, max_tmds_clock) :
1012*4882a593Smuzhiyun max_tmds_clock;
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_KEPLER)
1015*4882a593Smuzhiyun return 297000;
1016*4882a593Smuzhiyun if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_FERMI)
1017*4882a593Smuzhiyun return 225000;
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun if (dcb->location != DCB_LOC_ON_CHIP ||
1021*4882a593Smuzhiyun drm->client.device.info.chipset >= 0x46)
1022*4882a593Smuzhiyun return 165000 * duallink_scale;
1023*4882a593Smuzhiyun else if (drm->client.device.info.chipset >= 0x40)
1024*4882a593Smuzhiyun return 155000 * duallink_scale;
1025*4882a593Smuzhiyun else if (drm->client.device.info.chipset >= 0x18)
1026*4882a593Smuzhiyun return 135000 * duallink_scale;
1027*4882a593Smuzhiyun else
1028*4882a593Smuzhiyun return 112000 * duallink_scale;
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun static enum drm_mode_status
nouveau_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1032*4882a593Smuzhiyun nouveau_connector_mode_valid(struct drm_connector *connector,
1033*4882a593Smuzhiyun struct drm_display_mode *mode)
1034*4882a593Smuzhiyun {
1035*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
1036*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
1037*4882a593Smuzhiyun struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
1038*4882a593Smuzhiyun unsigned int min_clock = 25000, max_clock = min_clock, clock = mode->clock;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun switch (nv_encoder->dcb->type) {
1041*4882a593Smuzhiyun case DCB_OUTPUT_LVDS:
1042*4882a593Smuzhiyun if (nv_connector->native_mode &&
1043*4882a593Smuzhiyun (mode->hdisplay > nv_connector->native_mode->hdisplay ||
1044*4882a593Smuzhiyun mode->vdisplay > nv_connector->native_mode->vdisplay))
1045*4882a593Smuzhiyun return MODE_PANEL;
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun min_clock = 0;
1048*4882a593Smuzhiyun max_clock = 400000;
1049*4882a593Smuzhiyun break;
1050*4882a593Smuzhiyun case DCB_OUTPUT_TMDS:
1051*4882a593Smuzhiyun max_clock = get_tmds_link_bandwidth(connector);
1052*4882a593Smuzhiyun break;
1053*4882a593Smuzhiyun case DCB_OUTPUT_ANALOG:
1054*4882a593Smuzhiyun max_clock = nv_encoder->dcb->crtconf.maxfreq;
1055*4882a593Smuzhiyun if (!max_clock)
1056*4882a593Smuzhiyun max_clock = 350000;
1057*4882a593Smuzhiyun break;
1058*4882a593Smuzhiyun case DCB_OUTPUT_TV:
1059*4882a593Smuzhiyun return get_slave_funcs(encoder)->mode_valid(encoder, mode);
1060*4882a593Smuzhiyun case DCB_OUTPUT_DP:
1061*4882a593Smuzhiyun return nv50_dp_mode_valid(connector, nv_encoder, mode, NULL);
1062*4882a593Smuzhiyun default:
1063*4882a593Smuzhiyun BUG();
1064*4882a593Smuzhiyun return MODE_BAD;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
1068*4882a593Smuzhiyun clock *= 2;
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun if (clock < min_clock)
1071*4882a593Smuzhiyun return MODE_CLOCK_LOW;
1072*4882a593Smuzhiyun if (clock > max_clock)
1073*4882a593Smuzhiyun return MODE_CLOCK_HIGH;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun return MODE_OK;
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun static struct drm_encoder *
nouveau_connector_best_encoder(struct drm_connector * connector)1079*4882a593Smuzhiyun nouveau_connector_best_encoder(struct drm_connector *connector)
1080*4882a593Smuzhiyun {
1081*4882a593Smuzhiyun struct nouveau_connector *nv_connector = nouveau_connector(connector);
1082*4882a593Smuzhiyun
1083*4882a593Smuzhiyun if (nv_connector->detected_encoder)
1084*4882a593Smuzhiyun return to_drm_encoder(nv_connector->detected_encoder);
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun return NULL;
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun static const struct drm_connector_helper_funcs
1090*4882a593Smuzhiyun nouveau_connector_helper_funcs = {
1091*4882a593Smuzhiyun .get_modes = nouveau_connector_get_modes,
1092*4882a593Smuzhiyun .mode_valid = nouveau_connector_mode_valid,
1093*4882a593Smuzhiyun .best_encoder = nouveau_connector_best_encoder,
1094*4882a593Smuzhiyun };
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun static const struct drm_connector_funcs
1097*4882a593Smuzhiyun nouveau_connector_funcs = {
1098*4882a593Smuzhiyun .dpms = drm_helper_connector_dpms,
1099*4882a593Smuzhiyun .reset = nouveau_conn_reset,
1100*4882a593Smuzhiyun .detect = nouveau_connector_detect,
1101*4882a593Smuzhiyun .force = nouveau_connector_force,
1102*4882a593Smuzhiyun .fill_modes = drm_helper_probe_single_connector_modes,
1103*4882a593Smuzhiyun .set_property = nouveau_connector_set_property,
1104*4882a593Smuzhiyun .destroy = nouveau_connector_destroy,
1105*4882a593Smuzhiyun .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
1106*4882a593Smuzhiyun .atomic_destroy_state = nouveau_conn_atomic_destroy_state,
1107*4882a593Smuzhiyun .atomic_set_property = nouveau_conn_atomic_set_property,
1108*4882a593Smuzhiyun .atomic_get_property = nouveau_conn_atomic_get_property,
1109*4882a593Smuzhiyun .late_register = nouveau_connector_late_register,
1110*4882a593Smuzhiyun .early_unregister = nouveau_connector_early_unregister,
1111*4882a593Smuzhiyun };
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun static const struct drm_connector_funcs
1114*4882a593Smuzhiyun nouveau_connector_funcs_lvds = {
1115*4882a593Smuzhiyun .dpms = drm_helper_connector_dpms,
1116*4882a593Smuzhiyun .reset = nouveau_conn_reset,
1117*4882a593Smuzhiyun .detect = nouveau_connector_detect_lvds,
1118*4882a593Smuzhiyun .force = nouveau_connector_force,
1119*4882a593Smuzhiyun .fill_modes = drm_helper_probe_single_connector_modes,
1120*4882a593Smuzhiyun .set_property = nouveau_connector_set_property,
1121*4882a593Smuzhiyun .destroy = nouveau_connector_destroy,
1122*4882a593Smuzhiyun .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
1123*4882a593Smuzhiyun .atomic_destroy_state = nouveau_conn_atomic_destroy_state,
1124*4882a593Smuzhiyun .atomic_set_property = nouveau_conn_atomic_set_property,
1125*4882a593Smuzhiyun .atomic_get_property = nouveau_conn_atomic_get_property,
1126*4882a593Smuzhiyun .late_register = nouveau_connector_late_register,
1127*4882a593Smuzhiyun .early_unregister = nouveau_connector_early_unregister,
1128*4882a593Smuzhiyun };
1129*4882a593Smuzhiyun
1130*4882a593Smuzhiyun void
nouveau_connector_hpd(struct drm_connector * connector)1131*4882a593Smuzhiyun nouveau_connector_hpd(struct drm_connector *connector)
1132*4882a593Smuzhiyun {
1133*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(connector->dev);
1134*4882a593Smuzhiyun u32 mask = drm_connector_mask(connector);
1135*4882a593Smuzhiyun
1136*4882a593Smuzhiyun mutex_lock(&drm->hpd_lock);
1137*4882a593Smuzhiyun if (!(drm->hpd_pending & mask)) {
1138*4882a593Smuzhiyun drm->hpd_pending |= mask;
1139*4882a593Smuzhiyun schedule_work(&drm->hpd_work);
1140*4882a593Smuzhiyun }
1141*4882a593Smuzhiyun mutex_unlock(&drm->hpd_lock);
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun static int
nouveau_connector_hotplug(struct nvif_notify * notify)1145*4882a593Smuzhiyun nouveau_connector_hotplug(struct nvif_notify *notify)
1146*4882a593Smuzhiyun {
1147*4882a593Smuzhiyun struct nouveau_connector *nv_connector =
1148*4882a593Smuzhiyun container_of(notify, typeof(*nv_connector), hpd);
1149*4882a593Smuzhiyun struct drm_connector *connector = &nv_connector->base;
1150*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
1151*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(dev);
1152*4882a593Smuzhiyun const struct nvif_notify_conn_rep_v0 *rep = notify->data;
1153*4882a593Smuzhiyun bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
1156*4882a593Smuzhiyun nouveau_dp_irq(drm, nv_connector);
1157*4882a593Smuzhiyun return NVIF_NOTIFY_KEEP;
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun
1160*4882a593Smuzhiyun NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", connector->name);
1161*4882a593Smuzhiyun nouveau_connector_hpd(connector);
1162*4882a593Smuzhiyun
1163*4882a593Smuzhiyun return NVIF_NOTIFY_KEEP;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun static ssize_t
nouveau_connector_aux_xfer(struct drm_dp_aux * obj,struct drm_dp_aux_msg * msg)1167*4882a593Smuzhiyun nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg)
1168*4882a593Smuzhiyun {
1169*4882a593Smuzhiyun struct nouveau_connector *nv_connector =
1170*4882a593Smuzhiyun container_of(obj, typeof(*nv_connector), aux);
1171*4882a593Smuzhiyun struct nouveau_encoder *nv_encoder;
1172*4882a593Smuzhiyun struct nvkm_i2c_aux *aux;
1173*4882a593Smuzhiyun u8 size = msg->size;
1174*4882a593Smuzhiyun int ret;
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
1177*4882a593Smuzhiyun if (!nv_encoder || !(aux = nv_encoder->aux))
1178*4882a593Smuzhiyun return -ENODEV;
1179*4882a593Smuzhiyun if (WARN_ON(msg->size > 16))
1180*4882a593Smuzhiyun return -E2BIG;
1181*4882a593Smuzhiyun
1182*4882a593Smuzhiyun ret = nvkm_i2c_aux_acquire(aux);
1183*4882a593Smuzhiyun if (ret)
1184*4882a593Smuzhiyun return ret;
1185*4882a593Smuzhiyun
1186*4882a593Smuzhiyun ret = nvkm_i2c_aux_xfer(aux, false, msg->request, msg->address,
1187*4882a593Smuzhiyun msg->buffer, &size);
1188*4882a593Smuzhiyun nvkm_i2c_aux_release(aux);
1189*4882a593Smuzhiyun if (ret >= 0) {
1190*4882a593Smuzhiyun msg->reply = ret;
1191*4882a593Smuzhiyun return size;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun return ret;
1195*4882a593Smuzhiyun }
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun static int
drm_conntype_from_dcb(enum dcb_connector_type dcb)1198*4882a593Smuzhiyun drm_conntype_from_dcb(enum dcb_connector_type dcb)
1199*4882a593Smuzhiyun {
1200*4882a593Smuzhiyun switch (dcb) {
1201*4882a593Smuzhiyun case DCB_CONNECTOR_VGA : return DRM_MODE_CONNECTOR_VGA;
1202*4882a593Smuzhiyun case DCB_CONNECTOR_TV_0 :
1203*4882a593Smuzhiyun case DCB_CONNECTOR_TV_1 :
1204*4882a593Smuzhiyun case DCB_CONNECTOR_TV_3 : return DRM_MODE_CONNECTOR_TV;
1205*4882a593Smuzhiyun case DCB_CONNECTOR_DMS59_0 :
1206*4882a593Smuzhiyun case DCB_CONNECTOR_DMS59_1 :
1207*4882a593Smuzhiyun case DCB_CONNECTOR_DVI_I : return DRM_MODE_CONNECTOR_DVII;
1208*4882a593Smuzhiyun case DCB_CONNECTOR_DVI_D : return DRM_MODE_CONNECTOR_DVID;
1209*4882a593Smuzhiyun case DCB_CONNECTOR_LVDS :
1210*4882a593Smuzhiyun case DCB_CONNECTOR_LVDS_SPWG: return DRM_MODE_CONNECTOR_LVDS;
1211*4882a593Smuzhiyun case DCB_CONNECTOR_DMS59_DP0:
1212*4882a593Smuzhiyun case DCB_CONNECTOR_DMS59_DP1:
1213*4882a593Smuzhiyun case DCB_CONNECTOR_DP :
1214*4882a593Smuzhiyun case DCB_CONNECTOR_mDP :
1215*4882a593Smuzhiyun case DCB_CONNECTOR_USB_C : return DRM_MODE_CONNECTOR_DisplayPort;
1216*4882a593Smuzhiyun case DCB_CONNECTOR_eDP : return DRM_MODE_CONNECTOR_eDP;
1217*4882a593Smuzhiyun case DCB_CONNECTOR_HDMI_0 :
1218*4882a593Smuzhiyun case DCB_CONNECTOR_HDMI_1 :
1219*4882a593Smuzhiyun case DCB_CONNECTOR_HDMI_C : return DRM_MODE_CONNECTOR_HDMIA;
1220*4882a593Smuzhiyun case DCB_CONNECTOR_WFD : return DRM_MODE_CONNECTOR_VIRTUAL;
1221*4882a593Smuzhiyun default:
1222*4882a593Smuzhiyun break;
1223*4882a593Smuzhiyun }
1224*4882a593Smuzhiyun
1225*4882a593Smuzhiyun return DRM_MODE_CONNECTOR_Unknown;
1226*4882a593Smuzhiyun }
1227*4882a593Smuzhiyun
1228*4882a593Smuzhiyun struct drm_connector *
nouveau_connector_create(struct drm_device * dev,const struct dcb_output * dcbe)1229*4882a593Smuzhiyun nouveau_connector_create(struct drm_device *dev,
1230*4882a593Smuzhiyun const struct dcb_output *dcbe)
1231*4882a593Smuzhiyun {
1232*4882a593Smuzhiyun const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
1233*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(dev);
1234*4882a593Smuzhiyun struct nouveau_display *disp = nouveau_display(dev);
1235*4882a593Smuzhiyun struct nouveau_connector *nv_connector = NULL;
1236*4882a593Smuzhiyun struct drm_connector *connector;
1237*4882a593Smuzhiyun struct drm_connector_list_iter conn_iter;
1238*4882a593Smuzhiyun char aux_name[48] = {0};
1239*4882a593Smuzhiyun int index = dcbe->connector;
1240*4882a593Smuzhiyun int type, ret = 0;
1241*4882a593Smuzhiyun bool dummy;
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun drm_connector_list_iter_begin(dev, &conn_iter);
1244*4882a593Smuzhiyun nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
1245*4882a593Smuzhiyun nv_connector = nouveau_connector(connector);
1246*4882a593Smuzhiyun if (nv_connector->index == index) {
1247*4882a593Smuzhiyun drm_connector_list_iter_end(&conn_iter);
1248*4882a593Smuzhiyun return connector;
1249*4882a593Smuzhiyun }
1250*4882a593Smuzhiyun }
1251*4882a593Smuzhiyun drm_connector_list_iter_end(&conn_iter);
1252*4882a593Smuzhiyun
1253*4882a593Smuzhiyun nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
1254*4882a593Smuzhiyun if (!nv_connector)
1255*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun connector = &nv_connector->base;
1258*4882a593Smuzhiyun nv_connector->index = index;
1259*4882a593Smuzhiyun
1260*4882a593Smuzhiyun /* attempt to parse vbios connector type and hotplug gpio */
1261*4882a593Smuzhiyun nv_connector->dcb = olddcb_conn(dev, index);
1262*4882a593Smuzhiyun if (nv_connector->dcb) {
1263*4882a593Smuzhiyun u32 entry = ROM16(nv_connector->dcb[0]);
1264*4882a593Smuzhiyun if (olddcb_conntab(dev)[3] >= 4)
1265*4882a593Smuzhiyun entry |= (u32)ROM16(nv_connector->dcb[2]) << 16;
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun nv_connector->type = nv_connector->dcb[0];
1268*4882a593Smuzhiyun if (drm_conntype_from_dcb(nv_connector->type) ==
1269*4882a593Smuzhiyun DRM_MODE_CONNECTOR_Unknown) {
1270*4882a593Smuzhiyun NV_WARN(drm, "unknown connector type %02x\n",
1271*4882a593Smuzhiyun nv_connector->type);
1272*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_NONE;
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun
1275*4882a593Smuzhiyun /* Gigabyte NX85T */
1276*4882a593Smuzhiyun if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) {
1277*4882a593Smuzhiyun if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
1278*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_DVI_I;
1279*4882a593Smuzhiyun }
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun /* Gigabyte GV-NX86T512H */
1282*4882a593Smuzhiyun if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) {
1283*4882a593Smuzhiyun if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
1284*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_DVI_I;
1285*4882a593Smuzhiyun }
1286*4882a593Smuzhiyun } else {
1287*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_NONE;
1288*4882a593Smuzhiyun }
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun /* no vbios data, or an unknown dcb connector type - attempt to
1291*4882a593Smuzhiyun * figure out something suitable ourselves
1292*4882a593Smuzhiyun */
1293*4882a593Smuzhiyun if (nv_connector->type == DCB_CONNECTOR_NONE) {
1294*4882a593Smuzhiyun struct nouveau_drm *drm = nouveau_drm(dev);
1295*4882a593Smuzhiyun struct dcb_table *dcbt = &drm->vbios.dcb;
1296*4882a593Smuzhiyun u32 encoders = 0;
1297*4882a593Smuzhiyun int i;
1298*4882a593Smuzhiyun
1299*4882a593Smuzhiyun for (i = 0; i < dcbt->entries; i++) {
1300*4882a593Smuzhiyun if (dcbt->entry[i].connector == nv_connector->index)
1301*4882a593Smuzhiyun encoders |= (1 << dcbt->entry[i].type);
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun
1304*4882a593Smuzhiyun if (encoders & (1 << DCB_OUTPUT_DP)) {
1305*4882a593Smuzhiyun if (encoders & (1 << DCB_OUTPUT_TMDS))
1306*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_DP;
1307*4882a593Smuzhiyun else
1308*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_eDP;
1309*4882a593Smuzhiyun } else
1310*4882a593Smuzhiyun if (encoders & (1 << DCB_OUTPUT_TMDS)) {
1311*4882a593Smuzhiyun if (encoders & (1 << DCB_OUTPUT_ANALOG))
1312*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_DVI_I;
1313*4882a593Smuzhiyun else
1314*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_DVI_D;
1315*4882a593Smuzhiyun } else
1316*4882a593Smuzhiyun if (encoders & (1 << DCB_OUTPUT_ANALOG)) {
1317*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_VGA;
1318*4882a593Smuzhiyun } else
1319*4882a593Smuzhiyun if (encoders & (1 << DCB_OUTPUT_LVDS)) {
1320*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_LVDS;
1321*4882a593Smuzhiyun } else
1322*4882a593Smuzhiyun if (encoders & (1 << DCB_OUTPUT_TV)) {
1323*4882a593Smuzhiyun nv_connector->type = DCB_CONNECTOR_TV_0;
1324*4882a593Smuzhiyun }
1325*4882a593Smuzhiyun }
1326*4882a593Smuzhiyun
1327*4882a593Smuzhiyun switch ((type = drm_conntype_from_dcb(nv_connector->type))) {
1328*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_LVDS:
1329*4882a593Smuzhiyun ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy);
1330*4882a593Smuzhiyun if (ret) {
1331*4882a593Smuzhiyun NV_ERROR(drm, "Error parsing LVDS table, disabling\n");
1332*4882a593Smuzhiyun kfree(nv_connector);
1333*4882a593Smuzhiyun return ERR_PTR(ret);
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun funcs = &nouveau_connector_funcs_lvds;
1337*4882a593Smuzhiyun break;
1338*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_DisplayPort:
1339*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_eDP:
1340*4882a593Smuzhiyun nv_connector->aux.dev = connector->kdev;
1341*4882a593Smuzhiyun nv_connector->aux.transfer = nouveau_connector_aux_xfer;
1342*4882a593Smuzhiyun snprintf(aux_name, sizeof(aux_name), "sor-%04x-%04x",
1343*4882a593Smuzhiyun dcbe->hasht, dcbe->hashm);
1344*4882a593Smuzhiyun nv_connector->aux.name = kstrdup(aux_name, GFP_KERNEL);
1345*4882a593Smuzhiyun ret = drm_dp_aux_register(&nv_connector->aux);
1346*4882a593Smuzhiyun if (ret) {
1347*4882a593Smuzhiyun NV_ERROR(drm, "failed to register aux channel\n");
1348*4882a593Smuzhiyun kfree(nv_connector);
1349*4882a593Smuzhiyun return ERR_PTR(ret);
1350*4882a593Smuzhiyun }
1351*4882a593Smuzhiyun funcs = &nouveau_connector_funcs;
1352*4882a593Smuzhiyun break;
1353*4882a593Smuzhiyun default:
1354*4882a593Smuzhiyun funcs = &nouveau_connector_funcs;
1355*4882a593Smuzhiyun break;
1356*4882a593Smuzhiyun }
1357*4882a593Smuzhiyun
1358*4882a593Smuzhiyun /* HDMI 3D support */
1359*4882a593Smuzhiyun if ((disp->disp.object.oclass >= G82_DISP)
1360*4882a593Smuzhiyun && ((type == DRM_MODE_CONNECTOR_DisplayPort)
1361*4882a593Smuzhiyun || (type == DRM_MODE_CONNECTOR_eDP)
1362*4882a593Smuzhiyun || (type == DRM_MODE_CONNECTOR_HDMIA)))
1363*4882a593Smuzhiyun connector->stereo_allowed = true;
1364*4882a593Smuzhiyun
1365*4882a593Smuzhiyun /* defaults, will get overridden in detect() */
1366*4882a593Smuzhiyun connector->interlace_allowed = false;
1367*4882a593Smuzhiyun connector->doublescan_allowed = false;
1368*4882a593Smuzhiyun
1369*4882a593Smuzhiyun drm_connector_init(dev, connector, funcs, type);
1370*4882a593Smuzhiyun drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
1371*4882a593Smuzhiyun
1372*4882a593Smuzhiyun connector->funcs->reset(connector);
1373*4882a593Smuzhiyun nouveau_conn_attach_properties(connector);
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun /* Default scaling mode */
1376*4882a593Smuzhiyun switch (nv_connector->type) {
1377*4882a593Smuzhiyun case DCB_CONNECTOR_LVDS:
1378*4882a593Smuzhiyun case DCB_CONNECTOR_LVDS_SPWG:
1379*4882a593Smuzhiyun case DCB_CONNECTOR_eDP:
1380*4882a593Smuzhiyun /* see note in nouveau_connector_set_property() */
1381*4882a593Smuzhiyun if (disp->disp.object.oclass < NV50_DISP) {
1382*4882a593Smuzhiyun nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
1383*4882a593Smuzhiyun break;
1384*4882a593Smuzhiyun }
1385*4882a593Smuzhiyun nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
1386*4882a593Smuzhiyun break;
1387*4882a593Smuzhiyun default:
1388*4882a593Smuzhiyun nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
1389*4882a593Smuzhiyun break;
1390*4882a593Smuzhiyun }
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun /* dithering properties */
1393*4882a593Smuzhiyun switch (nv_connector->type) {
1394*4882a593Smuzhiyun case DCB_CONNECTOR_TV_0:
1395*4882a593Smuzhiyun case DCB_CONNECTOR_TV_1:
1396*4882a593Smuzhiyun case DCB_CONNECTOR_TV_3:
1397*4882a593Smuzhiyun case DCB_CONNECTOR_VGA:
1398*4882a593Smuzhiyun break;
1399*4882a593Smuzhiyun default:
1400*4882a593Smuzhiyun nv_connector->dithering_mode = DITHERING_MODE_AUTO;
1401*4882a593Smuzhiyun break;
1402*4882a593Smuzhiyun }
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun switch (type) {
1405*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_DisplayPort:
1406*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_eDP:
1407*4882a593Smuzhiyun drm_dp_cec_register_connector(&nv_connector->aux, connector);
1408*4882a593Smuzhiyun break;
1409*4882a593Smuzhiyun }
1410*4882a593Smuzhiyun
1411*4882a593Smuzhiyun ret = nvif_notify_ctor(&disp->disp.object, "kmsHotplug",
1412*4882a593Smuzhiyun nouveau_connector_hotplug,
1413*4882a593Smuzhiyun true, NV04_DISP_NTFY_CONN,
1414*4882a593Smuzhiyun &(struct nvif_notify_conn_req_v0) {
1415*4882a593Smuzhiyun .mask = NVIF_NOTIFY_CONN_V0_ANY,
1416*4882a593Smuzhiyun .conn = index,
1417*4882a593Smuzhiyun },
1418*4882a593Smuzhiyun sizeof(struct nvif_notify_conn_req_v0),
1419*4882a593Smuzhiyun sizeof(struct nvif_notify_conn_rep_v0),
1420*4882a593Smuzhiyun &nv_connector->hpd);
1421*4882a593Smuzhiyun if (ret)
1422*4882a593Smuzhiyun connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1423*4882a593Smuzhiyun else
1424*4882a593Smuzhiyun connector->polled = DRM_CONNECTOR_POLL_HPD;
1425*4882a593Smuzhiyun
1426*4882a593Smuzhiyun drm_connector_register(connector);
1427*4882a593Smuzhiyun return connector;
1428*4882a593Smuzhiyun }
1429