~ubuntu-branches/ubuntu/trusty/xserver-xorg-video-nouveau/trusty

« back to all changes in this revision

Viewing changes to src/nv50_randr.c

  • Committer: Bazaar Package Importer
  • Author(s): Christopher James Halse Rogers
  • Date: 2009-12-04 12:31:58 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20091204123158-oc7ytykkz8anvr6i
Tags: 1:0.0.15+git20100128+2630a15-0ubuntu1
* New upstream snapshot
  + Too many commits to usefully list in the changelog.
  + User modesetting code is now removed.  Nouveau will now only work with 
    KMS.
* debian/control:
  + Bump versioned Build-Dep on libdrm-dev to >= 2.4.17-1ubuntu1~ to pick 
    up nouveau #define updates.
  + Bump build-dep on xserver-xorg-dev to >= 2:1.7.  Nouveau now requires 
    xorg-server >= 1.7.
  + Drop duplicate build-dep on xserver-xorg-dev
  + List the Build-Depends one-to-a-line for clarity
  + Drop the Depends: on linux-nouveau-modules.  Replace with temporary 
    Depends against apw's linux-backports-modules-nouveau* packages.
  + Bump Standards version to 3.8.3.
* debian/README.source
  + Quilt patchsys README for standards version 3.8.3 compliance
* Change versioning to match Sarvatt's snapshot versioning.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2008 Maarten Maathuis
3
 
 *
4
 
 * Permission is hereby granted, free of charge, to any person obtaining a
5
 
 * copy of this software and associated documentation files (the "Software"),
6
 
 * to deal in the Software without restriction, including without limitation
7
 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
 
 * and/or sell copies of the Software, and to permit persons to whom the
9
 
 * Software is furnished to do so, subject to the following conditions:
10
 
 *
11
 
 * The above copyright notice and this permission notice shall be included in
12
 
 * all copies or substantial portions of the Software.
13
 
 *
14
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17
 
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19
 
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
 
 * SOFTWARE.
21
 
 */
22
 
 
23
 
#include "nv50_randr.h"
24
 
#include "X11/Xatom.h"
25
 
 
26
 
/*
27
 
 * A randr-1.2 wrapper around the NV50 driver.
28
 
 */
29
 
 
30
 
/*
31
 
 * CRTC stuff.
32
 
 */
33
 
 
34
 
static void
35
 
nv50_crtc_dpms(xf86CrtcPtr crtc, int mode)
36
 
{
37
 
        ScrnInfoPtr pScrn = crtc->scrn;
38
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
39
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_dpms is called with mode %d for %s.\n", mode, nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
40
 
 
41
 
        switch (mode) {
42
 
                case DPMSModeOn:
43
 
                        nv_crtc->crtc->active = TRUE;
44
 
                        break;
45
 
                case DPMSModeSuspend:
46
 
                case DPMSModeStandby:
47
 
                case DPMSModeOff:
48
 
                default:
49
 
                        nv_crtc->crtc->active = FALSE;
50
 
                        break;
51
 
        }
52
 
}
53
 
 
54
 
static Bool
55
 
nv50_crtc_lock(xf86CrtcPtr crtc)
56
 
{
57
 
        return FALSE;
58
 
}
59
 
 
60
 
static Bool
61
 
nv50_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
62
 
                DisplayModePtr adjusted_mode)
63
 
{
64
 
        return TRUE;
65
 
}
66
 
 
67
 
static void
68
 
nv50_crtc_prepare(xf86CrtcPtr crtc)
69
 
{
70
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
71
 
        ScrnInfoPtr pScrn = crtc->scrn;
72
 
        NVPtr pNv = NVPTR(pScrn);
73
 
        xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
74
 
        nouveauOutputPtr output;
75
 
        int i;
76
 
 
77
 
        /* Rewire internal stucts to match randr-1.2... yet again.. */
78
 
        for (i = 0; i < xf86_config->num_output; i++) {
79
 
                xf86OutputPtr output = xf86_config->output[i];
80
 
                NV50OutputPrivatePtr nv50_output = output->driver_private;
81
 
                nouveauOutputPtr nv_output = nv50_output->output;
82
 
 
83
 
                if (output->crtc) {
84
 
                        NV50CrtcPrivatePtr nv50_crtc =
85
 
                                output->crtc->driver_private;
86
 
                        nv_output->crtc = nv50_crtc->crtc;
87
 
                } else {
88
 
                        nv_output->crtc = NULL;
89
 
                }
90
 
        }
91
 
 
92
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
93
 
                   "nv50_crtc_prepare is called for %s.\n",
94
 
                   nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
95
 
 
96
 
        nv_crtc->crtc->active = TRUE;
97
 
        nv_crtc->crtc->modeset_lock = TRUE;
98
 
 
99
 
        /* Detach any unused outputs. */
100
 
        for (output = pNv->output; output != NULL; output = output->next) {
101
 
                if (!output->crtc)
102
 
                        output->ModeSet(output, NULL);
103
 
        }
104
 
}
105
 
 
106
 
