Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1029 serge 1
/*
2
 * Copyright 2007, 2008  Luc Verhaegen 
3
 * Copyright 2007, 2008  Matthias Hopf 
4
 * Copyright 2007, 2008  Egbert Eich   
5
 * Copyright 2007, 2008  Advanced Micro Devices, Inc.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
21
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
 
26
#ifdef HAVE_CONFIG_H
27
#include "config.h"
28
#endif
29
 
30
#include "xf86.h"
31
 
32
/* for usleep */
33
#if HAVE_XF86_ANSIC_H
34
# include "xf86_ansic.h"
35
#else
36
# include 
37
# include 
38
# include 
39
#endif
40
 
41
#include "rhd.h"
42
#include "edid.h"
43
#include "rhd_connector.h"
44
#include "rhd_output.h"
45
#include "rhd_crtc.h"
46
#include "rhd_atombios.h"
47
#include "rhd_atomout.h"
48
#include "rhd_biosscratch.h"
49
#include "rhd_hdmi.h"
50
 
51
#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER)
52
struct rhdAtomOutputPrivate {
53
    Bool Stored;
54
 
55
    struct atomCodeTableVersion EncoderVersion;
56
    struct atomCodeTableVersion CrtcSourceVersion;
57
    struct atomEncoderConfig EncoderConfig;
58
    enum atomEncoder EncoderId;
59
 
60
    struct atomTransmitterConfig TransmitterConfig;
61
    enum atomTransmitter TransmitterId;
62
 
63
    enum atomOutput OutputControlId;
64
 
65
    Bool   RunDualLink;
66
    int    PixelClock;
67
 
68
    void  *Save;
69
 
70
    CARD16 PowerDigToDE;
71
    CARD16 PowerDEToBL;
72
    CARD16 OffDelay;
73
    Bool   TemporalDither;
74
    Bool   SpatialDither;
75
    int    GreyLevel;
76
    Bool   DualLink;
77
    Bool   LVDS24Bit;
78
    Bool   FPDI;
79
 
80
    Bool   Coherent;
81
    DisplayModePtr Mode;
82
    struct rhdHdmi *Hdmi;
83
 
84
    int    BlLevel;
85
};
86
 
87
#define ERROR_MSG(x) 	xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: %s failed.\n", __func__, x)
88
 
89
/*
90
 *
91
 */
92
static inline void
93
rhdSetEncoderTransmitterConfig(struct rhdOutput *Output, int PixelClock)
94
{
95
    RHDPtr rhdPtr = RHDPTRI(Output);
96
    struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
97
    struct atomEncoderConfig *EncoderConfig = &Private->EncoderConfig;
98
    struct atomTransmitterConfig *TransmitterConfig = &Private->TransmitterConfig;
99
 
100
    RHDFUNC(Output);
101
 
102
    EncoderConfig->PixelClock = TransmitterConfig->PixelClock = PixelClock;
103
 
104
    switch (Output->Id) {
105
	case RHD_OUTPUT_NONE:
106
	    break;
107
	case RHD_OUTPUT_DVO:
108
 
109
	    EncoderConfig->u.dvo.DvoDeviceType = Output->OutputDriverPrivate->Device;
110
	    switch (EncoderConfig->u.dvo.DvoDeviceType) {
111
		case atomCRT1:
112
		case atomCRT2:
113
		    EncoderConfig->u.dvo.digital = FALSE;
114
		break;
115
		case atomTV1:
116
		case atomTV2:
117
		case atomCV:
118
		    EncoderConfig->u.dvo.digital = FALSE;
119
		    EncoderConfig->u.dvo.u.TVMode = rhdPtr->tvMode;
120
		break;
121
		case atomLCD1:
122
		case atomDFP1:
123
		case atomDFP2:
124
		case atomLCD2:
125
		case atomDFP3:
126
		case atomDFP4:
127
		case atomDFP5:
128
		    EncoderConfig->u.dvo.digital = TRUE;
129
		    /* @@@ no digital attributes, yet */
130
		break;
131
		case atomNone:
132
		    break;
133
	    }
134
	    break;
135
	case RHD_OUTPUT_DACA:
136
	case RHD_OUTPUT_DACB:
137
	    switch (Output->SensedType) {
138
		case RHD_SENSED_VGA:
139
		    EncoderConfig->u.dac.DacStandard = atomDAC_VGA;
140
		    break;
141
		case RHD_SENSED_TV_COMPONENT:
142
		    EncoderConfig->u.dac.DacStandard = atomDAC_CV;
143
		    break;
144
		case RHD_SENSED_TV_SVIDEO:
145
		case RHD_SENSED_TV_COMPOSITE:
146
		    switch (rhdPtr->tvMode) {
147
			case RHD_TV_NTSC:
148
			case RHD_TV_NTSCJ:
149
			    EncoderConfig->u.dac.DacStandard = atomDAC_NTSC;
150
			    /* NTSC */
151
			    break;
152
			case RHD_TV_PAL:
153
			case RHD_TV_PALN:
154
			case RHD_TV_PALCN:
155
			case RHD_TV_PAL60:
156
			default:
157
			    EncoderConfig->u.dac.DacStandard = atomDAC_PAL;
158
			    /* PAL */
159
			    break;
160
		    }
161
		    break;
162
		case RHD_SENSED_NONE:
163
		    EncoderConfig->u.dac.DacStandard = atomDAC_VGA;
164
		    break;
165
		default:
166
		    xf86DrvMsg(Output->scrnIndex, X_ERROR, "Sensed incompatible output for DAC\n");
167
		    EncoderConfig->u.dac.DacStandard = atomDAC_VGA;
168
		    break;
169
	    }
170
	    break;
171
 
172
	case RHD_OUTPUT_TMDSA:
173
	case RHD_OUTPUT_LVTMA:
174
	    if (Output->Connector && PixelClock > 0) {
175
		if (Output->Connector->Type == RHD_CONNECTOR_DVI
176
#if 0
177
		    || Output->Connector->Type == RHD_CONNECTOR_HDMI_B
178
#endif
179
		    )
180
		    Private->RunDualLink = (PixelClock > 165000) ? TRUE : FALSE;
181
		else
182
		    Private->RunDualLink = FALSE;
183
	    } else
184
		/* only get here for power down: thus power down both channels to be save */
185
		Private->RunDualLink = TRUE;
186
 
187
	    switch (Private->EncoderVersion.cref) {
188
		case 1:
189
		    if (Private->RunDualLink)
190
			EncoderConfig->u.lvds.LinkCnt = atomDualLink;
191
		    else
192
			EncoderConfig->u.lvds.LinkCnt = atomSingleLink;
193
		    break;
194
		case 2:
195
		case 3:
196
		    if (Private->RunDualLink)
197
			EncoderConfig->u.lvds2.LinkCnt = atomDualLink;
198
		    else
199
			EncoderConfig->u.lvds2.LinkCnt = atomSingleLink;
200
		    if (Private->Coherent)
201
			EncoderConfig->u.lvds2.Coherent = TRUE;
202
		    else
203
			EncoderConfig->u.lvds2.Coherent = FALSE;
204
		    break;
205
	    }
206
	    break;
207
 
208
	case RHD_OUTPUT_KLDSKP_LVTMA:
209
	case RHD_OUTPUT_UNIPHYA:
210
	case RHD_OUTPUT_UNIPHYB:
211
	case RHD_OUTPUT_UNIPHYC:
212
	case RHD_OUTPUT_UNIPHYD:
213
	case RHD_OUTPUT_UNIPHYE:
214
	case RHD_OUTPUT_UNIPHYF:
215
	    if (Output->Connector && PixelClock > 0) {
216
		if (Output->Connector->Type == RHD_CONNECTOR_DVI
217
#if 0
218
		    || Output->Connector->Type == RHD_CONNECTOR_DP_DUAL
219
		    || Output->Connector->Type == RHD_CONNECTOR_HDMI_B
220
#endif
221
		    )
222
		    Private->RunDualLink = (PixelClock > 165000) ? TRUE : FALSE;
223
		else
224
		    Private->RunDualLink = FALSE;
225
	    } else
226
		/* only get here for power down: thus power down both channels to be save */
227
		    Private->RunDualLink = TRUE;
228
 
229
	    if (Private->RunDualLink) {
230
		TransmitterConfig->LinkCnt = EncoderConfig->u.dig.LinkCnt = atomDualLink;
231
		if (TransmitterConfig->Link == atomTransLinkA)
232
		    TransmitterConfig->Link = atomTransLinkAB;
233
		else if (TransmitterConfig->Link == atomTransLinkB)
234
		    TransmitterConfig->Link = atomTransLinkBA;
235
	    } else {
236
		TransmitterConfig->LinkCnt = EncoderConfig->u.dig.LinkCnt = atomSingleLink;
237
		if (TransmitterConfig->Link == atomTransLinkAB)
238
		    TransmitterConfig->Link = atomTransLinkA;
239
		else if (TransmitterConfig->Link == atomTransLinkBA)
240
		    TransmitterConfig->Link = atomTransLinkB;
241
	    }
242
 	    TransmitterConfig->Coherent = Private->Coherent;
243
	    break;
244
    }
245
}
246
 
