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
/*
27
 * Deals with the Primary TMDS device (TMDSA) of R500s, R600s.
28
 * Gets replaced by DDIA on RS690 and DIG/UNIPHY on RV620.
29
 */
30
 
31
#ifdef HAVE_CONFIG_H
32
#include "config.h"
33
#endif
34
 
35
#include "xf86.h"
36
 
37
/* for usleep */
38
#if HAVE_XF86_ANSIC_H
39
# include "xf86_ansic.h"
40
#else
41
# include 
42
#endif
43
#include "rhd.h"
44
#include "rhd_crtc.h"
45
#include "rhd_connector.h"
46
#include "rhd_output.h"
47
#include "rhd_regs.h"
48
#include "rhd_hdmi.h"
49
 
50
#ifdef ATOM_BIOS
51
#include "rhd_atombios.h"
52
#endif
53
 
54
struct rhdTMDSPrivate {
55
    Bool RunsDualLink;
56
    DisplayModePtr Mode;
57
    Bool Coherent;
58
    int PowerState;
59
 
60
    struct rhdHdmi *Hdmi;
61
 
62
    Bool Stored;
63
 
64
    CARD32 StoreControl;
65
    CARD32 StoreSource;
66
    CARD32 StoreFormat;
67
    CARD32 StoreForce;
68
    CARD32 StoreReduction;
69
    CARD32 StoreDCBalancer;
70
    CARD32 StoreDataSynchro;
71
    CARD32 StoreTXEnable;
72
    CARD32 StoreMacro;
73
    CARD32 StoreTXControl;
74
    CARD32 StoreTXAdjust;
75
};
76
 
77
/*
78
 * We cannot sense for dual link here at all, plus, we need a bit more work
79
 * for enabling the transmitter for sensing to happen on most R5xx cards.
80
 * RV570 (0x7280) and R600 and above seem ok.
81
 */
82
static enum rhdSensedOutput
83
TMDSASense(struct rhdOutput *Output, struct rhdConnector *Connector)
84
{
85
    RHDPtr rhdPtr = RHDPTRI(Output);
86
    CARD32 Enable, Control, Detect;
87
    enum rhdConnectorType Type = Connector->Type;
88
    Bool ret;
89
 
90
    RHDFUNC(Output);
91
 
92
    if ((Type != RHD_CONNECTOR_DVI) && (Type != RHD_CONNECTOR_DVI_SINGLE)) {
93
	xf86DrvMsg(Output->scrnIndex, X_WARNING,
94
		   "%s: connector type %d is not supported.\n",
95
		   __func__, Type);
96
	return RHD_SENSED_NONE;
97
    }
98
 
99
    Enable = RHDRegRead(Output, TMDSA_TRANSMITTER_ENABLE);
100
    Control = RHDRegRead(Output, TMDSA_TRANSMITTER_CONTROL);
101
    Detect = RHDRegRead(Output, TMDSA_LOAD_DETECT);
102
 
103
    if (rhdPtr->ChipSet < RHD_R600) {
104
	RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00000003, 0x00000003);
105
	RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001, 0x00000003);
106
    }
107
 
108
    RHDRegMask(Output, TMDSA_LOAD_DETECT, 0x00000001, 0x00000001);
109
    usleep(1);
110
    ret = RHDRegRead(Output, TMDSA_LOAD_DETECT) & 0x00000010;
111
 
112
    RHDRegMask(Output, TMDSA_LOAD_DETECT, Detect, 0x00000001);
113
 
114
    if (rhdPtr->ChipSet < RHD_R600) {
115
	RHDRegWrite(Output, TMDSA_TRANSMITTER_ENABLE, Enable);
116
	RHDRegWrite(Output, TMDSA_TRANSMITTER_CONTROL, Control);
117
    }
118
 
119
    RHDDebug(Output->scrnIndex, "%s: %s\n", __func__,
120
	     ret ? "Attached" : "Disconnected");
121
 
122
    if (ret)
123
	return RHD_SENSED_DVI;
124
    else
125
	return RHD_SENSED_NONE;
126
}
127
 
128
/*
129
 *
130
 */