static void
107
 
nv50_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
108
 
                   DisplayModePtr adjusted_mode, int x, int y)
109
 
{
110
 
        ScrnInfoPtr pScrn = crtc->scrn;
111
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
112
 
        struct nouveau_bo *bo;
113
 
 
114
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
115
 
                   "nv50_crtc_mode_set is called for %s.\n",
116
 
                   nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
117
 
 
118
 
        NVPtr pNv = NVPTR(pScrn);
119
 
 
120
 
        bo = pNv->scanout;
121
 
        if (crtc->rotatedData) {
122
 
                bo = nv_crtc->shadow;
123
 
                x = 0;
124
 
                y = 0;
125
 
        }
126
 
 
127
 
        nv_crtc->crtc->SetFB(nv_crtc->crtc, bo);
128
 
        nv_crtc->crtc->SetFBOffset(nv_crtc->crtc, x, y);
129
 
        nv_crtc->crtc->ModeSet(nv_crtc->crtc, mode);
130
 
}
131
 
 
132
 
static void
133
 
nv50_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, int size)
134
 
{
135
 
        ScrnInfoPtr pScrn = crtc->scrn;
136
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
137
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_gamma_set is called for %s.\n", nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
138
 
 
139
 
        nv_crtc->crtc->GammaSet(nv_crtc->crtc, (uint16_t *) red, (uint16_t *) green, (uint16_t *) blue, size);
140
 
}
141
 
 
142
 
static void
143
 
nv50_crtc_commit(xf86CrtcPtr crtc)
144
 
{
145
 
        ScrnInfoPtr pScrn = crtc->scrn;
146
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
147
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_commit is called for %s.\n", nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
148
 
 
149
 
        NVPtr pNv = NVPTR(pScrn);
150
 
 
151
 
        /* Let's detect any outputs and connectors that have gone inactive. */
152
 
        uint8_t crtc_active_mask = 0;
153
 
        int i, j;
154
 
        nouveauOutputPtr output;
155
 
 
156
 
        for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++) {
157
 
                Bool connector_active = FALSE;
158
 
                for (j = 0; j < MAX_OUTPUTS_PER_CONNECTOR; j++) {
159
 
                        output = pNv->connector[i]->outputs[j];
160
 
                        if (output) {
161
 
                                if (output->crtc) {
162
 
                                        crtc_active_mask |= 1 << output->crtc->index;
163
 
                                        connector_active = TRUE;
164
 
                                } else {
165
 
                                        output->active = FALSE;
166
 
                                }
167
 
                        }
168
 
                }
169
 
 
170
 
                pNv->connector[i]->active = connector_active;
171
 
        }
172
 
 
173
 
        /* Blank any crtc's that are inactive. */
174
 
        if (!(crtc_active_mask & (1 << 0)))
175
 
                pNv->crtc[0]->Blank(pNv->crtc[0], TRUE);
176
 
 
177
 
        if (!(crtc_active_mask & (1 << 1)))
178
 
                pNv->crtc[1]->Blank(pNv->crtc[1], TRUE);
179
 
 
180
 
        xf86_reload_cursors(pScrn->pScreen);
181
 
 
182
 
        NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
183
 
 
184
 
        nv_crtc->crtc->modeset_lock = FALSE;
185
 
}
186
 
 
187
 
/*
188
 
 * Cursor CRTC stuff.
189
 
 */
190
 
 
191
 
static void 
192
 
nv50_crtc_show_cursor(xf86CrtcPtr crtc)
193
 
{
194
 
        //ScrnInfoPtr pScrn = crtc->scrn;
195
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
196
 
        //xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_show_cursor is called for %s.\n", nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
197
 
 
198
 
        if (!nv_crtc->crtc->blanked)
199
 
                nv_crtc->crtc->ShowCursor(nv_crtc->crtc, FALSE);
200
 
}
201
 
 
202
 
static void
203
 
nv50_crtc_hide_cursor(xf86CrtcPtr crtc)
204
 
{
205
 
        //ScrnInfoPtr pScrn = crtc->scrn;
206
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
207
 
        //xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_hide_cursor is called for %s.\n", nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
208
 
 
209
 
        nv_crtc->crtc->HideCursor(nv_crtc->crtc, FALSE);
210
 
}
211
 
 
212
 
static void
213
 
nv50_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
214
 
{
215
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
216
 
 
217
 
        nv_crtc->crtc->SetCursorPosition(nv_crtc->crtc, x, y);
218
 
}
219
 
 
220
 
static void
221
 
nv50_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *src)
222
 
{
223
 
        //ScrnInfoPtr pScrn = crtc->scrn;
224
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
225
 
        //xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_load_cursor_argb is called for %s.\n", nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
226
 
 
227
 
        nv_crtc->crtc->LoadCursor(nv_crtc->crtc, TRUE, (uint32_t *) src);
228
 
}
229
 
 
230
 