247
/*
248
 *
249
 */
250
static void
251
atomSetBacklightFromBIOSScratch(struct rhdOutput *Output)
252
{
253
    RHDPtr rhdPtr = RHDPTRI(Output);
254
    struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
255
 
256
    RHDFUNC(Output);
257
 
258
    switch (Output->Id) {
259
	case RHD_OUTPUT_KLDSKP_LVTMA:
260
	case RHD_OUTPUT_UNIPHYA:
261
	case RHD_OUTPUT_UNIPHYB:
262
	case RHD_OUTPUT_UNIPHYC:
263
	case RHD_OUTPUT_UNIPHYD:
264
	case RHD_OUTPUT_UNIPHYE:
265
	case RHD_OUTPUT_UNIPHYF:
266
	    rhdSetEncoderTransmitterConfig(Output, Private->PixelClock);
267
	    if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId,
268
					      atomTransLcdBlBrightness, &Private->TransmitterConfig))
269
		ERROR_MSG("rhdAtomDigTransmitterControl(atomTransEnable)");
270
	    break;
271
	default:
272
	    if (!rhdAtomOutputControl(rhdPtr->atomBIOS, Private->OutputControlId, atomOutputLcdBrightnessControl))
273
		ERROR_MSG("rhdAtomOutputControl(atomOutputLcdBrightnessControl)");
274
	    break;
275
    }
276
}
277
 
278
/*
279
 *
280
 */
281
static void
282
atomSetBacklight(struct rhdOutput *Output, int value)
283
{
284
    RHDPtr rhdPtr = RHDPTRI(Output);
285
 
286
    RHDFUNC(Output);
287
 
288
    RHDAtomBIOSScratchBlLevel(rhdPtr, rhdBIOSScratchBlSet, &value);
289
 
290
    atomSetBacklightFromBIOSScratch(Output);
291
}
292
 
293
/*
294
 *
295
 */
296
static inline void
297
rhdAtomOutputSet(struct rhdOutput *Output, DisplayModePtr Mode)
298
{
299
    RHDPtr rhdPtr = RHDPTRI(Output);
300
    struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
301
    struct atomEncoderConfig *EncoderConfig = &Private->EncoderConfig;
302
    struct atomCrtcSourceConfig CrtcSourceConfig;
303
    union AtomBiosArg data;
304
 
305
    RHDFUNC(Output);
306
 
307
    Private->Mode = Mode;
308
 
309
    data.Address = &Private->Save;
310
    RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data);
311
 
312
    Private->PixelClock = Mode->SynthClock;
313
    rhdSetEncoderTransmitterConfig(Output, Private->PixelClock);
314
 
315
    switch ( Private->CrtcSourceVersion.cref){
316
	case 1:
317
	    CrtcSourceConfig.u.Device = Output->OutputDriverPrivate->Device;
318
	    break;
319
	case 2:
320
	    CrtcSourceConfig.u.crtc2.Encoder = Private->EncoderId;
321
	    CrtcSourceConfig.u.crtc2.Mode = EncoderConfig->u.dig.EncoderMode;
322
	    break;
323
	default:
324
	    xf86DrvMsg(Output->scrnIndex, X_ERROR,
325
		       "Unknown version of SelectCrtcSource code table: %i\n",Private->CrtcSourceVersion.cref);
326
	    return;
327
    }