131
static ModeStatus
132
TMDSAModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
133
{
134
    RHDFUNC(Output);
135
 
136
    if (Mode->Flags & V_INTERLACE)
137
        return MODE_NO_INTERLACE;
138
 
139
    if (Mode->Clock < 25000)
140
	return MODE_CLOCK_LOW;
141
 
142
    if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) {
143
	if (Mode->Clock > 165000)
144
	    return MODE_CLOCK_HIGH;
145
    } else if (Output->Connector->Type == RHD_CONNECTOR_DVI) {
146
	if (Mode->Clock > 330000) /* could go higher still */
147
	    return MODE_CLOCK_HIGH;
148
    }
149
 
150
    return MODE_OK;
151
}
152
 
153
/*
154
 * This information is not provided in an atombios data table.
155
 */
156
static struct R5xxTMDSAMacro {
157
    CARD16 Device;
158
    CARD32 Macro;
159
} R5xxTMDSAMacro[] = {
160
    { 0x7104, 0x00C00414 }, /* R520  */
161
    { 0x7142, 0x00A00415 }, /* RV515 */
162
    { 0x7145, 0x00A00416 }, /* M54   */
163
    { 0x7146, 0x00C0041F }, /* RV515 */
164
    { 0x7147, 0x00C00418 }, /* RV505 */
165
    { 0x7149, 0x00800416 }, /* M56   */
166
    { 0x7152, 0x00A00415 }, /* RV515 */
167
    { 0x7183, 0x00600412 }, /* RV530 */
168
    { 0x71C1, 0x00C0041F }, /* RV535 */
169
    { 0x71C2, 0x00A00416 }, /* RV530 */
170
    { 0x71C4, 0x00A00416 }, /* M56   */
171
    { 0x71C5, 0x00A00416 }, /* M56   */
172
    { 0x71C6, 0x00A00513 }, /* RV530 */
173
    { 0x71D2, 0x00A00513 }, /* RV530 */
174
    { 0x71D5, 0x00A00513 }, /* M66   */
175
    { 0x7249, 0x00A00513 }, /* R580  */
176
    { 0x724B, 0x00A00513 }, /* R580  */
177
    { 0x7280, 0x00C0041F }, /* RV570 */
178
    { 0x7288, 0x00C0041F }, /* RV570 */
179
    { 0x9400, 0x00910419 }, /* R600: */
180
    { 0, 0} /* End marker */
181
};
182
 
183
static struct Rv6xxTMDSAMacro {
184
    CARD16 Device;
185
    CARD32 PLL;
186
    CARD32 TX;
187
} Rv6xxTMDSAMacro[] = {
188
    { 0x94C1, 0x00010416, 0x00010308 }, /* RV610 */
189
    { 0x94C3, 0x00010416, 0x00010308 }, /* RV610 */
190
    { 0x9501, 0x00010416, 0x00010308 }, /* RV670: != atombios */
191
    { 0x9505, 0x00010416, 0x00010308 }, /* RV670: != atombios */
192
    { 0x950F, 0x00010416, 0x00010308 }, /* R680 : != atombios */
193
    { 0x9581, 0x00030410, 0x00301044 }, /* M76 */
194
    { 0x9587, 0x00010416, 0x00010308 }, /* RV630 */
195
    { 0x9588, 0x00010416, 0x00010388 }, /* RV630 */
196
    { 0x9589, 0x00010416, 0x00010388 }, /* RV630 */
197
    { 0, 0, 0} /* End marker */
198
};
199
 
200
static void
201
TMDSAVoltageControl(struct rhdOutput *Output)
202
{
203
    RHDPtr rhdPtr = RHDPTRI(Output);
204
    int i;
205
 
206
    if (rhdPtr->ChipSet < RHD_RV610) {
207
	for (i = 0; R5xxTMDSAMacro[i].Device; i++)
208
	    if (R5xxTMDSAMacro[i].Device == rhdPtr->PciDeviceID) {
209
		RHDRegWrite(Output, TMDSA_MACRO_CONTROL, R5xxTMDSAMacro[i].Macro);
210
		return;
211
	    }
212
 
213
	xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
214
		   __func__, rhdPtr->PciDeviceID);
215
	xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_MACRO_CONTROL: 0x%08X\n",
216
		   (unsigned int) RHDRegRead(Output, TMDSA_MACRO_CONTROL));