static void *
231
 
nv50_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
232
 
{
233
 
        ScrnInfoPtr pScrn = crtc->scrn;
234
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
235
 
        NVPtr pNv = NVPTR(pScrn);
236
 
        int size, pitch;
237
 
 
238
 
        ErrorF("nv50_crtc_shadow_allocate\n");
239
 
 
240
 
        pitch = pScrn->displayWidth * (pScrn->bitsPerPixel/8);
241
 
        size = pitch * height;
242
 
 
243
 
        if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM |
244
 
                           NOUVEAU_BO_MAP, 64, size, &nv_crtc->shadow)) {
245
 
                xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
246
 
                           "Failed to allocate memory for shadow buffer!\n");
247
 
                return NULL;
248
 
        }
249
 
 
250
 
        if (nv_crtc->shadow && nouveau_bo_map(nv_crtc->shadow, NOUVEAU_BO_RDWR)) {
251
 
                xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
252
 
                                "Failed to map shadow buffer.\n");
253
 
                return NULL;
254
 
        }
255
 
 
256
 
        pNv->shadow[nv_crtc->crtc->index] = nv_crtc->shadow;
257
 
 
258
 
        return nv_crtc->shadow->map;
259
 
}
260
 
 
261
 
static PixmapPtr
262
 
nv50_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
263
 
{
264
 
        ScrnInfoPtr pScrn = crtc->scrn;
265
 
        uint32_t pitch;
266
 
        PixmapPtr rotate_pixmap;
267
 
 
268
 
        ErrorF("nv50_crtc_shadow_create\n");
269
 
 
270
 
        if (!data)
271
 
                data = crtc->funcs->shadow_allocate (crtc, width, height);
272
 
 
273
 
        pitch = pScrn->displayWidth * (pScrn->bitsPerPixel/8);
274
 
 
275
 
        rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen,
276
 
                                                width, height,
277
 
                                                pScrn->depth,
278
 
                                                pScrn->bitsPerPixel,
279
 
                                                pitch,
280
 
                                                data);
281
 
 
282
 
        if (rotate_pixmap == NULL) {
283
 
                xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
284
 
                        "Couldn't allocate shadow pixmap for rotated CRTC\n");
285
 
        }
286
 
 
287
 
        return rotate_pixmap;
288
 
}
289
 
 
290
 
static void
291
 
nv50_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
292
 
{
293
 
        ScrnInfoPtr pScrn = crtc->scrn;
294
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
295
 
        NVPtr pNv = NVPTR(pScrn);
296
 
        ScreenPtr pScreen = pScrn->pScreen;
297
 
 
298
 
        ErrorF("nv50_crtc_shadow_destroy\n");
299
 
 
300
 
        if (rotate_pixmap)
301
 
                pScreen->DestroyPixmap(rotate_pixmap);
302
 
 
303
 
        if (nv_crtc->shadow)
304
 
                nouveau_bo_ref(NULL, &nv_crtc->shadow);
305
 
 
306
 
        nv_crtc->shadow = NULL;
307
 
        /* for easy acces by exa */
308
 
        pNv->shadow[nv_crtc->crtc->index] = NULL;
309
 
}
310
 
 
311
 
#if XF86_CRTC_VERSION >= 2
312
 
static void
313
 
nv50_crtc_set_origin(xf86CrtcPtr crtc, int x, int y)
314
 
{
315
 
        ScrnInfoPtr pScrn = crtc->scrn;
316
 
        NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
317
 
        nouveauCrtcPtr nvcrtc = nv_crtc->crtc; /* sigh.. */
318
 
        NVPtr pNv = NVPTR(pScrn);
319
 
        uint32_t fb;
320
 
 
321
 
        nvcrtc->SetFB(nvcrtc, pNv->scanout);
322
 
        nvcrtc->SetFBOffset(nvcrtc, x, y);
323
 
        nvcrtc->fb_pitch = pScrn->displayWidth * (pScrn->bitsPerPixel >> 3);
324
 
        fb = nvcrtc->front_buffer->offset - pNv->dev->vm_vram_base;
325
 
 
326
 
        NV50CrtcCommand(nvcrtc, NV50_CRTC0_FB_OFFSET, fb >> 8);
327
 
        NV50CrtcCommand(nvcrtc, NV50_CRTC0_FB_PITCH, nvcrtc->fb_pitch | (1<<20));
328
 
        NV50CrtcCommand(nvcrtc, NV50_CRTC0_FB_SIZE, (pScrn->virtualY << 16) |
329
 
                                                     pScrn->virtualX);
330
 
 
331
 
        NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
332
 
}
333
 
#endif
334
 
 
335
 
static void
336
 
nv50_crtc_destroy(xf86CrtcPtr crtc)
337
 