328
    switch (Output->Id) {
329
	case RHD_OUTPUT_UNIPHYA:
330
	case RHD_OUTPUT_UNIPHYB:
331
 	case RHD_OUTPUT_UNIPHYC:
332
 	case RHD_OUTPUT_UNIPHYD:
333
 	case RHD_OUTPUT_UNIPHYE:
334
 	case RHD_OUTPUT_UNIPHYF:
335
#if 1
336
	    rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, atomTransInit,
337
					 &Private->TransmitterConfig);
338
#endif
339
	case RHD_OUTPUT_KLDSKP_LVTMA:
340
	    rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, atomTransSetup,
341
					 &Private->TransmitterConfig);
342
	    break;
343
	default:
344
	    break;
345
    }
346
 
347
    rhdAtomSelectCrtcSource(rhdPtr->atomBIOS, Output->Crtc->Id ? atomCrtc2 : atomCrtc1, &CrtcSourceConfig);
348
    data.Address = NULL;
349
    RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data);
350
    RHDHdmiSetMode(Private->Hdmi, Mode);
351
}
352
 
353
/*
354
 *
355
 */
356
static inline void
357
rhdAtomOutputPower(struct rhdOutput *Output, int Power)
358
{
359
    RHDPtr rhdPtr = RHDPTRI(Output);
360
    struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
361
    struct atomEncoderConfig *EncoderConfig = &Private->EncoderConfig;
362
    union AtomBiosArg data;
363
    Bool enableHDMI = FALSE;
364
 
365
    RHDFUNC(Output);
366
 
367
    if(Output->Connector != NULL) {
368
	enableHDMI = RHDConnectorEnableHDMI(Output->Connector);
369
	switch(Output->Id) {
370
	    case RHD_OUTPUT_TMDSA:
371
	    case RHD_OUTPUT_LVTMA:
372
		if(enableHDMI && !Private->EncoderConfig.u.lvds2.Hdmi)
373
		    Private->EncoderConfig.u.lvds2.Hdmi = TRUE;
374
		else if(!enableHDMI && Private->EncoderConfig.u.lvds2.Hdmi)
375
		    Private->EncoderConfig.u.lvds2.Hdmi = FALSE;
376
		break;
377
 
378
	    case RHD_OUTPUT_UNIPHYA:
379
	    case RHD_OUTPUT_UNIPHYB:
380
	    case RHD_OUTPUT_KLDSKP_LVTMA:
381
		if(enableHDMI && Private->TransmitterConfig.Mode == atomDVI) {
382
		    Private->TransmitterConfig.Mode = atomHDMI;
383
		    Private->EncoderConfig.u.dig.EncoderMode = atomHDMI;
384
 
385
		} else if(!enableHDMI && Private->TransmitterConfig.Mode == atomHDMI) {
386
		    Private->TransmitterConfig.Mode = atomDVI;
387
		    Private->EncoderConfig.u.dig.EncoderMode = atomDVI;
388
		}
389
		break;
390
 
391
	    default:
392
		break;
393
	}
394
    }
395
 
396
    data.Address = &Private->Save;
397
    RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data);
398
 
399
    rhdSetEncoderTransmitterConfig(Output, Private->PixelClock);
400
 
401
    switch (Power) {
402
	case RHD_POWER_ON:
403
	    RHDDebug(Output->scrnIndex, "RHD_POWER_ON\n");
404
	    rhdAtomEncoderControl(rhdPtr->atomBIOS,  Private->EncoderId, atomEncoderOn, EncoderConfig);
405
	    switch (Output->Id) {
406
		case RHD_OUTPUT_KLDSKP_LVTMA:
407
		case RHD_OUTPUT_UNIPHYA:
408
		case RHD_OUTPUT_UNIPHYB:
409
		case RHD_OUTPUT_UNIPHYC:
410
		case RHD_OUTPUT_UNIPHYD:
411
		case RHD_OUTPUT_UNIPHYE:
412
		case RHD_OUTPUT_UNIPHYF:
413
		    if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId,
414
						      atomTransEnable, &Private->TransmitterConfig)) {
415
			ERROR_MSG("rhdAtomDigTransmitterControl(atomTransEnable)");
416
			break;
417
		    }
418
		    if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId,
419
						      atomTransEnableOutput, &Private->TransmitterConfig))
420
			ERROR_MSG("rhdAtomDigTransmitterControl(atomTransEnableOutput)");
421
		    break;
422
		default:
423
		    if (!rhdAtomOutputControl(rhdPtr->atomBIOS, Private->OutputControlId, atomOutputEnable))
424
			ERROR_MSG("rhdAtomOutputControl(atomOutputEnable)");
425
		    break;
426
	    }
427
	    RHDHdmiEnable(Private->Hdmi, enableHDMI);
428
	    break;
429
	case RHD_POWER_RESET:
430
	    RHDDebug(Output->scrnIndex, "RHD_POWER_RESET\n");
431
	    switch (Output->Id) {
432
		case RHD_OUTPUT_KLDSKP_LVTMA:
433
		case RHD_OUTPUT_UNIPHYA:
434
		case RHD_OUTPUT_UNIPHYB:
435
		case RHD_OUTPUT_UNIPHYC:
436
		case RHD_OUTPUT_UNIPHYD:
437
		case RHD_OUTPUT_UNIPHYE:
438
		case RHD_OUTPUT_UNIPHYF:
439
		    if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId,
440
						      atomTransDisableOutput, &Private->TransmitterConfig))
441
			ERROR_MSG("rhdAtomDigTransmitterControl(atomTransDisableOutput)");
442
		    break;
443
		default:
444
		    if (!rhdAtomOutputControl(rhdPtr->atomBIOS, Private->OutputControlId, atomOutputDisable))
445
			ERROR_MSG("rhdAtomOutputControl(atomOutputDisable)");
446
		    break;
447
	    }
448
	    break;
449
	case RHD_POWER_SHUTDOWN:
450
	    RHDDebug(Output->scrnIndex, "RHD_POWER_SHUTDOWN\n");