217
    } else {
218
	for (i = 0; Rv6xxTMDSAMacro[i].Device; i++)
219
	    if (Rv6xxTMDSAMacro[i].Device == rhdPtr->PciDeviceID) {
220
		RHDRegWrite(Output, TMDSA_PLL_ADJUST, Rv6xxTMDSAMacro[i].PLL);
221
		RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Rv6xxTMDSAMacro[i].TX);
222
		return;
223
	    }
224
	xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
225
		   __func__, rhdPtr->PciDeviceID);
226
	xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_PLL_ADJUST: 0x%08X\n",
227
		   (unsigned int) RHDRegRead(Output, TMDSA_PLL_ADJUST));
228
	xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_TRANSMITTER_ADJUST: 0x%08X\n",
229
		   (unsigned int) RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST));
230
    }
231
}
232
 
233
/*
234
 *
235
 */
236
static Bool
237
TMDSAPropertyControl(struct rhdOutput *Output,
238
	     enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val)
239
{
240
    struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
241
 
242
    RHDFUNC(Output);
243
    switch (Action) {
244
	case rhdPropertyCheck:
245
	switch (Property) {
246
	    case RHD_OUTPUT_COHERENT:
247
		return TRUE;
248
	    default:
249
		return FALSE;
250
	}
251
	case rhdPropertyGet:
252
	    switch (Property) {
253
		case RHD_OUTPUT_COHERENT:
254
		    val->Bool = Private->Coherent;
255
		    return TRUE;
256
		    break;
257
		default:
258
		    return FALSE;
259
	    }
260
	    break;
261
	case rhdPropertySet:
262
	    switch (Property) {
263
		case RHD_OUTPUT_COHERENT:
264
		    Private->Coherent = val->Bool;
265
		    Output->Mode(Output, Private->Mode);
266
		    Output->Power(Output, RHD_POWER_ON);
267
		    break;
268
		default:
269
		    return FALSE;
270
	    }
271
	    break;
272
    }
273
    return TRUE;
274
}
275
 
276
/*
277
 *
278
 */
279
static void
280
TMDSASet(struct rhdOutput *Output, DisplayModePtr Mode)
281
{
282
    RHDPtr rhdPtr = RHDPTRI(Output);
283
    struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
284
 
285
    RHDFUNC(Output);
286
 
287
    /* Clear out some HPD events first: this should be under driver control. */
288
    RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x0000000C);
289
    RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00070000);
290
    RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000010);
291
 
292
    /* Disable the transmitter */
293
    RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001D1F);
294
 
295
    /* Disable bit reduction and reset temporal dither */
296
    RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x00010101);
297
    if (rhdPtr->ChipSet < RHD_R600) {
298
	RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0x04000000, 0x04000000);
299
	usleep(2);
300
	RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x04000000);
301
    } else {
302
	RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0x02000000, 0x02000000);
303
	usleep(2);
304
	RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x02000000);
305
    }
306
 
307
    /* reset phase on vsync and use RGB */
308
    RHDRegMask(Output, TMDSA_CNTL, 0x00001000, 0x00011000);
309
 
310
    /* Select CRTC, select syncA, no stereosync */
311
    RHDRegMask(Output, TMDSA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101);
312
 
313
    /* Single link, for now */
314
    RHDRegWrite(Output, TMDSA_COLOR_FORMAT, 0);
315
 
316
    /* store this for TRANSMITTER_ENABLE in TMDSAPower */
317
    Private->Mode = Mode;
318
    if (Mode->SynthClock > 165000) {
319
	RHDRegMask(Output, TMDSA_CNTL, 0x01000000, 0x01000000);
320
	Private->RunsDualLink = TRUE; /* for TRANSMITTER_ENABLE in TMDSAPower */
321
    } else {
322
	RHDRegMask(Output, TMDSA_CNTL, 0, 0x01000000);
323
	Private->RunsDualLink = FALSE;
324
    }
325
 
326
    /* Disable force data */
327
    RHDRegMask(Output, TMDSA_FORCE_OUTPUT_CNTL, 0, 0x00000001);
328
 
329
    /* DC balancer enable */
330
    RHDRegMask(Output, TMDSA_DCBALANCER_CONTROL, 0x00000001, 0x00000001);
331
 
332
    TMDSAVoltageControl(Output);
333
 
334
    /* use IDCLK */
335
    RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010);
336
 