{
338
 
        xfree(crtc->driver_private);
339
 
}
340
 
 
341
 
static const xf86CrtcFuncsRec nv50_crtc_funcs = {
342
 
        .dpms = nv50_crtc_dpms,
343
 
        .save = NULL,
344
 
        .restore = NULL,
345
 
        .lock = nv50_crtc_lock,
346
 
        .unlock = NULL,
347
 
        .mode_fixup = nv50_crtc_mode_fixup,
348
 
        .prepare = nv50_crtc_prepare,
349
 
        .mode_set = nv50_crtc_mode_set,
350
 
        .gamma_set = nv50_crtc_gamma_set,
351
 
        .commit = nv50_crtc_commit,
352
 
        .shadow_create = nv50_crtc_shadow_create,
353
 
        .shadow_allocate = nv50_crtc_shadow_allocate,
354
 
        .shadow_destroy = nv50_crtc_shadow_destroy,
355
 
        .set_cursor_position = nv50_crtc_set_cursor_position,
356
 
        .show_cursor = nv50_crtc_show_cursor,
357
 
        .hide_cursor = nv50_crtc_hide_cursor,
358
 
        .load_cursor_argb = nv50_crtc_load_cursor_argb,
359
 
        .destroy = nv50_crtc_destroy,
360
 
#if XF86_CRTC_VERSION >= 2
361
 
        .set_origin = nv50_crtc_set_origin,
362
 
#endif
363
 
};
364
 
 
365
 
void
366
 
nv50_crtc_init(ScrnInfoPtr pScrn, int crtc_num)
367
 
{
368
 
        NVPtr pNv = NVPTR(pScrn);
369
 
        xf86CrtcPtr crtc;
370
 
        NV50CrtcPrivatePtr nv_crtc;
371
 
 
372
 
        crtc = xf86CrtcCreate(pScrn, &nv50_crtc_funcs);
373
 
        if (crtc == NULL)
374
 
                return;
375
 
 
376
 
        nv_crtc = xnfcalloc (sizeof (NV50CrtcPrivateRec), 1);
377
 
        nv_crtc->crtc = pNv->crtc[crtc_num];
378
 
 
379
 
        crtc->driver_private = nv_crtc;
380
 
}
381
 
 
382
 
 
383
 
/*
384
 
 * "Output" stuff.
385
 
 */
386
 
 
387
 
static void
388
 
nv50_output_dpms(xf86OutputPtr output, int mode)
389
 
{
390
 
        ScrnInfoPtr pScrn = output->scrn;
391
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_dpms is called with mode %d.\n", mode);
392
 
 
393
 
        NVPtr pNv = NVPTR(pScrn);
394
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
395
 
 
396
 
        /* Keep the crtc wiring consistent with randr-1.2 */
397
 
        if (output->crtc) {
398
 
                NV50CrtcPrivatePtr nv_crtc = output->crtc->driver_private;
399
 
                nv_output->output->crtc = nv_crtc->crtc;
400
 
        } else {
401
 
                nv_output->output->crtc = NULL;
402
 
        }
403
 
 
404
 
        /* Our crtc's map 1:1 onto randr-1.2 crtc's. */
405
 
        switch (mode) {
406
 
                case DPMSModeOn:
407
 
                        nv_output->output->active = TRUE;
408
 
                        break;
409
 
                case DPMSModeSuspend:
410
 
                case DPMSModeStandby:
411
 
                case DPMSModeOff:
412
 
                default:
413
 
                        nv_output->output->active = FALSE;
414
 
                        break;
415
 
        }
416
 
 
417
 
        /* Set dpms on all outputs for ths connector, just to be safe. */
418
 
        nouveauConnectorPtr connector =
419
 
                pNv->connector[nv_output->output->dcb->i2c_index];
420
 
        int i;
421
 
        for (i = 0; i < MAX_OUTPUTS_PER_CONNECTOR; i++) {
422
 
                if (connector->outputs[i])
423
 
                        connector->outputs[i]->SetPowerMode(connector->outputs[i], mode);
424
 
        }
425
 
}
426
 
 
427
 
static int
428
 
nv50_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
429
 
{
430
 
        ScrnInfoPtr pScrn = output->scrn;
431
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_mode_valid is called.\n");
432
 
 
433
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
434
 
 
435
 
        return nv_output->output->ModeValid(nv_output->output, mode);
436
 
}
437
 
 
438
 
static Bool
439
 
nv50_output_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
440
 
{
441
 
        return TRUE;
442
 
}
443
 
 
444
 
static void
445
 
nv50_output_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
446
 
{
447
 
        ScrnInfoPtr pScrn = output->scrn;
448
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_mode_set is called.\n");
449
 
 
450
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
451
 
 
452
 
        nv_output->output->ModeSet(nv_output->output, mode);
453
 
}
454
 
 
455
 
static xf86OutputStatus
456
 
nv50_output_detect(xf86OutputPtr output)
457
 