451
	    switch (Output->Id) {
452
		case RHD_OUTPUT_KLDSKP_LVTMA:
453
		case RHD_OUTPUT_UNIPHYA:
454
		case RHD_OUTPUT_UNIPHYB:
455
		case RHD_OUTPUT_UNIPHYC:
456
		case RHD_OUTPUT_UNIPHYD:
457
		case RHD_OUTPUT_UNIPHYE:
458
		case RHD_OUTPUT_UNIPHYF:
459
		    if (Private->EncoderId == atomEncoderNone)
460
			break;
461
		    if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId,
462
						      atomTransDisableOutput, &Private->TransmitterConfig)) {
463
			ERROR_MSG("rhdAtomDigTransmitterControl(atomTransDisableOutput)");
464
			break;
465
		    }
466
		    if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId,
467
						      atomTransDisable, &Private->TransmitterConfig))
468
			ERROR_MSG("rhdAtomDigTransmitterControl(atomTransDisable)");
469
		    break;
470
		default:
471
		    if (!rhdAtomOutputControl(rhdPtr->atomBIOS, Private->OutputControlId, atomOutputDisable))
472
			ERROR_MSG("rhdAtomOutputControl(atomOutputDisable)");
473
		    break;
474
	    }
475
	    if (Private->EncoderId != atomEncoderNone)
476
	    if (!rhdAtomEncoderControl(rhdPtr->atomBIOS, Private->EncoderId, atomEncoderOff, &Private->EncoderConfig))
477
		ERROR_MSG("rhdAtomEncoderControl(atomEncoderOff)");
478
	    RHDHdmiEnable(Private->Hdmi, FALSE);
479
	    break;
480
    }
481
 
482
    data.Address = NULL;
483
    RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data);
484
}
485
 
486
/*
487
 *
488
 */
489
static inline void
490
rhdAtomOutputSave(struct rhdOutput *Output)
491
{
492
     struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
493
     RHDHdmiSave(Private->Hdmi);
494
}
495
 
496
/*
497
 *
498
 */
499
static void
500
rhdAtomOutputRestore(struct rhdOutput *Output)
501
{
502
     struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
503
     RHDPtr rhdPtr = RHDPTRI(Output);
504
     union AtomBiosArg data;
505
 
506
     data.Address = &Private->Save;
507
     RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_RESTORE_REGISTERS, &data);
508
     if (Output->Connector && Output->Connector->Type == RHD_CONNECTOR_PANEL)
509
	 atomSetBacklightFromBIOSScratch(Output);
510
     RHDHdmiRestore(Private->Hdmi);
511
}
512
 
513
/*
514
 *
515
 */
516
static ModeStatus
517
rhdAtomOutputModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
518
{
519
    RHDFUNC(Output);
520
 
521
    if (Mode->Flags & V_INTERLACE)
522
	return MODE_NO_INTERLACE;
523
 
524
    if (Mode->Clock < 25000)
525
	return MODE_CLOCK_LOW;
526
 
527
 
528
    if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE
529
#if 0
530
		|| Output->Connector->Type == RHD_CONNECTOR_DP_DUAL
531
		|| Output->Connector->Type == RHD_CONNECTOR_HDMI_B
532
#endif
533
	) {
534
	if (Mode->Clock > 165000)
535
	    return MODE_CLOCK_HIGH;
536
    }
537
    else if (Output->Connector->Type == RHD_CONNECTOR_DVI) {
538
	if (Mode->Clock > 330000) /* could go higher still */
539
	    return MODE_CLOCK_HIGH;
540
    }
541
 
542
    return MODE_OK;
543
}
544
 
545
 
546
/*
547
 *
548
 */
549
static Bool
550
LVDSInfoRetrieve(RHDPtr rhdPtr, struct rhdAtomOutputPrivate *Private)
551
{
552
    AtomBiosArgRec data;
553
 
554
    if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
555
			ATOM_LVDS_SEQ_DIG_ONTO_DE, &data) != ATOM_SUCCESS)
556
	return FALSE;
557
    Private->PowerDigToDE = data.val;
558
 
559
    if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
560
			ATOM_LVDS_SEQ_DE_TO_BL, &data) != ATOM_SUCCESS)
561
	return FALSE;
562
    Private->PowerDEToBL = data.val;
563
 
564
    if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
565
			ATOM_LVDS_OFF_DELAY, &data) != ATOM_SUCCESS)
566
	return FALSE;
567
    Private->OffDelay = data.val;
568
 
569
    if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
570
			ATOM_LVDS_DUALLINK, &data) != ATOM_SUCCESS)
571
	return FALSE;
572
    Private->DualLink = data.val;
573
 
574
    if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
575
			ATOM_LVDS_24BIT, &data) != ATOM_SUCCESS)
576
	return FALSE;
577
    Private->LVDS24Bit = data.val;
578
 
579
    if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
580
			ATOM_LVDS_FPDI, &data) != ATOM_SUCCESS)
581
	return FALSE;
582
    Private->FPDI = data.val;
583
 
584
    if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
585
			ATOM_LVDS_TEMPORAL_DITHER, &data) != ATOM_SUCCESS)
586
	return FALSE;
587
    Private->TemporalDither = data.val;
588
 
589
    if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
590
			ATOM_LVDS_SPATIAL_DITHER, &data) != ATOM_SUCCESS)
591
	return FALSE;
592
    Private->SpatialDither = data.val;
593
 
594
    if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
595
			ATOM_LVDS_GREYLVL, &data) != ATOM_SUCCESS)
596
	return FALSE;
597
    {
598
	Private->GreyLevel = data.val;
599
	xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "AtomBIOS returned %i Grey Levels\n",
600
		   Private->GreyLevel);
601
    }
602
    Private->Coherent = FALSE;
603
 
604
    RHDAtomBIOSScratchBlLevel(rhdPtr, rhdBIOSScratchBlGet, &Private->BlLevel);
605
 
606
    return TRUE;
607
}
608
 
609
/*
610
 * TMDSInfoRetrieve() - interface to set TMDS (DVI) parameters.
611
 */
