2
* Copyright 2008 Maarten Maathuis
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:
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
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
23
#include "nv50_randr.h"
24
#include "X11/Xatom.h"
27
* A randr-1.2 wrapper around the NV50 driver.
35
nv50_crtc_dpms(xf86CrtcPtr crtc, int mode)
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");
43
nv_crtc->crtc->active = TRUE;
49
nv_crtc->crtc->active = FALSE;
55
nv50_crtc_lock(xf86CrtcPtr crtc)
61
nv50_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
62
DisplayModePtr adjusted_mode)
68
nv50_crtc_prepare(xf86CrtcPtr crtc)
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;
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;
84
NV50CrtcPrivatePtr nv50_crtc =
85
output->crtc->driver_private;
86
nv_output->crtc = nv50_crtc->crtc;
88
nv_output->crtc = NULL;
92
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
93
"nv50_crtc_prepare is called for %s.\n",
94
nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
96
nv_crtc->crtc->active = TRUE;
97
nv_crtc->crtc->modeset_lock = TRUE;
99
/* Detach any unused outputs. */
100
for (output = pNv->output; output != NULL; output = output->next) {
102
output->ModeSet(output, NULL);
107
nv50_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
108
DisplayModePtr adjusted_mode, int x, int y)
110
ScrnInfoPtr pScrn = crtc->scrn;
111
NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
112
struct nouveau_bo *bo;
114
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
115
"nv50_crtc_mode_set is called for %s.\n",
116
nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
118
NVPtr pNv = NVPTR(pScrn);
121
if (crtc->rotatedData) {
122
bo = nv_crtc->shadow;
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);
133
nv50_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, int size)
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");
139
nv_crtc->crtc->GammaSet(nv_crtc->crtc, (uint16_t *) red, (uint16_t *) green, (uint16_t *) blue, size);
143
nv50_crtc_commit(xf86CrtcPtr crtc)
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");
149
NVPtr pNv = NVPTR(pScrn);
151
/* Let's detect any outputs and connectors that have gone inactive. */
152
uint8_t crtc_active_mask = 0;
154
nouveauOutputPtr output;
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];
162
crtc_active_mask |= 1 << output->crtc->index;
163
connector_active = TRUE;
165
output->active = FALSE;
170
pNv->connector[i]->active = connector_active;
173
/* Blank any crtc's that are inactive. */
174
if (!(crtc_active_mask & (1 << 0)))
175
pNv->crtc[0]->Blank(pNv->crtc[0], TRUE);
177
if (!(crtc_active_mask & (1 << 1)))
178
pNv->crtc[1]->Blank(pNv->crtc[1], TRUE);
180
xf86_reload_cursors(pScrn->pScreen);
182
NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
184
nv_crtc->crtc->modeset_lock = FALSE;
192
nv50_crtc_show_cursor(xf86CrtcPtr crtc)
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");
198
if (!nv_crtc->crtc->blanked)
199
nv_crtc->crtc->ShowCursor(nv_crtc->crtc, FALSE);
203
nv50_crtc_hide_cursor(xf86CrtcPtr crtc)
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");
209
nv_crtc->crtc->HideCursor(nv_crtc->crtc, FALSE);
213
nv50_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
215
NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
217
nv_crtc->crtc->SetCursorPosition(nv_crtc->crtc, x, y);
221
nv50_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *src)
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");
227
nv_crtc->crtc->LoadCursor(nv_crtc->crtc, TRUE, (uint32_t *) src);
231
nv50_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
233
ScrnInfoPtr pScrn = crtc->scrn;
234
NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
235
NVPtr pNv = NVPTR(pScrn);
238
ErrorF("nv50_crtc_shadow_allocate\n");
240
pitch = pScrn->displayWidth * (pScrn->bitsPerPixel/8);
241
size = pitch * height;
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");
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");
256
pNv->shadow[nv_crtc->crtc->index] = nv_crtc->shadow;
258
return nv_crtc->shadow->map;
262
nv50_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
264
ScrnInfoPtr pScrn = crtc->scrn;
266
PixmapPtr rotate_pixmap;
268
ErrorF("nv50_crtc_shadow_create\n");
271
data = crtc->funcs->shadow_allocate (crtc, width, height);
273
pitch = pScrn->displayWidth * (pScrn->bitsPerPixel/8);
275
rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen,
282
if (rotate_pixmap == NULL) {
283
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
284
"Couldn't allocate shadow pixmap for rotated CRTC\n");
287
return rotate_pixmap;
291
nv50_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
293
ScrnInfoPtr pScrn = crtc->scrn;
294
NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
295
NVPtr pNv = NVPTR(pScrn);
296
ScreenPtr pScreen = pScrn->pScreen;
298
ErrorF("nv50_crtc_shadow_destroy\n");
301
pScreen->DestroyPixmap(rotate_pixmap);
304
nouveau_bo_ref(NULL, &nv_crtc->shadow);
306
nv_crtc->shadow = NULL;
307
/* for easy acces by exa */
308
pNv->shadow[nv_crtc->crtc->index] = NULL;
311
#if XF86_CRTC_VERSION >= 2
313
nv50_crtc_set_origin(xf86CrtcPtr crtc, int x, int y)
315
ScrnInfoPtr pScrn = crtc->scrn;
316
NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
317
nouveauCrtcPtr nvcrtc = nv_crtc->crtc; /* sigh.. */
318
NVPtr pNv = NVPTR(pScrn);
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;
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) |
331
NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
336
nv50_crtc_destroy(xf86CrtcPtr crtc)
338
xfree(crtc->driver_private);
341
static const xf86CrtcFuncsRec nv50_crtc_funcs = {
342
.dpms = nv50_crtc_dpms,
345
.lock = nv50_crtc_lock,
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,
366
nv50_crtc_init(ScrnInfoPtr pScrn, int crtc_num)
368
NVPtr pNv = NVPTR(pScrn);
370
NV50CrtcPrivatePtr nv_crtc;
372
crtc = xf86CrtcCreate(pScrn, &nv50_crtc_funcs);
376
nv_crtc = xnfcalloc (sizeof (NV50CrtcPrivateRec), 1);
377
nv_crtc->crtc = pNv->crtc[crtc_num];
379
crtc->driver_private = nv_crtc;
388
nv50_output_dpms(xf86OutputPtr output, int mode)
390
ScrnInfoPtr pScrn = output->scrn;
391
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_dpms is called with mode %d.\n", mode);
393
NVPtr pNv = NVPTR(pScrn);
394
NV50OutputPrivatePtr nv_output = output->driver_private;
396
/* Keep the crtc wiring consistent with randr-1.2 */
398
NV50CrtcPrivatePtr nv_crtc = output->crtc->driver_private;
399
nv_output->output->crtc = nv_crtc->crtc;
401
nv_output->output->crtc = NULL;
404
/* Our crtc's map 1:1 onto randr-1.2 crtc's. */
407
nv_output->output->active = TRUE;
409
case DPMSModeSuspend:
410
case DPMSModeStandby:
413
nv_output->output->active = FALSE;
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];
421
for (i = 0; i < MAX_OUTPUTS_PER_CONNECTOR; i++) {
422
if (connector->outputs[i])
423
connector->outputs[i]->SetPowerMode(connector->outputs[i], mode);
428
nv50_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
430
ScrnInfoPtr pScrn = output->scrn;
431
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_mode_valid is called.\n");
433
NV50OutputPrivatePtr nv_output = output->driver_private;
435
return nv_output->output->ModeValid(nv_output->output, mode);
439
nv50_output_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
445
nv50_output_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
447
ScrnInfoPtr pScrn = output->scrn;
448
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_mode_set is called.\n");
450
NV50OutputPrivatePtr nv_output = output->driver_private;
452
nv_output->output->ModeSet(nv_output->output, mode);
455
static xf86OutputStatus
456
nv50_output_detect(xf86OutputPtr output)
458
ScrnInfoPtr pScrn = output->scrn;
459
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_detect is called.\n");
461
NVPtr pNv = NVPTR(pScrn);
462
NV50OutputPrivatePtr nv_output = output->driver_private;
463
nouveauConnectorPtr connector =
464
pNv->connector[nv_output->output->dcb->i2c_index];
467
return XF86OutputStatusDisconnected;
469
Bool detect_present = FALSE;
470
Bool detect_digital = FALSE;
471
xf86MonPtr ddc_mon = connector->DDCDetect(connector);
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;
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;
492
* We abuse randr-1.2 outputs as connector, so here we have to determine what actual output is connected to the connector.
494
if (ddc_mon || detect_present) {
495
Bool is_digital = FALSE;
497
nouveauCrtcPtr crtc_backup = nv_output->output->crtc;
498
nv_output->output->crtc = NULL;
499
nv_output->output->connector = NULL;
502
is_digital = ddc_mon->features.input_type;
504
is_digital = detect_digital;
506
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected a %s output on %s\n", is_digital ? "Digital" : "Analog", connector->name);
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)) {
511
} else if (is_digital && (connector->outputs[i]->type == OUTPUT_TMDS || connector->outputs[i]->type == OUTPUT_LVDS)) {
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];
525
if (ddc_mon || detect_present) {
527
return XF86OutputStatusConnected;
529
return XF86OutputStatusDisconnected;
533
static DisplayModePtr
534
nv50_output_get_modes(xf86OutputPtr output)
536
ScrnInfoPtr pScrn = output->scrn;
537
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_detect is called.\n");
539
NVPtr pNv = NVPTR(pScrn);
540
NV50OutputPrivatePtr nv_output = output->driver_private;
541
nouveauConnectorPtr connector =
542
pNv->connector[nv_output->output->dcb->i2c_index];
544
xf86MonPtr ddc_mon = connector->DDCDetect(connector);
546
xf86OutputSetEDID(output, ddc_mon);
548
DisplayModePtr ddc_modes = connector->GetDDCModes(connector);
549
DisplayModePtr default_modes = NULL;
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;
556
/* typically only LVDS will hit this code path. */
558
DisplayModeRec mode = {};
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);
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");
572
if (!ddc_modes && nv_output->output->type == OUTPUT_LVDS) {
573
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "LVDS and no modes found, bailing out.\n");
577
/* NV5x hardware can also do scaling on analog connections. */
579
/* Use the first preferred mode as native mode. */
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);
592
/* TODO: Scaling needs a native mode, maybe fail in a better way. */
595
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
596
"%s: no preferred mode found, using %s\n",
597
output->name, mode->name);
600
nv_output->output->native_mode = xf86DuplicateMode(mode);
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);
607
xf86SetModeCrtc(nv_output->output->native_mode, 0);
609
if (nv_output->output->crtc)
610
nv_output->output->crtc->native_mode = nv_output->output->native_mode;
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);
618
default_modes = xf86GetDefaultModes();
622
xf86ModesAdd(ddc_modes, default_modes);
627
nv50_output_destroy(xf86OutputPtr output)
629
NV50OutputPrivatePtr nv_output = output->driver_private;
631
xf86DeleteMode(&nv_output->output->native_mode, nv_output->output->native_mode);
633
xfree(output->driver_private);
634
output->driver_private = NULL;
638
nv50_output_prepare(xf86OutputPtr output)
640
ScrnInfoPtr pScrn = output->scrn;
641
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_prepare is called.\n");
643
NV50OutputPrivatePtr nv_output = output->driver_private;
644
NV50CrtcPrivatePtr nv_crtc = output->crtc->driver_private;
646
/* Set the real crtc now. */
647
nv_output->output->crtc = nv_crtc->crtc;
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;
654
if (nv_output->output->scale_mode != SCALE_PANEL)
655
nv_output->output->crtc->use_native_mode = TRUE;
657
nv_output->output->crtc->use_native_mode = FALSE;
661
nv50_output_commit(xf86OutputPtr output)
663
ScrnInfoPtr pScrn = output->scrn;
664
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_commit is called.\n");
667
#ifdef RANDR_GET_CRTC_INTERFACE
669
nv50_output_get_crtc(xf86OutputPtr output)
671
ScrnInfoPtr pScrn = output->scrn;
672
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_output_get_crtc is called.\n");
674
NV50OutputPrivatePtr nv_output = output->driver_private;
675
nouveauCrtcPtr crtc = nv_output->output->GetCurrentCrtc(nv_output->output);
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.
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];
694
#endif /* RANDR_GET_CRTC_INTERFACE */
701
* Several scaling modes exist, let the user choose.
703
#define SCALING_MODE_NAME "SCALING_MODE"
704
static const struct {
706
enum scaling_modes mode;
708
{ "panel", SCALE_PANEL },
709
{ "fullscreen", SCALE_FULLSCREEN },
710
{ "aspect", SCALE_ASPECT },
711
{ "noscale", SCALE_NOSCALE },
712
{ NULL, SCALE_INVALID}
714
static Atom scaling_mode_atom;
716
#define DITHERING_MODE_NAME "DITHERING"
717
static Atom dithering_atom;
720
nv_scaling_mode_lookup(char *name, int size)
724
/* for when name is zero terminated */
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))
734
return scaling_mode[i].mode;
738
nv50_output_create_resources(xf86OutputPtr output)
740
NV50OutputPrivatePtr nv_output = output->driver_private;
741
ScrnInfoPtr pScrn = output->scrn;
742
INT32 dithering_range[2] = { 0, 1 };
746
* Setup scaling mode property.
748
scaling_mode_atom = MakeAtom(SCALING_MODE_NAME, sizeof(SCALING_MODE_NAME) - 1, TRUE);
750
error = RRConfigureOutputProperty(output->randr_output,
751
scaling_mode_atom, TRUE, FALSE, FALSE,
755
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
756
"RRConfigureOutputProperty error, %d\n", error);
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;
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);
770
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
771
"Failed to set scaling mode, %d\n", error);
774
if (nv_output->output->type == OUTPUT_TMDS || nv_output->output->type == OUTPUT_LVDS) {
776
* Setup dithering property.
778
dithering_atom = MakeAtom(DITHERING_MODE_NAME, sizeof(DITHERING_MODE_NAME) - 1, TRUE);
780
error = RRConfigureOutputProperty(output->randr_output,
781
dithering_atom, TRUE, TRUE, FALSE,
785
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
786
"RRConfigureOutputProperty error, %d\n", error);
789
error = RRChangeOutputProperty(output->randr_output, dithering_atom,
790
XA_INTEGER, 32, PropModeReplace, 1, &nv_output->output->dithering,
794
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
795
"Failed to set dithering mode, %d\n", error);
801
nv50_output_set_property(xf86OutputPtr output, Atom property,
802
RRPropertyValuePtr value)
804
NV50OutputPrivatePtr nv_output = output->driver_private;
806
if (property == scaling_mode_atom) {
810
if (value->type != XA_STRING || value->format != 8)
813
name = (char *) value->data;
815
/* Match a string to a scaling mode */
816
ret = nv_scaling_mode_lookup(name, value->size);
817
if (ret == SCALE_INVALID)
820
/* LVDS must always use gpu scaling. */
821
if (ret == SCALE_PANEL && nv_output->output->type == OUTPUT_LVDS)
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;
828
} else if (property == dithering_atom) {
829
if (value->type != XA_INTEGER || value->format != 32)
832
int32_t val = *(int32_t *) value->data;
834
if (val < 0 || val > 1)
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;
846
static const xf86OutputFuncsRec nv50_output_funcs = {
847
.dpms = nv50_output_dpms,
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,
866
nv50_output_create(ScrnInfoPtr pScrn)
868
NVPtr pNv = NVPTR(pScrn);
869
xf86OutputPtr output;
870
NV50OutputPrivatePtr nv_output;
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. */
878
if (!(output = xf86OutputCreate(pScrn, &nv50_output_funcs, pNv->connector[i]->name)))
881
if (!(nv_output = xnfcalloc(sizeof(NV50OutputPrivateRec), 1)))
884
output->driver_private = nv_output;
886
nv_output->output = pNv->connector[i]->outputs[0]; /* initially just wire up the first output available. */
888
output->possible_crtcs = nv_output->output->allowed_crtc;
889
output->possible_clones = 0;
891
if (nv_output->output->type == OUTPUT_TMDS || nv_output->output->type == OUTPUT_LVDS) {
892
output->doubleScanAllowed = false;
893
output->interlaceAllowed = false;
895
output->doubleScanAllowed = true;
896
output->interlaceAllowed = true;