{
458
 
        ScrnInfoPtr pScrn = output->scrn;
459
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_detect is called.\n");
460
 
 
461
 
        NVPtr pNv = NVPTR(pScrn);
462
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
463
 
        nouveauConnectorPtr connector =
464
 
                pNv->connector[nv_output->output->dcb->i2c_index];
465
 
 
466
 
        if (!connector)
467
 
                return XF86OutputStatusDisconnected;
468
 
 
469
 
        Bool detect_present = FALSE;
470
 
        Bool detect_digital = FALSE;
471
 
        xf86MonPtr ddc_mon = connector->DDCDetect(connector);
472
 
        int i;
473
 
 
474
 
        if (!ddc_mon) {
475
 
                for (i = 0; i < MAX_OUTPUTS_PER_CONNECTOR; i++) {
476
 
                        if (connector->outputs[i] && connector->outputs[i]->Detect) {
477
 
                                detect_present = connector->outputs[i]->Detect(connector->outputs[i]);
478
 
                                if (detect_present) {
479
 
                                        if (connector->outputs[i]->type == OUTPUT_TMDS || connector->outputs[i]->type == OUTPUT_LVDS)
480
 
                                                detect_digital = TRUE;
481
 
                                        break;
482
 
                                }
483
 
                        }
484
 
                }
485
 
        }
486
 
 
487
 
        /* HACK: assume that a connector only holds output in the case of a tv-out */
488
 
        if (nv_output->output->type == OUTPUT_TV)
489
 
                return XF86OutputStatusUnknown;
490
 
 
491
 
        /*
492
 
         * We abuse randr-1.2 outputs as connector, so here we have to determine what actual output is connected to the connector.
493
 
         */
494
 
        if (ddc_mon || detect_present) {
495
 
                Bool is_digital = FALSE;
496
 
                Bool found = FALSE;
497
 
                nouveauCrtcPtr crtc_backup = nv_output->output->crtc;
498
 
                nv_output->output->crtc = NULL;
499
 
                nv_output->output->connector = NULL;
500
 
 
501
 
                if (ddc_mon)
502
 
                        is_digital = ddc_mon->features.input_type;
503
 
                else
504
 
                        is_digital = detect_digital;
505
 
 
506
 
                xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected a %s output on %s\n", is_digital ? "Digital" : "Analog", connector->name);
507
 
 
508
 
                for (i = 0; i < MAX_OUTPUTS_PER_CONNECTOR; i++) {
509
 
                        if (!is_digital && (connector->outputs[i]->type == OUTPUT_ANALOG || connector->outputs[i]->type == OUTPUT_TV)) {
510
 
                                found = TRUE;
511
 
                        } else if (is_digital && (connector->outputs[i]->type == OUTPUT_TMDS || connector->outputs[i]->type == OUTPUT_LVDS)) {
512
 
                                found = TRUE;
513
 
                        }
514
 
                        if (found) {
515
 
                                xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found a suitable output, index %d\n", i);
516
 
                                connector->connected_output = i;
517
 
                                connector->outputs[i]->connector = connector;
518
 
                                connector->outputs[i]->crtc = crtc_backup;
519
 
                                nv_output->output = connector->outputs[i];
520
 
                                break;
521
 
                        }
522
 
                }
523
 
        }
524
 
 
525
 
        if (ddc_mon || detect_present) {
526
 
                free(ddc_mon);
527
 
                return XF86OutputStatusConnected;
528
 
        } else {
529
 
                return XF86OutputStatusDisconnected;
530
 
        }
531
 
}
532
 
 
533
 
static DisplayModePtr
534
 
nv50_output_get_modes(xf86OutputPtr output)
535
 
{
536
 
        ScrnInfoPtr pScrn = output->scrn;
537
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_detect is called.\n");
538
 
 
539
 
        NVPtr pNv = NVPTR(pScrn);
540
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
541
 
        nouveauConnectorPtr connector =
542
 
                pNv->connector[nv_output->output->dcb->i2c_index];
543
 
 
544
 
        xf86MonPtr ddc_mon = connector->DDCDetect(connector);
545
 
 
546
 
        xf86OutputSetEDID(output, ddc_mon);
547
 
 
548
 
        DisplayModePtr ddc_modes = connector->GetDDCModes(connector);
549
 
        DisplayModePtr default_modes = NULL;
550
 
 
551
 
        xf86DeleteMode(&nv_output->output->native_mode, nv_output->output->native_mode);
552
 
        nv_output->output->native_mode = NULL;
553
 
        if (nv_output->output->crtc)
554
 
                nv_output->output->crtc->native_mode = NULL;
555
 
 
556
 
        /* typically only LVDS will hit this code path. */
557
 
        if (!ddc_modes) {
558
 
                DisplayModeRec mode = {};
559
 
 
560
 
                if (nv_output->output->type == OUTPUT_LVDS &&
561
 
                      nouveau_bios_fp_mode(pScrn, &mode)) {
562
 
                        mode.status = MODE_OK;
563
 
                        mode.type = M_T_DRIVER | M_T_PREFERRED;
564
 
                        xf86SetModeDefaultName(&mode);
565
 
 
566
 
                        ddc_modes = xf86DuplicateMode(&mode);
567
 
                        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
568
 
                                   "LVDS: Using a bios mode, which should work, if it doesn't please report.\n");
569
 
                }
570
 
        }