612
static Bool
613
TMDSInfoRetrieve(RHDPtr rhdPtr, struct rhdAtomOutputPrivate *Private)
614
{
615
    Private->FPDI = FALSE;
616
    Private->TemporalDither = FALSE;
617
    Private->SpatialDither = FALSE;
618
    Private->GreyLevel = 0;
619
    Private->BlLevel = -1;
620
 
621
    return TRUE;
622
}
623
 
624
/*
625
 *
626
 */
627
static Bool
628
atomLVDSPropertyControl(struct rhdOutput *Output,
629
	     enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val)
630
{
631
    struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
632
 
633
    RHDFUNC(Output);
634
    switch (Action) {
635
	case rhdPropertyCheck:
636
	    if (Private->BlLevel < 0)
637
		return FALSE;
638
	switch (Property) {
639
	    case RHD_OUTPUT_BACKLIGHT:
640
		    return TRUE;
641
	    default:
642
		return FALSE;
643
	}
644
	case rhdPropertyGet:
645
	    if (Private->BlLevel < 0)
646
		return FALSE;
647
	    switch (Property) {
648
		case RHD_OUTPUT_BACKLIGHT:
649
		    val->integer = Private->BlLevel;
650
		    return TRUE;
651
		default:
652
		    return FALSE;
653
	    }
654
	    break;
655
	case rhdPropertySet:
656
	    if (Private->BlLevel < 0)
657
		return FALSE;
658
	    switch (Property) {
659
		case RHD_OUTPUT_BACKLIGHT:
660
		    atomSetBacklight(Output, val->integer);
661
		    return TRUE;
662
		default:
663
		    return FALSE;
664
	    }
665
	    break;
666
    }
667
    return TRUE;
668
}
669
 
670
/*
671
 *
672
 */
673
static Bool
674
atomTMDSPropertyControl(struct rhdOutput *Output,
675
	     enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val)
676
{
677
    struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
678
 
679
    RHDFUNC(Output);
680
    switch (Action) {
681
	case rhdPropertyCheck:
682
	switch (Property) {
683
	    case RHD_OUTPUT_COHERENT:
684
		    return TRUE;
685
	    default:
686
		return FALSE;
687
	}
688
	case rhdPropertyGet:
689
	    switch (Property) {
690
		case RHD_OUTPUT_COHERENT:
691
		    val->Bool =  Private->Coherent;
692
		    return TRUE;
693
		default:
694
		    return FALSE;
695
	    }
696
	    break;
697
	case rhdPropertySet:
698
	    switch (Property) {
699
		case RHD_OUTPUT_COHERENT:
700
		    Private->Coherent = val->Bool;
701
		    Output->Mode(Output, Private->Mode);
702
		    Output->Power(Output, RHD_POWER_ON);
703
		    break;
704
		default:
705
		    return FALSE;
706
	    }
707
	    break;
708
    }
709
    return TRUE;
710
}
711
 
712
/*
713
 *
714
 */
715
static void
716
rhdAtomOutputDestroy(struct rhdOutput *Output)
717
{
718
    struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
719
    RHDFUNC(Output);
720
    if (Private->Save)
721
	xfree(Private->Save);
722
    RHDHdmiDestroy(Private->Hdmi);
723
 
724
    if (Private)
725
	xfree(Private);
726
    Output->Private = NULL;
727
    xfree(Output->Name);
728
}
729
 
730
/*
731
 *
732
 */
733
static Bool
734
RHDAtomOutputAllocFree(struct rhdOutput *Output, enum rhdOutputAllocation Alloc)
735
{
736
    struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private;
737
    struct atomTransmitterConfig *TransmitterConfig = &Private->TransmitterConfig;
738
    RHDPtr rhdPtr = RHDPTRI(Output);
739
    char *TransmitterName;
740
 
741
    RHDFUNC(rhdPtr);
742
 
743
    switch (Output->Id) {
744
	case RHD_OUTPUT_KLDSKP_LVTMA:
745
	    TransmitterName = "KLDSKP_LVTMA";
746
	    break;
747
	case RHD_OUTPUT_UNIPHYA:
748
	    TransmitterName = "KLDSKP_UNIPHYA";
749
	    break;
750
	case RHD_OUTPUT_UNIPHYB:
751
	    TransmitterName = "KLDSKP_UNIPHYB";
752
	    break;
753
	case RHD_OUTPUT_UNIPHYC:
754
	    TransmitterName = "KLDSKP_UNIPHYC";
755
	    break;
756
	case RHD_OUTPUT_UNIPHYD:
757
	    TransmitterName = "KLDSKP_UNIPHYD";
758
	    break;
759
	case RHD_OUTPUT_UNIPHYE:
760
	    TransmitterName = "KLDSKP_UNIPHYE";
761
	    break;
762
	case RHD_OUTPUT_UNIPHYF:
763
	    TransmitterName = "KLDSKP_UNIPHYF";
764
	    break;
765
	default:
766
	    return TRUE;
767
    }
768
 
769
    switch (Alloc) {
770
	case RHD_OUTPUT_ALLOC:
771
	    /*
772
	     * LVTMA can only use DIG2. Thus exclude
773
	     * DIG1 for LVTMA and prefer it for the
774
	     * UNIPHYs.
775
	     */
776
	    if (Private->EncoderId != atomEncoderNone)
777
		return TRUE;
778
	    if (Output->Id != RHD_OUTPUT_KLDSKP_LVTMA
779
		&& !rhdPtr->DigEncoderOutput[0]) {
780
		rhdPtr->DigEncoderOutput[0] = Output;
781
		TransmitterConfig->Encoder = Private->EncoderId = atomEncoderDIG1;
782
		xf86DrvMsg(Output->scrnIndex, X_INFO, "Mapping DIG1 encoder to %s\n",TransmitterName);
783
		return TRUE;
784
	    } else if (!rhdPtr->DigEncoderOutput[1]) {
785
		rhdPtr->DigEncoderOutput[1] = Output;
786
		TransmitterConfig->Encoder = Private->EncoderId = atomEncoderDIG2;
787
		xf86DrvMsg(Output->scrnIndex, X_INFO, "Mapping DIG2 encoder to %s\n",TransmitterName);
788
		return TRUE;
789
	    } else
790
		return FALSE;
791
	case RHD_OUTPUT_FREE:
792
		TransmitterConfig->Encoder = Private->EncoderId = atomEncoderNone;
793
	    if (rhdPtr->DigEncoderOutput[0] == Output) {
794
		rhdPtr->DigEncoderOutput[0] = NULL;
795
		return TRUE;
796
	    } else if (rhdPtr->DigEncoderOutput[1] == Output) {
797
		rhdPtr->DigEncoderOutput[1] = NULL;
798
		return TRUE;
799
	    } else
800
		return FALSE;
801
	    break;
802
	default:
803
	    return FALSE;
804
    }
805
}
806
 