337
    if (Private->Coherent)
338
	RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000000, 0x10000000);
339
    else
340
	RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
341
 
342
    RHDHdmiSetMode(Private->Hdmi, Mode);
343
}
344
 
345
/*
346
 *
347
 */
348
static void
349
TMDSAPower(struct rhdOutput *Output, int Power)
350
{
351
    RHDPtr rhdPtr = RHDPTRI(Output);
352
    struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
353
 
354
    RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
355
	     rhdPowerString[Power]);
356
 
357
    switch (Power) {
358
    case RHD_POWER_ON:
359
	if (Private->PowerState == RHD_POWER_SHUTDOWN
360
	    || Private->PowerState == RHD_POWER_UNKNOWN) {
361
	    RHDRegMask(Output, TMDSA_CNTL, 0x1, 0x00000001);
362
 
363
	RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001);
364
	usleep(20);
365
 
366
	/* reset transmitter PLL */
367
	RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
368
	usleep(2);
369
	RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x00000002);
370
 
371
	usleep(30);
372
 
373
	/* restart data synchronisation */
374
  if (rhdPtr->ChipSet < RHD_R600) {
375
	    RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0x00000001, 0x00000001);
376
	    usleep(2);
377
	    RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0x00000100, 0x00000100);
378
	    RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0, 0x00000001);
379
	} else {
380
	    RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0x00000001, 0x00000001);
381
	    usleep(2);
382
	    RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0x00000100, 0x00000100);
383
	    RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0, 0x00000001);
384
	}
385
	}
386
 
387
	if (Private->RunsDualLink) {
388
	    /* bit 9 is not known by anything below RV610, but is ignored by
389
	       the hardware anyway */
390
	    RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00001F1F, 0x00001F1F);
391
	} else
392
	    RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x0000001F, 0x00001F1F);
393
 
394
	if(Output->Connector != NULL && RHDConnectorEnableHDMI(Output->Connector))
395
	    RHDHdmiEnable(Private->Hdmi, TRUE);
396
	else
397
	    RHDHdmiEnable(Private->Hdmi, FALSE);
398
	Private->PowerState = RHD_POWER_ON;
399
	return;
400
 
401
    case RHD_POWER_RESET:
402
	RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001F1F);
403
	/* if we do a RESET after a SHUTDOWN don't raise the power level,
404
	 * and similarly, don't raise from UNKNOWN state. */
405
	if (Private->PowerState == RHD_POWER_ON)
406
	    Private->PowerState = RHD_POWER_RESET;
407
	return;
408
 
409
    case RHD_POWER_SHUTDOWN:
410
    default:
411
	RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
412
	usleep(2);
413
	RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x00000001);
414
	RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001F1F);
415
	RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000001);
416
	RHDHdmiEnable(Private->Hdmi, FALSE);
417
	Private->PowerState = RHD_POWER_SHUTDOWN;
418
	return;
419
    }
420
}
421
 
422
/*
423
 *
424
 */
425
static void
426
TMDSASave(struct rhdOutput *Output)
427
{
428
    int ChipSet = RHDPTRI(Output)->ChipSet;
429
    struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
430
 
431
    RHDFUNC(Output);
432
 
433
    Private->StoreControl = RHDRegRead(Output, TMDSA_CNTL);
434
    Private->StoreSource = RHDRegRead(Output, TMDSA_SOURCE_SELECT);
435
    Private->StoreFormat = RHDRegRead(Output, TMDSA_COLOR_FORMAT);
436
    Private->StoreForce = RHDRegRead(Output, TMDSA_FORCE_OUTPUT_CNTL);
437
    Private->StoreReduction = RHDRegRead(Output, TMDSA_BIT_DEPTH_CONTROL);
438
    Private->StoreDCBalancer = RHDRegRead(Output, TMDSA_DCBALANCER_CONTROL);
439
 
440
    if (ChipSet < RHD_R600)
441
	Private->StoreDataSynchro = RHDRegRead(Output, TMDSA_DATA_SYNCHRONIZATION_R500);
442
    else
443
	Private->StoreDataSynchro = RHDRegRead(Output, TMDSA_DATA_SYNCHRONIZATION_R600);
444
 
445
    Private->StoreTXEnable = RHDRegRead(Output, TMDSA_TRANSMITTER_ENABLE);
446
    Private->StoreMacro = RHDRegRead(Output, TMDSA_MACRO_CONTROL);
447
    Private->StoreTXControl = RHDRegRead(Output, TMDSA_TRANSMITTER_CONTROL);
448
 
449
    if (ChipSet >= RHD_RV610)
450
	Private->StoreTXAdjust = RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST);