571
 
 
572
 
        if (!ddc_modes && nv_output->output->type == OUTPUT_LVDS) {
573
 
                xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "LVDS and no modes found, bailing out.\n");
574
 
                return NULL;
575
 
        }
576
 
 
577
 
        /* NV5x hardware can also do scaling on analog connections. */
578
 
        if (ddc_modes) {
579
 
                /* Use the first preferred mode as native mode. */
580
 
                DisplayModePtr mode;
581
 
 
582
 
                /* Find the preferred mode. */
583
 
                for (mode = ddc_modes; mode != NULL; mode = mode->next) {
584
 
                        if (mode->type & M_T_PREFERRED) {
585
 
                                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
586
 
                                                "%s: preferred mode is %s\n",
587
 
                                                output->name, mode->name);
588
 
                                break;
589
 
                        }
590
 
                }
591
 
 
592
 
                /* TODO: Scaling needs a native mode, maybe fail in a better way. */
593
 
                if (!mode) {
594
 
                        mode = ddc_modes;
595
 
                        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
596
 
                                "%s: no preferred mode found, using %s\n",
597
 
                                output->name, mode->name);
598
 
                }
599
 
 
600
 
                nv_output->output->native_mode = xf86DuplicateMode(mode);
601
 
        }
602
 
 
603
 
        /* No ddc means no native mode, so make one up to avoid crashes. */
604
 
        if (!nv_output->output->native_mode)
605
 
                nv_output->output->native_mode = xf86CVTMode(1024, 768, 60.0, FALSE, FALSE);
606
 
 
607
 
        xf86SetModeCrtc(nv_output->output->native_mode, 0);
608
 
 
609
 
        if (nv_output->output->crtc)
610
 
                nv_output->output->crtc->native_mode = nv_output->output->native_mode;
611
 
 
612
 
        if (nv_output->output->type == OUTPUT_LVDS && 
613
 
            (!ddc_mon ||!GTF_SUPPORTED(ddc_mon->features.msc))) {
614
 
#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,6,99,1,0)
615
 
                default_modes = xf86GetDefaultModes(output->interlaceAllowed,
616
 
                                                    output->doubleScanAllowed);
617
 
#else
618
 
                default_modes = xf86GetDefaultModes();
619
 
#endif
620
 
        }
621
 
 
622
 
        xf86ModesAdd(ddc_modes, default_modes);
623
 
        return ddc_modes;
624
 
}
625
 
 
626
 
static void
627
 
nv50_output_destroy(xf86OutputPtr output)
628
 
{
629
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
630
 
 
631
 
        xf86DeleteMode(&nv_output->output->native_mode, nv_output->output->native_mode);
632
 
 
633
 
        xfree(output->driver_private);
634
 
        output->driver_private = NULL;
635
 
}
636
 
 
637
 
void
638
 
nv50_output_prepare(xf86OutputPtr output)
639
 
{
640
 
        ScrnInfoPtr pScrn = output->scrn;
641
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_prepare is called.\n");
642
 
 
643
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
644
 
        NV50CrtcPrivatePtr nv_crtc = output->crtc->driver_private;
645
 
 
646
 
        /* Set the real crtc now. */
647
 
        nv_output->output->crtc = nv_crtc->crtc;
648
 
 
649
 
        /* Transfer some output properties to the crtc for easy access. */
650
 
        nv_output->output->crtc->scale_mode = nv_output->output->scale_mode;
651
 
        nv_output->output->crtc->dithering = nv_output->output->dithering;
652
 
        nv_output->output->crtc->native_mode = nv_output->output->native_mode;
653
 
 
654
 
        if (nv_output->output->scale_mode != SCALE_PANEL)
655
 
                nv_output->output->crtc->use_native_mode = TRUE;
656
 
        else
657
 
                nv_output->output->crtc->use_native_mode = FALSE;
658
 
}
659
 
 
660
 
static void
661
 
nv50_output_commit(xf86OutputPtr output)
662
 
{
663
 
        ScrnInfoPtr pScrn = output->scrn;
664
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_commit is called.\n");
665
 
}
666
 
 
667
 
#ifdef RANDR_GET_CRTC_INTERFACE
668
 
static xf86CrtcPtr
669
 
nv50_output_get_crtc(xf86OutputPtr output)
670
 