807
/*
808
 *
809
 */
810
struct rhdOutput *
811
RHDAtomOutputInit(RHDPtr rhdPtr, rhdConnectorType ConnectorType,
812
		  rhdOutputType OutputType)
813
{
814
    struct rhdOutput *Output;
815
    struct rhdAtomOutputPrivate *Private;
816
    struct atomEncoderConfig *EncoderConfig;
817
    struct atomTransmitterConfig *TransmitterConfig;
818
    char *OutputName = NULL;
819
 
820
    RHDFUNC(rhdPtr);
821
 
822
    switch (OutputType) {
823
	case RHD_OUTPUT_NONE:
824
	    return NULL;
825
	case  RHD_OUTPUT_DACA:
826
	    OutputName = "DACA";
827
	    break;
828
	case RHD_OUTPUT_DACB:
829
	    OutputName = "DACB";
830
	    break;
831
	case RHD_OUTPUT_TMDSA:
832
	    OutputName = "TMDSA";
833
	    break;
834
	case RHD_OUTPUT_LVTMA:
835
	    OutputName = "LVTMA";
836
	    break;
837
	case RHD_OUTPUT_DVO:
838
	    OutputName = "DVO";
839
	    break;
840
	case RHD_OUTPUT_KLDSKP_LVTMA:
841
	    OutputName = "KldskpLvtma";
842
	    break;
843
	case RHD_OUTPUT_UNIPHYA:
844
	    OutputName = "UniphyA";
845
	    break;
846
	case RHD_OUTPUT_UNIPHYB:
847
	    OutputName = "UniphyB";
848
	    break;
849
	case RHD_OUTPUT_UNIPHYC:
850
	    OutputName = "UniphyC";
851
	    break;
852
	case RHD_OUTPUT_UNIPHYD:
853
	    OutputName = "UniphyD";
854
	    break;
855
	case RHD_OUTPUT_UNIPHYE:
856
	    OutputName = "UniphyE";
857
	    break;
858
	case RHD_OUTPUT_UNIPHYF:
859
	    OutputName = "UniphyF";
860
	    break;
861
    }
862
 
863
    Output = xnfcalloc(sizeof(struct rhdOutput), 1);
864
    Output->scrnIndex = rhdPtr->scrnIndex;
865
 
866
    Output->Name = RhdAppendString(NULL, "AtomOutput");
867
    Output->Name = RhdAppendString(Output->Name, OutputName);
868
 
869
    Output->Id = OutputType;
870
    Output->Sense = NULL;
871
    Private = xnfcalloc(sizeof(struct rhdAtomOutputPrivate), 1);
872
    Output->Private = Private;
873
    Output->OutputDriverPrivate = NULL;
874
 
875
    EncoderConfig = &Private->EncoderConfig;
876
    Private->PixelClock = 0;
877
 
878
    switch (OutputType) {
879
        case RHD_OUTPUT_NONE:
880
	    xfree(Output);
881
	    xfree(Private);
882
	    return NULL;
883
	case RHD_OUTPUT_DACA:
884
	    Output->Sense = RHDBIOSScratchDACSense;
885
	    Private->EncoderId = atomEncoderDACA;
886
	    Private->OutputControlId = atomDAC1Output;
887
	    Private->Hdmi = NULL;
888
	    break;
889
	case RHD_OUTPUT_DACB:
890
	    Output->Sense = RHDBIOSScratchDACSense;
891
	    Private->EncoderId = atomEncoderDACB;
892
	    Private->OutputControlId = atomDAC2Output;
893
	    Private->Hdmi = NULL;
894
	    break;
895
	case RHD_OUTPUT_TMDSA:
896
	case RHD_OUTPUT_LVTMA:
897
	    if (OutputType == RHD_OUTPUT_LVTMA) {
898
		if (ConnectorType == RHD_CONNECTOR_PANEL) {
899
		    Private->OutputControlId = atomLCDOutput;
900
		    LVDSInfoRetrieve(rhdPtr, Private);
901
		    Private->RunDualLink = Private->DualLink;
902
		    Private->EncoderId = atomEncoderLVDS;
903
		} else {
904
		    TMDSInfoRetrieve(rhdPtr, Private);
905
		    Private->OutputControlId = atomLVTMAOutput;
906
		    Private->EncoderId = atomEncoderTMDS2;
907
		}
908
	    } else {
909
		TMDSInfoRetrieve(rhdPtr, Private);
910
		Private->OutputControlId = atomTMDSAOutput;
911
		Private->EncoderId = atomEncoderTMDS1;
912
	    }
913
 
914
	    if (OutputType == RHD_CONNECTOR_DVI)
915
		Private->DualLink = TRUE;
916
	    else
917
		Private->DualLink = FALSE;
918
 
919
	    if (ConnectorType != RHD_CONNECTOR_PANEL)
920
		Private->Hdmi = RHDHdmiInit(rhdPtr, Output);
921
	    else
922
		Private->Hdmi = NULL;
923
 
924
	    Private->EncoderVersion = rhdAtomEncoderControlVersion(rhdPtr->atomBIOS, Private->EncoderId);
925
	    switch (Private->EncoderVersion.cref) {
926
		case 1:
927
		    EncoderConfig->u.lvds.Is24bit = Private->LVDS24Bit;
928
		    break;
929
		case 2:
930
		case 3:
931
		    EncoderConfig->u.lvds2.Is24bit = Private->LVDS24Bit;
932
		    EncoderConfig->u.lvds2.SpatialDither = Private->SpatialDither;
933
		    EncoderConfig->u.lvds2.LinkB = 0; /* @@@ */
934
		    EncoderConfig->u.lvds2.Hdmi = FALSE;
935
#if 0
936
		    if (ConnectorType == RHD_CONNECTOR_HDMI_B
937
			|| ConnectorType == RHD_CONNECTOR_HDMI_A)
938
			EncoderConfig->u.lvds2.hdmi = TRUE;
939
#endif
940
		    switch (Private->GreyLevel) {
941
			case 2:
942
			    EncoderConfig->u.lvds2.TemporalGrey = atomTemporalDither2;
943
			    break;
944
			case 4:
945
			    EncoderConfig->u.lvds2.TemporalGrey = atomTemporalDither4;
946
			    break;
947
			case 0:
948
			default:
949
			    EncoderConfig->u.lvds2.TemporalGrey = atomTemporalDither0;
950
		    }
951
		    if (Private->SpatialDither)
952
			EncoderConfig->u.lvds2.SpatialDither = TRUE;
953
		    else
954
			EncoderConfig->u.lvds2.SpatialDither = FALSE;
955
		    EncoderConfig->u.lvds2.Coherent = Private->Coherent;
956
		    break;
957
	    }
958
	    break;
959
	case RHD_OUTPUT_DVO:
960
	    Private->EncoderId = atomEncoderDVO;
961
	    Private->EncoderVersion = rhdAtomEncoderControlVersion(rhdPtr->atomBIOS,
962
								   Private->EncoderId);
963
	    switch (Private->EncoderVersion.cref) {
964
		case 1:
965
		case 2:
966
		    /* Output->OutputDriverPrivate->Device not set yet. */
967
		    break;
968
		case 3:  /* @@@ still to be handled */
969
		    xfree(Output);
970
		    xfree(Private);
971
		    return NULL;
972
	    }
973
	    {
974
		struct atomCodeTableVersion version = rhdAtomOutputControlVersion(rhdPtr->atomBIOS, atomDVOOutput);
975
		switch (version.cref) {
976
		    case 1:
977
		    case 2:
978
			Private->OutputControlId = atomDVOOutput;
979
			break;
980
		    case 3:
981
#if 0
982
			Private->TransmitterId = atomTransmitterDVO;    /* @@@ check how to handle this one */
983
			break;
984
#else
985
			xfree(Output);
986
			xfree(Private);
987
			return NULL;
988
#endif
989
		}
990
	    }
991
	    break;
992
	case RHD_OUTPUT_KLDSKP_LVTMA:
993
	    Private->EncoderVersion = rhdAtomEncoderControlVersion(rhdPtr->atomBIOS,
994
								   Private->EncoderId);
995
	    Output->AllocFree = RHDAtomOutputAllocFree;
996
	    EncoderConfig->u.dig.Link = atomTransLinkA;
997
	    EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterLVTMA;
998
 
999
	    TransmitterConfig = &Private->TransmitterConfig;
1000
	    TransmitterConfig->Link = atomTransLinkA;
1001
	    TransmitterConfig->Encoder =  Private->TransmitterId;
1002
 
1003
	    if (ConnectorType == RHD_CONNECTOR_PANEL) {
1004
		TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomLVDS;
1005
		LVDSInfoRetrieve(rhdPtr, Private);
1006
		Private->Hdmi = NULL;
1007
	    } else {
1008
		TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomDVI;
1009
		TMDSInfoRetrieve(rhdPtr, Private);
1010
			Private->Coherent = FALSE;
1011
		Private->Hdmi = RHDHdmiInit(rhdPtr, Output);
1012
	    }
1013
	    break;
1014
 
1015
	case RHD_OUTPUT_UNIPHYA:
1016
	case RHD_OUTPUT_UNIPHYB:
1017
	case RHD_OUTPUT_UNIPHYC:
1018
	case RHD_OUTPUT_UNIPHYD:
1019
	case RHD_OUTPUT_UNIPHYE:
1020
	case RHD_OUTPUT_UNIPHYF:
1021
	    Output->AllocFree = RHDAtomOutputAllocFree;
1022
	    if (RHDIsIGP(rhdPtr->ChipSet))
1023
		EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterPCIEPHY;
1024
	    else {
1025
		switch (OutputType) {
1026
		    case RHD_OUTPUT_UNIPHYA:
1027
		    case RHD_OUTPUT_UNIPHYB:
1028
		EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterUNIPHY;
1029
			break;
1030
		    case RHD_OUTPUT_UNIPHYC:
1031
		    case RHD_OUTPUT_UNIPHYD:
1032
			EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterUNIPHY1;
1033
			break;
1034
		    case RHD_OUTPUT_UNIPHYE:
1035
		    case RHD_OUTPUT_UNIPHYF:
1036
			EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterUNIPHY2;
1037
			break;
1038
		    default:
1039
		    xfree(Private);
1040
		    xfree(Output);
1041
		    return NULL;
1042
		}
1043
	    }
1044
 
1045
	    TransmitterConfig = &Private->TransmitterConfig;
1046
	    TransmitterConfig->Encoder =  Private->EncoderId = atomEncoderNone;
1047
	    switch (OutputType) {
1048
		case RHD_OUTPUT_UNIPHYA:
1049
		case RHD_OUTPUT_UNIPHYC:
1050
		case RHD_OUTPUT_UNIPHYE:
1051
		    TransmitterConfig->Link = EncoderConfig->u.dig.Link = atomTransLinkA;
1052
		    break;
1053
		case RHD_OUTPUT_UNIPHYB:
1054
		case RHD_OUTPUT_UNIPHYD:
1055
		case RHD_OUTPUT_UNIPHYF:
1056
		    TransmitterConfig->Link = EncoderConfig->u.dig.Link = atomTransLinkB;
1057
		    break;
1058
		default:
1059
		    xfree(Private);
1060
		    xfree(Output);
1061
		    return NULL;
1062
	    }
1063
 
1064
	    if (RHDIsIGP(rhdPtr->ChipSet)) {
1065
		AtomBiosArgRec data;
1066
		data.val = 1;
1067
		if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_PCIE_LANES,
1068
				    &data) == ATOM_SUCCESS)
1069
		    TransmitterConfig->Lanes = data.pcieLanes.Chassis;
1070
		/* only do 'chassis' for now */
1071
		else {
1072
		    xfree(Private);
1073
		    xfree(Output);
1074
		    return NULL;
1075
		}
1076
	    }