451
 
452
    RHDHdmiSave(Private->Hdmi);
453
 
454
    Private->Stored = TRUE;
455
}
456
 
457
/*
458
 *
459
 */
460
static void
461
TMDSARestore(struct rhdOutput *Output)
462
{
463
    int ChipSet = RHDPTRI(Output)->ChipSet;
464
    struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
465
 
466
    RHDFUNC(Output);
467
 
468
    if (!Private->Stored) {
469
	xf86DrvMsg(Output->scrnIndex, X_ERROR,
470
		   "%s: No registers stored.\n", __func__);
471
	return;
472
    }
473
 
474
    RHDRegWrite(Output, TMDSA_CNTL, Private->StoreControl);
475
    RHDRegWrite(Output, TMDSA_SOURCE_SELECT, Private->StoreSource);
476
    RHDRegWrite(Output, TMDSA_COLOR_FORMAT, Private->StoreFormat);
477
    RHDRegWrite(Output, TMDSA_FORCE_OUTPUT_CNTL, Private->StoreForce);
478
    RHDRegWrite(Output, TMDSA_BIT_DEPTH_CONTROL, Private->StoreReduction);
479
    RHDRegWrite(Output, TMDSA_DCBALANCER_CONTROL, Private->StoreDCBalancer);
480
 
481
    if (ChipSet < RHD_R600)
482
	RHDRegWrite(Output, TMDSA_DATA_SYNCHRONIZATION_R500, Private->StoreDataSynchro);
483
    else
484
	RHDRegWrite(Output, TMDSA_DATA_SYNCHRONIZATION_R600, Private->StoreDataSynchro);
485
 
486
    RHDRegWrite(Output, TMDSA_TRANSMITTER_ENABLE, Private->StoreTXEnable);
487
    RHDRegWrite(Output, TMDSA_MACRO_CONTROL, Private->StoreMacro);
488
    RHDRegWrite(Output, TMDSA_TRANSMITTER_CONTROL, Private->StoreTXControl);
489
 
490
    if (ChipSet >= RHD_RV610)
491
	RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Private->StoreTXAdjust);
492
 
493
    RHDHdmiRestore(Private->Hdmi);
494
}
495
 
496
/*
497
 *
498
 */
499
static void
500
TMDSADestroy(struct rhdOutput *Output)
501
{
502
    struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
503
    RHDFUNC(Output);
504
 
505
    if (!Private)
506
	return;
507
 
508
    RHDHdmiDestroy(Private->Hdmi);
509
 
510
    xfree(Private);
511
    Output->Private = NULL;
512
}
513
 
514
/*
515
 *
516
 */
517
struct rhdOutput *
518
RHDTMDSAInit(RHDPtr rhdPtr)
519
{
520
    struct rhdOutput *Output;
521
    struct rhdTMDSPrivate *Private;
522
 
523
    RHDFUNC(rhdPtr);
524
 
525
    Output = xnfcalloc(sizeof(struct rhdOutput), 1);
526
 
527
    Output->scrnIndex = rhdPtr->scrnIndex;
528
    Output->Name = "TMDS A";
529
    Output->Id = RHD_OUTPUT_TMDSA;
530
 
531
    Output->Sense = TMDSASense;
532
    Output->ModeValid = TMDSAModeValid;
533
    Output->Mode = TMDSASet;
534
    Output->Power = TMDSAPower;
535
    Output->Save = TMDSASave;
536
    Output->Restore = TMDSARestore;
537
    Output->Destroy = TMDSADestroy;
538
    Output->Property = TMDSAPropertyControl;
539
 
540
    Private = xnfcalloc(sizeof(struct rhdTMDSPrivate), 1);
541
    Private->RunsDualLink = FALSE;
542
    Private->Coherent = FALSE;
543
    Private->PowerState = RHD_POWER_UNKNOWN;
544
 
545
    Output->Private = Private;
546
 
547
    return Output;
548
}