{
671
 
        ScrnInfoPtr pScrn = output->scrn;
672
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_get_crtc is called.\n");
673
 
 
674
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
675
 
        nouveauCrtcPtr crtc = nv_output->output->GetCurrentCrtc(nv_output->output);
676
 
 
677
 
        /* 
678
 
         * Match the internal crtc to the public crtc.
679
 
         * Note that GetCurrentCrtc() retrieves hardware state. 
680
 
         * Otherwise we could have just used output->crtc.
681
 
         */
682
 
        if (crtc) {
683
 
                int i;
684
 
                xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
685
 
                for (i = 0; i < xf86_config->num_crtc; i++) {
686
 
                        NV50CrtcPrivatePtr nv_crtc = xf86_config->crtc[i]->driver_private;
687
 
                        if (nv_crtc->crtc == crtc)
688
 
                                return xf86_config->crtc[i];
689
 
                }
690
 
        }
691
 
 
692
 
        return NULL;
693
 
}
694
 
#endif /* RANDR_GET_CRTC_INTERFACE */
695
 
 
696
 
/*
697
 
 * Output properties.
698
 
 */
699
 
 
700
 
/*
701
 
 * Several scaling modes exist, let the user choose.
702
 
 */
703
 
#define SCALING_MODE_NAME "SCALING_MODE"
704
 
static const struct {
705
 
        char *name;
706
 
        enum scaling_modes mode;
707
 
} scaling_mode[] = {
708
 
        { "panel", SCALE_PANEL },
709
 
        { "fullscreen", SCALE_FULLSCREEN },
710
 
        { "aspect", SCALE_ASPECT },
711
 
        { "noscale", SCALE_NOSCALE },
712
 
        { NULL, SCALE_INVALID}
713
 
};
714
 
static Atom scaling_mode_atom;
715
 
 
716
 
#define DITHERING_MODE_NAME "DITHERING"
717
 
static Atom dithering_atom;
718
 
 
719
 
int
720
 
nv_scaling_mode_lookup(char *name, int size)
721
 
{
722
 
        int i;
723
 
 
724
 
        /* for when name is zero terminated */
725
 
        if (size < 0)
726
 
                size = strlen(name);
727
 
 
728
 
        for (i = 0; scaling_mode[i].name; i++)
729
 
                /* We're getting non-terminated strings */
730
 
                if (strlen(scaling_mode[i].name) >= size &&
731
 
                                !strncasecmp(name, scaling_mode[i].name, size))
732
 
                        break;
733
 
 
734
 
        return scaling_mode[i].mode;
735
 
}
736
 
 
737
 
void
738
 
nv50_output_create_resources(xf86OutputPtr output)
739
 
{
740
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
741
 
        ScrnInfoPtr pScrn = output->scrn;
742
 
        INT32 dithering_range[2] = { 0, 1 };
743
 
        int error, i;
744
 
 
745
 
        /*
746
 
         * Setup scaling mode property.
747
 
         */
748
 
        scaling_mode_atom = MakeAtom(SCALING_MODE_NAME, sizeof(SCALING_MODE_NAME) - 1, TRUE);
749
 
 
750
 
        error = RRConfigureOutputProperty(output->randr_output,
751
 
                                        scaling_mode_atom, TRUE, FALSE, FALSE,
752
 
                                        0, NULL);
753
 
 
754
 
        if (error != 0) {
755
 
                xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
756
 
                        "RRConfigureOutputProperty error, %d\n", error);
757
 
        }
758
 
 
759
 
        char *existing_scale_name = NULL;
760
 
        for (i = 0; scaling_mode[i].name; i++)
761
 
                if (scaling_mode[i].mode == nv_output->output->scale_mode)
762
 
                        existing_scale_name = scaling_mode[i].name;
763
 
 
764
 
        error = RRChangeOutputProperty(output->randr_output, scaling_mode_atom,
765
 
                                        XA_STRING, 8, PropModeReplace, 
766
 
                                        strlen(existing_scale_name),
767
 
                                        existing_scale_name, FALSE, TRUE);
768
 
 
769
 
        if (error != 0) {
770
 
                xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
771
 
                        "Failed to set scaling mode, %d\n", error);
772
 
        }
773
 
 
774
 
        if (nv_output->output->type == OUTPUT_TMDS || nv_output->output->type == OUTPUT_LVDS) {
775
 
                /*
776
 
                 * Setup dithering property.
777
 
                 */
778
 
                dithering_atom = MakeAtom(DITHERING_MODE_NAME, sizeof(DITHERING_MODE_NAME) - 1, TRUE);
779
 
 
780
 
                error = RRConfigureOutputProperty(output->randr_output,
781
 
                                                dithering_atom, TRUE, TRUE, FALSE,
782
 
                                                2, dithering_range);
783
 
 
784
 
                if (error != 0) {
785
 
                        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
786
 
                                "RRConfigureOutputProperty error, %d\n", error);
787
 
                }
788
 
 
789
 
                error = RRChangeOutputProperty(output->randr_output, dithering_atom,
790
 
                                                XA_INTEGER, 32, PropModeReplace, 1, &nv_output->output->dithering,
791
 
                                                FALSE, TRUE);
792
 
 
793
 
                if (error != 0) {
794
 
                        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
795
 
                                "Failed to set dithering mode, %d\n", error);
796
 
                }
797
 
        }
798
 
}
799
 
 
800
 
Bool
801
 
nv50_output_set_property(xf86OutputPtr output, Atom property,
802
 
                                RRPropertyValuePtr value)
803
 
{
804
 
        NV50OutputPrivatePtr nv_output = output->driver_private;
805
 
 
806
 
        if (property == scaling_mode_atom) {
807
 
                int32_t ret;
808
 
                char *name = NULL;
809
 
 
810
 
                if (value->type != XA_STRING || value->format != 8)
811
 
                        return FALSE;
812
 
 
813
 
                name = (char *) value->data;
814
 
 
815
 
                /* Match a string to a scaling mode */
816
 
                ret = nv_scaling_mode_lookup(name, value->size);
817
 
                if (ret == SCALE_INVALID)
818
 
                        return FALSE;
819
 
 
820
 
                /* LVDS must always use gpu scaling. */
821
 
                if (ret == SCALE_PANEL && nv_output->output->type == OUTPUT_LVDS)
822
 
                        return FALSE;
823
 
 
824
 
                nv_output->output->scale_mode = ret;
825
 
                if (nv_output->output->crtc) /* normally prepare sets all these things for the crtc. */
826
 
                        nv_output->output->crtc->scale_mode = ret;
827
 
                return TRUE;
828
 
        } else if (property == dithering_atom) {
829
 
                if (value->type != XA_INTEGER || value->format != 32)
830
 
                        return FALSE;
831
 
 
832
 
                int32_t val = *(int32_t *) value->data;
833
 
 
834
 
                if (val < 0 || val > 1)
835
 
                        return FALSE;
836
 
 
837
 
                nv_output->output->dithering = val;
838
 
                if (nv_output->output->crtc) /* normally prepare sets all these things for the crtc. */
839
 
                        nv_output->output->crtc->dithering = val;
840
 
                return TRUE;
841
 
        }
842
 
 
843
 
        return TRUE;
844
 
}
845
 
 
846
 
static const xf86OutputFuncsRec nv50_output_funcs = {
847
 
        .dpms = nv50_output_dpms,
848
 
        .save = NULL,
849
 
        .restore = NULL,
850
 
        .mode_valid = nv50_output_mode_valid,
851
 
        .mode_fixup = nv50_output_mode_fixup,
852
 
        .mode_set = nv50_output_mode_set,
853
 
        .detect = nv50_output_detect,
854
 
        .get_modes = nv50_output_get_modes,
855
 
        .destroy = nv50_output_destroy,
856
 
        .prepare = nv50_output_prepare,
857
 
        .commit = nv50_output_commit,
858
 
#ifdef RANDR_GET_CRTC_INTERFACE
859
 
        .get_crtc = nv50_output_get_crtc,
860
 
#endif /*RANDR_GET_CRTC_INTERFACE */
861
 
        .create_resources = nv50_output_create_resources,
862
 
        .set_property = nv50_output_set_property,
863
 
};
864
 
 
865
 
void
866
 
nv50_output_create(ScrnInfoPtr pScrn)
867
 
{
868
 
        NVPtr pNv = NVPTR(pScrn);
869
 
        xf86OutputPtr output;
870
 
        NV50OutputPrivatePtr nv_output;
871
 
        int i;
872
 
 
873
 
        /* this is a 1:1 hookup of the connectors. */
874
 
        for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++) {
875
 
                if (!(pNv->connector[i]->outputs[0]))
876
 
                        continue; /* An empty connector is not useful. */
877
 
 
878
 
                if (!(output = xf86OutputCreate(pScrn, &nv50_output_funcs, pNv->connector[i]->name)))
879
 
                        return;
880
 
 
881
 
                if (!(nv_output = xnfcalloc(sizeof(NV50OutputPrivateRec), 1)))
882
 
                        return;
883
 
 
884
 
                output->driver_private = nv_output;
885
 
 
886
 
                nv_output->output = pNv->connector[i]->outputs[0]; /* initially just wire up the first output available. */
887
 
 
888
 
                output->possible_crtcs = nv_output->output->allowed_crtc;
889
 
                output->possible_clones = 0;
890
 
 
891
 
                if (nv_output->output->type == OUTPUT_TMDS || nv_output->output->type == OUTPUT_LVDS) {
892
 
                        output->doubleScanAllowed = false;
893
 
                        output->interlaceAllowed = false;
894
 
                } else {
895
 
                        output->doubleScanAllowed = true;
896
 
                        output->interlaceAllowed = true;
897
 
                }
898
 
        }
899
 
}