1077
 
1078
	    if (ConnectorType == RHD_CONNECTOR_PANEL)
1079
		LVDSInfoRetrieve(rhdPtr, Private);
1080
	    else
1081
		TMDSInfoRetrieve(rhdPtr, Private);
1082
 
1083
	    switch (ConnectorType) {
1084
		case RHD_CONNECTOR_DVI:
1085
		case RHD_CONNECTOR_DVI_SINGLE:
1086
		    TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomDVI;
1087
		    Private->Hdmi = RHDHdmiInit(rhdPtr, Output);
1088
		    break;
1089
		case RHD_CONNECTOR_PANEL:
1090
		    TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomLVDS;
1091
		    break;
1092
#if 0
1093
		case RHD_CONNECTOR_DP:
1094
		case RHD_CONNECTOR_DP_DUAL:
1095
		    TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomDP;
1096
		    break;
1097
		case RHD_CONNECTOR_HDMI_A:
1098
		case RHD_CONNECTOR_HDMI_B:
1099
		    TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomHDMI;
1100
		    break;
1101
#endif
1102
		default:
1103
		    xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Unknown connector type\n",__func__);
1104
		    xfree(Output);
1105
		    xfree(Private);
1106
		    return NULL;
1107
	    }
1108
	    break;
1109
	default:
1110
	    xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Unknown output type\n");
1111
	    xfree(Output);
1112
	    xfree(Private);
1113
	    return NULL;
1114
    }
1115
    if (ConnectorType == RHD_CONNECTOR_PANEL) {
1116
	Output->Property = atomLVDSPropertyControl;
1117
	LVDSInfoRetrieve(rhdPtr, Private);
1118
    } else {
1119
	Output->Property = atomTMDSPropertyControl;
1120
	TMDSInfoRetrieve(rhdPtr, Private);
1121
    }
1122
 
1123
 
1124
    Output->Mode = rhdAtomOutputSet;
1125
    Output->Power = rhdAtomOutputPower;
1126
    Output->Save = rhdAtomOutputSave;
1127
    Output->Restore = rhdAtomOutputRestore;
1128
    Output->ModeValid = rhdAtomOutputModeValid;
1129
    Output->Destroy = rhdAtomOutputDestroy;
1130
    Private->CrtcSourceVersion = rhdAtomSelectCrtcSourceVersion(rhdPtr->atomBIOS);
1131
 
1132
    return Output;
1133
}
1134
 
1135
/*
1136
 * This sets up AtomBIOS based BL control if we need to use a non-standard method to control BL.
1137
 */
1138
int
1139
RhdAtomSetupBacklightControlProperty(struct rhdOutput *Output,
1140
				     Bool (**PropertyFunc)(struct rhdOutput *Output,
1141
							   enum rhdPropertyAction Action,
1142
							   enum rhdOutputProperty Property,
1143
							   union rhdPropertyData *val), void **PrivatePtr)
1144
{
1145
    RHDPtr rhdPtr = RHDPTRI(Output);
1146
    int BlLevel;
1147
    struct rhdAtomOutputPrivate *Private;
1148
    struct atomTransmitterConfig *TransmitterConfig;
1149
 
1150
    RHDFUNC(Output);
1151
 
1152
    Private = xnfcalloc(sizeof(struct rhdAtomOutputPrivate), 1);
1153
 
1154
    switch (Output->Id) {
1155
	case RHD_OUTPUT_KLDSKP_LVTMA:
1156
	case RHD_OUTPUT_UNIPHYE:
1157
	case RHD_OUTPUT_UNIPHYF:
1158
	    /* We set up a those parameters although they may never be needed for BL control */
1159
	    TransmitterConfig = &Private->TransmitterConfig;
1160
	    switch (Output->Id) {
1161
		case RHD_OUTPUT_KLDSKP_LVTMA:
1162
		    Private->TransmitterId = atomTransmitterLVTMA;
1163
		    break;
1164
		case RHD_OUTPUT_UNIPHYE:
1165
		    Private->TransmitterId = atomTransmitterUNIPHY2;
1166
		    TransmitterConfig->Link = atomTransLinkA;
1167
		    break;
1168
		case RHD_OUTPUT_UNIPHYF:
1169
		    Private->TransmitterId = atomTransmitterUNIPHY2;
1170
		    TransmitterConfig->Link = atomTransLinkB;
1171
		    break;
1172
		default:
1173
		    return 0;  /* never get here */
1174
	    }
1175
	    TransmitterConfig = &Private->TransmitterConfig;
1176
	    TransmitterConfig->Mode = atomLVDS;
1177
	    if (rhdPtr->DigEncoderOutput[0] == Output)
1178
		TransmitterConfig->Encoder =  Private->EncoderId = atomEncoderDIG1;
1179
	    else if (rhdPtr->DigEncoderOutput[1] == Output)
1180
		TransmitterConfig->Encoder =  Private->EncoderId = atomEncoderDIG2;
1181
	    else
1182
		TransmitterConfig->Encoder =  Private->EncoderId = atomEncoderNone;
1183
	    LVDSInfoRetrieve(rhdPtr, Private);
1184
	    Private->PixelClock = 0;
1185
	    Private->Hdmi = NULL;
1186
	    break;
1187
	case RHD_OUTPUT_LVTMA:
1188
	    Private->OutputControlId = atomLCDOutput;
1189
	    break;
1190
	default:
1191
	    xfree(Private);
1192
	    return 0;
1193
    }
1194
    *PropertyFunc = atomLVDSPropertyControl;
1195
    *PrivatePtr = Private;
1196
    RHDAtomBIOSScratchBlLevel(rhdPtr, rhdBIOSScratchBlGet, &BlLevel);
1197
 
1198
    return BlLevel;
1199
}
1200
 
1201
void
1202
RhdAtomDestroyBacklightControlProperty(struct rhdOutput *Output, void *PrivatePtr)
1203
{
1204
    if (PrivatePtr)
1205
	xfree(PrivatePtr);
1206
}
1207
 
1208
#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */