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 Shared LVDS/TMDS encoder.
28
 *
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
 
44
#include "rhd.h"
45
#include "rhd_crtc.h"
46
#include "rhd_connector.h"
47
#include "rhd_output.h"
48
#include "rhd_regs.h"
49
#include "rhd_hdmi.h"
50
#ifdef ATOM_BIOS
51
#include "rhd_atombios.h"
52
#include "rhd_atomout.h"
53
#endif
54
 
55
/*
56
 * First of all, make it more managable to code for both R500 and R600, as
57
 * there was a 1 register shift, right in the middle of the register block.
58
 * There are of course much nicer ways to do the workaround i am doing here,
59
 * but speed is not an issue here.
60
 */
61
static inline CARD16
62
LVTMAChipGenerationSelect(int ChipSet, CARD32 R500, CARD32 R600)
63
{
64
    if (ChipSet >= RHD_RS600)
65
	return R600;
66
    else
67
	return R500;
68
}
69
 
70
#define LVTMAGENSEL(r500, r600) LVTMAChipGenerationSelect(rhdPtr->ChipSet, (r500), (r600))
71
#define LVTMA_DATA_SYNCHRONIZATION \
72
    LVTMAGENSEL(LVTMA_R500_DATA_SYNCHRONIZATION, LVTMA_R600_DATA_SYNCHRONIZATION)
73
#define LVTMA_PWRSEQ_REF_DIV \
74
    LVTMAGENSEL(LVTMA_R500_PWRSEQ_REF_DIV, LVTMA_R600_PWRSEQ_REF_DIV)
75
#define LVTMA_PWRSEQ_DELAY1 \
76
    LVTMAGENSEL(LVTMA_R500_PWRSEQ_DELAY1, LVTMA_R600_PWRSEQ_DELAY1)
77
#define LVTMA_PWRSEQ_DELAY2 \
78
    LVTMAGENSEL(LVTMA_R500_PWRSEQ_DELAY2, LVTMA_R600_PWRSEQ_DELAY2)
79
#define LVTMA_PWRSEQ_CNTL \
80
    LVTMAGENSEL(LVTMA_R500_PWRSEQ_CNTL, LVTMA_R600_PWRSEQ_CNTL)
81
#define LVTMA_PWRSEQ_STATE \
82
    LVTMAGENSEL(LVTMA_R500_PWRSEQ_STATE, LVTMA_R600_PWRSEQ_STATE)
83
#define LVTMA_LVDS_DATA_CNTL \
84
    LVTMAGENSEL(LVTMA_R500_LVDS_DATA_CNTL, LVTMA_R600_LVDS_DATA_CNTL)
85
#define LVTMA_MODE LVTMAGENSEL(LVTMA_R500_MODE, LVTMA_R600_MODE)
86
#define LVTMA_TRANSMITTER_ENABLE \
87
    LVTMAGENSEL(LVTMA_R500_TRANSMITTER_ENABLE, LVTMA_R600_TRANSMITTER_ENABLE)
88
#define LVTMA_MACRO_CONTROL \
89
    LVTMAGENSEL(LVTMA_R500_MACRO_CONTROL, LVTMA_R600_MACRO_CONTROL)
90
#define LVTMA_TRANSMITTER_CONTROL \
91
    LVTMAGENSEL(LVTMA_R500_TRANSMITTER_CONTROL, LVTMA_R600_TRANSMITTER_CONTROL)
92
#define LVTMA_REG_TEST_OUTPUT \
93
    LVTMAGENSEL(LVTMA_R500_REG_TEST_OUTPUT, LVTMA_R600_REG_TEST_OUTPUT)
94
#define LVTMA_BL_MOD_CNTL \
95
    LVTMAGENSEL(LVTMA_R500_BL_MOD_CNTL, LVTMA_R600_BL_MOD_CNTL)
96
 
97
#define LVTMA_DITHER_RESET_BIT LVTMAGENSEL(0x04000000, 0x02000000)
98
 
99
/*
100
 *
101
 * Handling for LVTMA block as LVDS.
102
 *
103
 */
104
 
105
struct LVDSPrivate {
106
    Bool DualLink;
107
    Bool LVDS24Bit;
108
    Bool FPDI; /* LDI otherwise */
109
    CARD16 TXClockPattern;
110
    int BlLevel;
111
    CARD32 MacroControl;
112
 
113
    /* Power timing for LVDS */
114
    CARD16 PowerRefDiv;
115
    CARD16 BlonRefDiv;
116
    CARD16 PowerDigToDE;
117
    CARD16 PowerDEToBL;
118
    CARD16 OffDelay;
119
    Bool   TemporalDither;
120
    Bool   SpatialDither;
121
    int    GreyLevel;
122
 
123
    Bool Stored;
124
 
125
    CARD32 StoreControl;
126
    CARD32 StoreSourceSelect;
127
    CARD32 StoreBitDepthControl;
128
    CARD32 StoreDataSynchronisation;
129
    CARD32 StorePWRSEQRefDiv;
130
    CARD32 StorePWRSEQDelay1;
131
    CARD32 StorePWRSEQDelay2;
132
    CARD32 StorePWRSEQControl;
133
    CARD32 StorePWRSEQState;
134
    CARD32 StoreLVDSDataControl;
135
    CARD32 StoreMode;
136
    CARD32 StoreTxEnable;
137
    CARD32 StoreMacroControl;
138
    CARD32 StoreTXControl;
139
    CARD32 StoreBlModCntl;
140
#ifdef NOT_YET
141
    /* to hook in AtomBIOS property callback */
142
    Bool (*WrappedPropertyCallback) (struct rhdOutput *Output,
143
		      enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val);
144
    void *PropertyPrivate;
145
#endif
146
};
147
 
148
/*
149
 *
150
 */
151
static ModeStatus
152
LVDSModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
153
{
154
    RHDFUNC(Output);
155
 
156
    if (Mode->Flags & V_INTERLACE)
157
        return MODE_NO_INTERLACE;
158
 
159
    return MODE_OK;
160
}
161
 
162
/*
163
 *
164
 */
165
static void
166
LVDSDebugBacklight(struct rhdOutput *Output)
167
{
168
    RHDPtr rhdPtr = RHDPTRI(Output);
169
    CARD32 tmp;
170
    Bool Blon, BlonOvrd, BlonPol, BlModEn;
171
    int BlModLevel, BlModRes = 0;
172
 
173
    if (rhdPtr->verbosity < 7)
174
	return;
175
 
176
    tmp = (RHDRegRead(Output, LVTMA_PWRSEQ_STATE) >> 3) & 0x01;
177
    RHDDebug(rhdPtr->scrnIndex, "%s: PWRSEQ BLON State: %s\n",
178
	    __func__, tmp ? "on" : "off");
179
    tmp = RHDRegRead(rhdPtr, LVTMA_PWRSEQ_CNTL);
180
    Blon = (tmp >> 24) & 0x1;
181
    BlonOvrd = (tmp >> 25) & 0x1;
182
    BlonPol = (tmp >> 26) & 0x1;
183
 
184
    RHDDebug(rhdPtr->scrnIndex, "%s: BLON: %s BLON_OVRD: %s BLON_POL: %s\n",
185
	    __func__, Blon ? "on" : "off",
186
	    BlonOvrd ? "enabled" : "disabled",
187
	    BlonPol ? "invert" : "non-invert");
188
 
189
    tmp = RHDRegRead(rhdPtr, LVTMA_BL_MOD_CNTL);
190
    BlModEn = tmp & 0x1;
191
    BlModLevel = (tmp >> 8) & 0xFF;
192
    if (rhdPtr->ChipSet >= RHD_RS600)
193
	BlModRes = (tmp >> 16) & 0xFF;
194
 
195
    xf86DrvMsgVerb(rhdPtr->scrnIndex, X_INFO, 3,
196
		   "%s: BL_MOD: %s BL_MOD_LEVEL: %d BL_MOD_RES: %d\n",
197
		   __func__, BlModEn ? "enable" : "disable",
198
	    BlModLevel, BlModRes);
199
}
200
 
201
/*
202
 *
203
 */
204
static void
205
LVDSSetBacklight(struct rhdOutput *Output, int level)
206
{
207
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
208
    RHDPtr rhdPtr = RHDPTRI(Output);
209
 
210
    Private->BlLevel = level;
211
 
212
    xf86DrvMsg(rhdPtr->scrnIndex, X_INFO,
213
	       "%s: trying to set BL_MOD_LEVEL to: %d\n",
214
	       __func__, level);
215
 
216
    if (rhdPtr->ChipSet >= RHD_RS600)
217
  _RHDRegMask(rhdPtr, LVTMA_BL_MOD_CNTL,
218
		   0xFF << 16 | (level << 8) | 0x1,
219
		   0xFFFF01);
220
    else
221
  _RHDRegMask(rhdPtr, LVTMA_BL_MOD_CNTL,
222
		   (level << 8) | 0x1,
223
		   0xFF01);
224
 
225
    /*
226
     * Poor man's debug
227
     */
228
    LVDSDebugBacklight(Output);
229
}
230
 
231
/*
232
 *
233
 */
234
static Bool
235
LVDSPropertyControl(struct rhdOutput *Output, enum rhdPropertyAction Action,
236
		    enum rhdOutputProperty Property, union rhdPropertyData *val)
237
{
238
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
239
 
240
    switch (Action) {
241
	case rhdPropertyCheck:
242
	    switch (Property) {
243
		if (Private->BlLevel < 0)
244
		    return FALSE;
245
		case RHD_OUTPUT_BACKLIGHT:
246
		    return TRUE;
247
		default:
248
		    return FALSE;
249
	    }
250
	case rhdPropertyGet:
251
	    switch (Property) {
252
		case RHD_OUTPUT_BACKLIGHT:
253
		    if (Private->BlLevel < 0)
254
			return FALSE;
255
		    val->integer = Private->BlLevel;
256
		    break;
257
		default:
258
		    return FALSE;
259
	    }
260
	    break;
261
	case rhdPropertySet:
262
	    switch (Property) {
263
		case RHD_OUTPUT_BACKLIGHT:
264
		    if (Private->BlLevel < 0)
265
			return FALSE;
266
		    LVDSSetBacklight(Output, val->integer);
267
		    break;
268
		default:
269
		    return FALSE;
270
	    }
271
	    break;
272
    }
273
    return TRUE;
274
}
275
 
276
/*
277
 *
278
 */
279
static void
280
LVDSSet(struct rhdOutput *Output, DisplayModePtr Mode)
281
{
282
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
283
    RHDPtr rhdPtr = RHDPTRI(Output);
284
 
285
    RHDFUNC(Output);
286
 
287
    RHDRegMask(Output, LVTMA_CNTL, 0x00000001, 0x00000001); /* enable */
288
    usleep(20);
289
 
290
    RHDRegWrite(Output, LVTMA_MODE, 0); /* set to LVDS */
291
 
292
    /* Select CRTC, select syncA, no stereosync */
293
    RHDRegMask(Output, LVTMA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101);
294
 
295
    if (Private->LVDS24Bit) { /* 24bits */
296
	RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0x00000001, 0x00000001); /* enable 24bits */
297
	RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0x00101010, 0x00101010); /* dithering bit depth = 24 */
298
 
299
	if (Private->FPDI) /* FPDI? */
300
	    RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0x00000010, 0x00000010); /* 24 bit format: FPDI or LDI? */
301
	else
302
	    RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0, 0x00000010);
303
    } else {
304
	RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0, 0x00000001); /* disable 24bits */
305
	RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0x00101010); /* dithering bit depth != 24 */
306
    }
307
 
308
    /* enable temporal dithering, disable spatial dithering and disable truncation */
309
    RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL,
310
	       Private->TemporalDither ? 1 << 16 : 0
311
	       | Private->SpatialDither ? 1 << 8 : 0
312
	       | (Private->GreyLevel > 2) ? 1 << 24 : 0,
313
	       0x01010101);
314
 
315
    /* reset the temporal dithering */
316
    RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, LVTMA_DITHER_RESET_BIT, LVTMA_DITHER_RESET_BIT);
317
    RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, LVTMA_DITHER_RESET_BIT);
318
 
319
    /* go for RGB 4:4:4 RGB/YCbCr  */
320
    RHDRegMask(Output, LVTMA_CNTL, 0, 0x00010000);
321
 
322
    if (Private->DualLink)
323
	RHDRegMask(Output, LVTMA_CNTL, 0x01000000, 0x01000000);
324
    else
325
	RHDRegMask(Output, LVTMA_CNTL, 0, 0x01000000);
326
 
327
    /* PLL and TX voltages */
328
    RHDRegWrite(Output, LVTMA_MACRO_CONTROL, Private->MacroControl);
329
 
330
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010); /* use pclk_lvtma_direct */
331
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0xCC000000);
332
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, Private->TXClockPattern << 16, 0x03FF0000);
333
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001); /* enable PLL */
334
    usleep(20);
335
 
336
    /* reset transmitter */
337
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
338
    usleep(2);
339
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002);
340
    usleep(20);
341
 
342
    /* start data synchronisation */
343
    RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000001, 0x00000001);
344
    RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000100, 0x00000100); /* reset */
345
    usleep(2);
346
    RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0, 0x00000100);
347
}
348
 
349
/*
350
 *
351
 */
352
static void
353
LVDSPWRSEQInit(struct rhdOutput *Output)
354
{
355
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
356
    RHDPtr rhdPtr = RHDPTRI(Output);
357
 
358
    CARD32 tmp = 0;
359
 
360
    tmp = Private->PowerDigToDE >> 2;
361
    RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp, 0x000000FF);
362
    RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp << 24, 0xFF000000);
363
 
364
    tmp = Private->PowerDEToBL >> 2;
365
    RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp << 8, 0x0000FF00);
366
    RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp << 16, 0x00FF0000);
367
 
368
    RHDRegWrite(Output, LVTMA_PWRSEQ_DELAY2, Private->OffDelay >> 2);
369
    RHDRegWrite(Output, LVTMA_PWRSEQ_REF_DIV,
370
		Private->PowerRefDiv | (Private->BlonRefDiv << 16));
371
 
372
    /* Enable power sequencer and allow it to override everything */
373
    RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0x0000000D, 0x0000000D);
374
 
375
    /* give full control to the sequencer */
376
    RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0, 0x02020200);
377
}
378
 
379
/*
380
 *
381
 */
382
static void
383
LVDSEnable(struct rhdOutput *Output)
384
{
385
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
386
    RHDPtr rhdPtr = RHDPTRI(Output);
387
    CARD32 tmp = 0;
388
    int i;
389
 
390
    RHDFUNC(Output);
391
 
392
    LVDSPWRSEQInit(Output);
393
 
394
    /* set up the transmitter */
395
    RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x0000001E, 0x0000001E);
396
    if (Private->LVDS24Bit) /* 24bit ? */
397
	RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00000020, 0x00000020);
398
 
399
    if (Private->DualLink) {
400
	RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00001E00, 0x00001E00);
401
 
402
	if (Private->LVDS24Bit)
403
	    RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00002000, 0x00002000);
404
    }
405
 
406
    RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0x00000010, 0x00000010);
407
 
408
    for (i = 0; i <= Private->OffDelay; i++) {
409
	usleep(1000);
410
 
411
	tmp = (RHDRegRead(Output, LVTMA_PWRSEQ_STATE) >> 8) & 0x0F;
412
	if (tmp == 4)
413
	    break;
414
    }
415
 
416
    if (i == Private->OffDelay) {
417
	xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: failed to reach "
418
             "POWERUP_DONE state after %d loops (%d)\n",
419
             __func__, i, (int) tmp);
420
  }
421
    if (Private->BlLevel >= 0) {
422
	union rhdPropertyData data;
423
	data.integer = Private->BlLevel;
424
	Output->Property(Output, rhdPropertySet, RHD_OUTPUT_BACKLIGHT,
425
			 &data);
426
    }
427
}
428
 
429
/*
430
 *
431
 */
432
static void
433
LVDSDisable(struct rhdOutput *Output)
434
{
435
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
436
    RHDPtr rhdPtr = RHDPTRI(Output);
437
    CARD32 tmp = 0;
438
    int i;
439
 
440
    RHDFUNC(Output);
441
 
442
    if (!(RHDRegRead(Output, LVTMA_PWRSEQ_CNTL) & 0x00000010))
443
	return;
444
 
445
    LVDSPWRSEQInit(Output);
446
 
447
    RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0, 0x00000010);
448
 
449
    for (i = 0; i <= Private->OffDelay; i++) {
450
	usleep(1000);
451
 
452
	tmp = (RHDRegRead(Output, LVTMA_PWRSEQ_STATE) >> 8) & 0x0F;
453
	if (tmp == 9)
454
	    break;
455
    }
456
 
457
    if (i == Private->OffDelay) {
458
	xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: failed to reach "
459
		   "POWERDOWN_DONE state after %d loops (%d)\n",
460
		   __func__, i, (int) tmp);
461
    }
462
 
463
    RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x0000FFFF);
464
}
465
 
466
#if 0
467
/*
468
 *
469
 */
470
static void
471
LVDSShutdown(struct rhdOutput *Output)
472
{
473
    RHDPtr rhdPtr = RHDPTRI(Output);
474
    RHDFUNC(Output);
475
 
476
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002); /* PLL in reset */
477
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000001); /* disable LVDS */
478
    RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0, 0x00000001);
479
    RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, LVTMA_DITHER_RESET_BIT, LVTMA_DITHER_RESET_BIT); /* reset temp dithering */
480
    RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0x00111111); /* disable all dithering */
481
    RHDRegWrite(Output, LVTMA_CNTL, 0); /* disable */
482
}
483
#endif
484
 
485
/*
486
 *
487
 */
488
static void
489
LVDSPower(struct rhdOutput *Output, int Power)
490
{
491
    RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
492
	     rhdPowerString[Power]);
493
 
494
    switch (Power) {
495
    case RHD_POWER_ON:
496
	LVDSEnable(Output);
497
	break;
498
    case RHD_POWER_RESET:
499
	/*	LVDSDisable(Output);
500
		break;*/
501
    case RHD_POWER_SHUTDOWN:
502
    default:
503
	LVDSDisable(Output);
504
	/* LVDSShutdown(Output); */
505
	break;
506
    }
507
    return;
508
}
509
 
510
/*
511
 *
512
 */
513
static void
514
LVDSSave(struct rhdOutput *Output)
515
{
516
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
517
    RHDPtr rhdPtr = RHDPTRI(Output);
518
 
519
    RHDFUNC(Output);
520
 
521
    Private->StoreControl = RHDRegRead(Output, LVTMA_CNTL);
522
    Private->StoreSourceSelect = RHDRegRead(Output,  LVTMA_SOURCE_SELECT);
523
    Private->StoreBitDepthControl = RHDRegRead(Output, LVTMA_BIT_DEPTH_CONTROL);
524
    Private->StoreDataSynchronisation = RHDRegRead(Output, LVTMA_DATA_SYNCHRONIZATION);
525
    Private->StorePWRSEQRefDiv = RHDRegRead(Output, LVTMA_PWRSEQ_REF_DIV);
526
    Private->StorePWRSEQDelay1 = RHDRegRead(Output, LVTMA_PWRSEQ_DELAY1);
527
    Private->StorePWRSEQDelay2 = RHDRegRead(Output, LVTMA_PWRSEQ_DELAY2);
528
    Private->StorePWRSEQControl = RHDRegRead(Output, LVTMA_PWRSEQ_CNTL);
529
    Private->StorePWRSEQState = RHDRegRead(Output, LVTMA_PWRSEQ_STATE);
530
    Private->StoreLVDSDataControl = RHDRegRead(Output, LVTMA_LVDS_DATA_CNTL);
531
    Private->StoreMode = RHDRegRead(Output, LVTMA_MODE);
532
    Private->StoreTxEnable = RHDRegRead(Output, LVTMA_TRANSMITTER_ENABLE);
533
    Private->StoreMacroControl = RHDRegRead(Output, LVTMA_MACRO_CONTROL);
534
    Private->StoreTXControl = RHDRegRead(Output, LVTMA_TRANSMITTER_CONTROL);
535
    Private->StoreBlModCntl = RHDRegRead(Output, LVTMA_BL_MOD_CNTL);
536
 
537
    Private->Stored = TRUE;
538
}
539
 
540
/*
541
 * This needs to reset things like the temporal dithering and the TX appropriately.
542
 * Currently it's a dumb register dump.
543
 */
544
static void
545
LVDSRestore(struct rhdOutput *Output)
546
{
547
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
548
    RHDPtr rhdPtr = RHDPTRI(Output);
549
 
550
    RHDFUNC(Output);
551
 
552
    if (!Private->Stored) {
553
	xf86DrvMsg(Output->scrnIndex, X_ERROR,
554
		   "%s: No registers stored.\n", __func__);
555
	return;
556
    }
557
 
558
    RHDRegWrite(Output, LVTMA_CNTL, Private->StoreControl);
559
    RHDRegWrite(Output, LVTMA_SOURCE_SELECT, Private->StoreSourceSelect);
560
    RHDRegWrite(Output, LVTMA_BIT_DEPTH_CONTROL,  Private->StoreBitDepthControl);
561
    RHDRegWrite(Output, LVTMA_DATA_SYNCHRONIZATION, Private->StoreDataSynchronisation);
562
    RHDRegWrite(Output, LVTMA_PWRSEQ_REF_DIV, Private->StorePWRSEQRefDiv);
563
    RHDRegWrite(Output, LVTMA_PWRSEQ_DELAY1, Private->StorePWRSEQDelay1);
564
    RHDRegWrite(Output, LVTMA_PWRSEQ_DELAY2,  Private->StorePWRSEQDelay2);
565
    RHDRegWrite(Output, LVTMA_PWRSEQ_CNTL, Private->StorePWRSEQControl);
566
    RHDRegWrite(Output, LVTMA_PWRSEQ_STATE, Private->StorePWRSEQState);
567
    RHDRegWrite(Output, LVTMA_LVDS_DATA_CNTL, Private->StoreLVDSDataControl);
568
    RHDRegWrite(Output, LVTMA_MODE, Private->StoreMode);
569
    RHDRegWrite(Output, LVTMA_TRANSMITTER_ENABLE, Private->StoreTxEnable);
570
    RHDRegWrite(Output, LVTMA_MACRO_CONTROL, Private->StoreMacroControl);
571
    RHDRegWrite(Output, LVTMA_TRANSMITTER_CONTROL,  Private->StoreTXControl);
572
    RHDRegWrite(Output, LVTMA_BL_MOD_CNTL, Private->StoreBlModCntl);
573
 
574
    /*
575
     * Poor man's debug
576
     */
577
    LVDSDebugBacklight(Output);
578
}
579
 
580
/*
581
 * Here we pretty much assume that ATOM has either initialised the panel already
582
 * or that we can find information from ATOM BIOS data tables. We know that the
583
 * latter assumption is false for some values, but there is no getting around
584
 * ATI clinging desperately to a broken concept.
585
 */
586
static struct LVDSPrivate *
587
LVDSInfoRetrieve(RHDPtr rhdPtr)
588
{
589
    struct LVDSPrivate *Private = xnfcalloc(sizeof(struct LVDSPrivate), 1);
590
    CARD32 tmp;
591
 
592
    /* These values are not available from atombios data tables at all. */
593
    Private->MacroControl = RHDRegRead(rhdPtr, LVTMA_MACRO_CONTROL);
594
    Private->TXClockPattern =
595
  (_RHDRegRead(rhdPtr, LVTMA_TRANSMITTER_CONTROL) >> 16) & 0x3FF;
596
 
597
    /* For these values, we try to retrieve them from register space first,
598
       and later override with atombios data table information */
599
    Private->PowerDigToDE =
600
  (_RHDRegRead(rhdPtr, LVTMA_PWRSEQ_DELAY1) & 0x000000FF) << 2;
601
 
602
    Private->PowerDEToBL =
603
  (_RHDRegRead(rhdPtr, LVTMA_PWRSEQ_DELAY1) & 0x0000FF00) >> 6;
604
 
605
    Private->OffDelay = (_RHDRegRead(rhdPtr, LVTMA_PWRSEQ_DELAY2) & 0xFF) << 2;
606
 
607
    tmp = _RHDRegRead(rhdPtr, LVTMA_PWRSEQ_REF_DIV);
608
    Private->PowerRefDiv = tmp & 0x0FFF;
609
    Private->BlonRefDiv = (tmp >> 16) & 0x0FFF;
610
    tmp = _RHDRegRead(rhdPtr, LVTMA_BL_MOD_CNTL);
611
    if (tmp & 0x1)
612
	Private->BlLevel = (tmp >> 8) & 0xff;
613
    else
614
	Private->BlLevel = -1; /* Backlight control seems to be done some other way */
615
 
616
    Private->DualLink = (_RHDRegRead(rhdPtr, LVTMA_CNTL) >> 24) & 0x00000001;
617
    Private->LVDS24Bit = _RHDRegRead(rhdPtr, LVTMA_LVDS_DATA_CNTL) & 0x00000001;
618
    Private->FPDI = _RHDRegRead(rhdPtr, LVTMA_LVDS_DATA_CNTL) & 0x00000010;
619
 
620
    tmp = _RHDRegRead(rhdPtr, LVTMA_BIT_DEPTH_CONTROL);
621
    Private->TemporalDither =  ((tmp & (1 << 16)) != 0);
622
    Private->SpatialDither = ((tmp & (1 << 8)) != 0);
623
    Private->GreyLevel = (tmp & (1 << 24)) ? 4 : 2;
624
 
625
#ifdef ATOM_BIOS
626
    {
627
	AtomBiosArgRec data;
628
 
629
  if(RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
630
			   ATOM_LVDS_SEQ_DIG_ONTO_DE, &data) == ATOM_SUCCESS)
631
	    Private->PowerDigToDE = data.val;
632
 
633
  if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
634
			    ATOM_LVDS_SEQ_DE_TO_BL, &data) == ATOM_SUCCESS)
635
	    Private->PowerDEToBL = data.val;
636
 
637
  if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
638
			    ATOM_LVDS_OFF_DELAY, &data) == ATOM_SUCCESS)
639
	    Private->OffDelay = data.val;
640
 
641
  if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
642
			    ATOM_LVDS_DUALLINK, &data) == ATOM_SUCCESS)
643
	    Private->DualLink = data.val;
644
 
645
  if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
646
			    ATOM_LVDS_24BIT, &data) == ATOM_SUCCESS)
647
	    Private->LVDS24Bit = data.val;
648
 
649
  if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
650
				 ATOM_LVDS_FPDI, &data) == ATOM_SUCCESS)
651
	    Private->FPDI = data.val;
652
 
653
  if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
654
			    ATOM_LVDS_TEMPORAL_DITHER, &data) == ATOM_SUCCESS)
655
	    Private->TemporalDither = data.val;
656
 
657
  if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
658
			    ATOM_LVDS_SPATIAL_DITHER, &data) == ATOM_SUCCESS)
659
	    Private->SpatialDither = data.val;
660
 
661
  if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
662
			    ATOM_LVDS_GREYLVL, &data) == ATOM_SUCCESS) {
663
	    Private->GreyLevel = data.val;
664
	    xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "AtomBIOS returned %i Grey Levels\n",
665
		       Private->GreyLevel);
666
    }
667
    }
668
#endif
669
 
670
    if (Private->LVDS24Bit)
671
	xf86DrvMsg(rhdPtr->scrnIndex, X_PROBED,
672
		   "Detected a 24bit %s, %s link panel.\n",
673
            Private->DualLink ? "dual" : "single",
674
            Private->FPDI ? "FPDI": "LDI");
675
    else
676
	xf86DrvMsg(rhdPtr->scrnIndex, X_PROBED,
677
		   "Detected a 18bit %s link panel.\n",
678
             Private->DualLink ? "dual" : "single");
679
 
680
    /* extra noise */
681
    RHDDebug(rhdPtr->scrnIndex, "Printing LVDS paramaters:\n");
682
    xf86MsgVerb(X_NONE, LOG_DEBUG, "\tMacroControl: 0x%08X\n",
683
		(unsigned int) Private->MacroControl);
684
    xf86MsgVerb(X_NONE, LOG_DEBUG, "\tTXClockPattern: 0x%04X\n",
685
		Private->TXClockPattern);
686
    xf86MsgVerb(X_NONE, LOG_DEBUG, "\tPowerDigToDE: 0x%04X\n",
687
		Private->PowerDigToDE);
688
    xf86MsgVerb(X_NONE, LOG_DEBUG, "\tPowerDEToBL: 0x%04X\n",
689
		Private->PowerDEToBL);
690
    xf86MsgVerb(X_NONE, LOG_DEBUG, "\tOffDelay: 0x%04X\n",
691
		Private->OffDelay);
692
    xf86MsgVerb(X_NONE, LOG_DEBUG, "\tPowerRefDiv: 0x%04X\n",
693
		Private->PowerRefDiv);
694
    xf86MsgVerb(X_NONE, LOG_DEBUG, "\tBlonRefDiv: 0x%04X\n",
695
		Private->BlonRefDiv);
696
 
697
    return Private;
698
}
699
 
700
/*
701
 *
702
 */
703
static void
704
LVDSDestroy(struct rhdOutput *Output)
705
{
706
 
707
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
708
 
709
    RHDFUNC(Output);
710
 
711
    if (!Private)
712
	return;
713
 
714
#ifdef NOT_YET
715
    if (Private->PropertyPrivate)
716
	RhdAtomDestroyBacklightControlProperty(Output, Private->PropertyPrivate);
717
#endif
718
    xfree(Private);
719
    Output->Private = NULL;
720
}
721
 
722
/*
723
 *
724
 * Handling for LVTMA block as TMDS.
725
 *
726
 */
727
struct rhdTMDSBPrivate {
728
    Bool RunsDualLink;
729
    Bool Coherent;
730
    DisplayModePtr Mode;
731
 
732
    struct rhdHdmi *Hdmi;
733
 
734
    Bool Stored;
735
 
736
    CARD32 StoreControl;
737
    CARD32 StoreSource;
738
    CARD32 StoreFormat;
739
    CARD32 StoreForce;
740
    CARD32 StoreReduction;
741
    CARD32 StoreDCBalancer;
742
    CARD32 StoreDataSynchro;
743
    CARD32 StoreMode;
744
    CARD32 StoreTXEnable;
745
    CARD32 StoreMacro;
746
    CARD32 StoreTXControl;
747
    CARD32 StoreTXAdjust;
748
    CARD32 StoreTestOutput;
749
 
750
    CARD32 StoreRs690Unknown;
751
    CARD32 StoreRv600TXAdjust;
752
    CARD32 StoreRv600PreEmphasis;
753
};
754
 
755
/*
756
 *
757
 */
758
static ModeStatus
759
TMDSBModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
760
{
761
    RHDFUNC(Output);
762
 
763
    if (Mode->Flags & V_INTERLACE)
764
        return MODE_NO_INTERLACE;
765
 
766
    if (Mode->Clock < 25000)
767
	return MODE_CLOCK_LOW;
768
 
769
    if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) {
770
    if (Mode->Clock > 165000)
771
	return MODE_CLOCK_HIGH;
772
    } else if (Output->Connector->Type == RHD_CONNECTOR_DVI) {
773
	if (Mode->Clock > 330000) /* could go higher still */
774
	    return MODE_CLOCK_HIGH;
775
    }
776
 
777
    return MODE_OK;
778
}
779
 
780
/*
781
 *
782
 */
783
static void
784
RS600VoltageControl(struct rhdOutput *Output, DisplayModePtr Mode)
785
{
786
    struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
787
 
788
    RHDFUNC(Output);
789
#ifdef NOTYET
790
    if (Output->Connector == RHD_CONNECTOR_HDMI || Output->Connector == RHD_CONNECTOR_HDMI_DUAL) {
791
	int clock = Mode->SynthClock;
792
 
793
	if (Private->RunsDualLink)
794
	    clock >>= 1;
795
	if (clock <= 75000) {
796
	    RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00010213);
797
	    RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x000a0000);
798
	} else {
799
	    RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00000213);
800
	    RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x00100000);
801
	}
802
    } else
803
#endif
804
    {
805
	if (Private->RunsDualLink) {
806
	    RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000020f);
807
	    RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x00100000);
808
	} else {
809
	    if (Mode->SynthClock < 39000)
810
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0002020f);
811
	    else
812
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000020f);
813
	    RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x00100000);
814
	}
815
    }
816
}
817
 
818
/*
819
 *
820
 */
821
static void
822
RS690VoltageControl(struct rhdOutput *Output, DisplayModePtr Mode)
823
{
824
    RHDPtr rhdPtr = RHDPTRI(Output);
825
    struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
826
    CARD32 rev = (RHDRegRead(Output, CONFIG_CNTL) && RS69_CFG_ATI_REV_ID_MASK) >> RS69_CFG_ATI_REV_ID_SHIFT;
827
 
828
    if (rev < 3) {
829
#ifdef NOTYET
830
	if (Output->Connector == RHD_CONNECTOR_HDMI || Output->Connector == RHD_CONNECTOR_HDMI_DUAL) {
831
	    if (Mode->SynthClock > 75000) {
832
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0xa001632f);
833
		RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x05120000);
834
		RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
835
	    } else if (Mode->SynthClock > 41000) {
836
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000632f);
837
		RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x05120000);
838
		RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
839
	    } else {
840
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0003632f);
841
		RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x050b000);
842
		RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x0, 0x10000000);
843
	    }
844
	} else
845
#endif
846
	{
847
	    int clock = Mode->SynthClock;
848
 
849
	    if (Private->RunsDualLink)
850
		clock >>= 1;
851
 
852
	    RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x05120000);
853
 
854
	    if (clock > 75000) {
855
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0xa001631f);
856
		RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
857
	    } else if (clock > 41000) {
858
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000631f);
859
		RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
860
	    } else {
861
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0003631f);
862
		RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x0, 0x10000000);
863
	    }
864
	}
865
    } else {
866
#ifdef NOTYET
867
	if (Output->Connector == RHD_CONNECTOR_HDMI || Output->Connector == RHD_CONNECTOR_HDMI_DUAL) {
868
	    if (Mode->SynthClock <= 75000) {
869
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0002612f);
870
		RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x010b0000);
871
		RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x0, 0x10000000);
872
	    } else {
873
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000642f);
874
		RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x01120000);
875
		RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
876
	    }
877
	} else
878
#endif
879
	{
880
	    int clock = Mode->SynthClock;
881
 
882
	    if (Private->RunsDualLink)
883
		clock >>= 1;
884
 
885
	    RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x01120000);
886
	    RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
887
 
888
	    if (Mode->SynthClock > 75000) {
889
		RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00016318);
890
	    } else {
891
		{
892
#ifdef ATOM_BIOS
893
		    AtomBiosArgRec data;
894
 
895
        if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
896
					ATOM_GET_CAPABILITY_FLAG, &data) == ATOM_SUCCESS) {
897
			if (((data.val & 0x60) == 0x20 || (data.val & 0x80))) {
898
			    RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00016318);
899
			} else {
900
			    RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00006318);
901
			}
902
		    } else
903
#endif
904
		    {
905
			RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00006318);
906
		    }
907
		}
908
	    }
909
	}
910
    }
911
}
912
 
913
/*
914
 * This information is not provided in an atombios data table.
915
 */
916
static struct R5xxTMDSBMacro {
917
    CARD16 Device;
918
    CARD32 MacroSingle;
919
    CARD32 MacroDual;
920
} R5xxTMDSBMacro[] = {
921
    /*
922
     * this list isn't complete yet.
923
     *  Some more values for dual need to be dug up
924
     */
925
    { 0x7104, 0x00F20616, 0x00F20616 }, /* R520  */
926
    { 0x7142, 0x00F2061C, 0x00F2061C }, /* RV515 */
927
    { 0x7145, 0x00F1061D, 0x00F2061D }, /**/
928
    { 0x7146, 0x00F1061D, 0x00F1061D }, /* RV515 */
929
    { 0x7147, 0x0082041D, 0x0082041D }, /* RV505 */
930
    { 0x7149, 0x00F1061D, 0x00D2061D }, /**/
931
    { 0x7152, 0x00F2061C, 0x00F2061C }, /* RV515 */
932
    { 0x7183, 0x00B2050C, 0x00B2050C }, /* RV530 */
933
    { 0x71C0, 0x00F1061F, 0x00f2061D }, /**/
934
    { 0x71C1, 0x0062041D, 0x0062041D }, /* RV535 *//**/
935
    { 0x71C2, 0x00F1061D, 0x00F2061D }, /* RV530 *//**/
936
    { 0x71C5, 0x00D1061D, 0x00D2061D }, /**/
937
    { 0x71C6, 0x00F2061D, 0x00F2061D }, /* RV530 */
938
    { 0x71D2, 0x00F10610, 0x00F20610 }, /* RV530: atombios uses 0x00F1061D *//**/
939
    { 0x7249, 0x00F1061D, 0x00F1061D }, /* R580  */
940
    { 0x724B, 0x00F10610, 0x00F10610 }, /* R580: atombios uses 0x00F1061D */
941
    { 0x7280, 0x0042041F, 0x0042041F }, /* RV570 *//**/
942
    { 0x7288, 0x0042041F, 0x0042041F }, /* RV570 */
943
    { 0x791E, 0x0001642F, 0x0001642F }, /* RS690 */
944
    { 0x791F, 0x0001642F, 0x0001642F }, /* RS690 */
945
    { 0x9400, 0x00020213, 0x00020213 }, /* R600  */
946
    { 0x9401, 0x00020213, 0x00020213 }, /* R600  */
947
    { 0x9402, 0x00020213, 0x00020213 }, /* R600  */
948
    { 0x9403, 0x00020213, 0x00020213 }, /* R600  */
949
    { 0x9405, 0x00020213, 0x00020213 }, /* R600  */
950
    { 0x940A, 0x00020213, 0x00020213 }, /* R600  */
951
    { 0x940B, 0x00020213, 0x00020213 }, /* R600  */
952
    { 0x940F, 0x00020213, 0x00020213 }, /* R600  */
953
    { 0, 0, 0 } /* End marker */
954
};
955
 
956
static struct RV6xxTMDSBMacro {
957
    CARD16 Device;
958
    CARD32 Macro;
959
    CARD32 TX;
960
    CARD32 PreEmphasis;
961
} RV6xxTMDSBMacro[] = {
962
    { 0x94C1, 0x01030311, 0x10001A00, 0x01801015}, /* RV610 */
963
    { 0x94C3, 0x01030311, 0x10001A00, 0x01801015}, /* RV610 */
964
    { 0x9501, 0x0533041A, 0x020010A0, 0x41002045}, /* RV670 */
965
    { 0x9505, 0x0533041A, 0x020010A0, 0x41002045}, /* RV670 */
966
    { 0x950F, 0x0533041A, 0x020010A0, 0x41002045}, /* R680  */
967
    { 0x9587, 0x01030311, 0x10001C00, 0x01C01011}, /* RV630 */
968
    { 0x9588, 0x01030311, 0x10001C00, 0x01C01011}, /* RV630 */
969
    { 0x9589, 0x01030311, 0x10001C00, 0x01C01011}, /* RV630 */
970
    { 0, 0, 0, 0} /* End marker */
971
};
972
 
973
static void
974
TMDSBVoltageControl(struct rhdOutput *Output, DisplayModePtr Mode)
975
{
976
    struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
977
    RHDPtr rhdPtr = RHDPTRI(Output);
978
  int i;
979
 
980
    /* IGP chipsets are rather special */
981
    if (rhdPtr->ChipSet == RHD_RS690) {
982
	RS690VoltageControl(Output, Mode);
983
	return;
984
    } else if (rhdPtr->ChipSet == RHD_RS600) {
985
	RS600VoltageControl(Output, Mode);
986
	return;
987
    }
988
 
989
    /* TEST_OUTPUT register - IGPs are handled above */
990
    if (rhdPtr->ChipSet < RHD_RS600) /* r5xx */
991
	RHDRegMask(Output, LVTMA_REG_TEST_OUTPUT, 0x00200000, 0x00200000);
992
    else if (rhdPtr->ChipSet < RHD_RV670)
993
	RHDRegMask(Output, LVTMA_REG_TEST_OUTPUT, 0x00100000, 0x00100000);
994
 
995
    /* macro control values */
996
    if (rhdPtr->ChipSet < RHD_RV610) { /* R5xx and R600 */
997
    for (i = 0; R5xxTMDSBMacro[i].Device; i++)
998
	    if (R5xxTMDSBMacro[i].Device == rhdPtr->PciDeviceID) {
999
		if (!Private->RunsDualLink)
1000
		    RHDRegWrite(Output, LVTMA_MACRO_CONTROL, R5xxTMDSBMacro[i].MacroSingle);
1001
		else
1002
		    RHDRegWrite(Output, LVTMA_MACRO_CONTROL, R5xxTMDSBMacro[i].MacroDual);
1003
        return;
1004
	    }
1005
 
1006
	xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
1007
		   __func__, rhdPtr->PciDeviceID);
1008
	xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_MACRO_CONTROL: 0x%08X\n",
1009
		   (unsigned int) RHDRegRead(Output, LVTMA_MACRO_CONTROL));
1010
    } else { /* RV6x0 and up */
1011
    for (i = 0; RV6xxTMDSBMacro[i].Device; i++)
1012
	    if (RV6xxTMDSBMacro[i].Device == rhdPtr->PciDeviceID) {
1013
        RHDRegWrite(Output, LVTMA_MACRO_CONTROL, RV6xxTMDSBMacro[i].Macro);
1014
        RHDRegWrite(Output, LVTMA_TRANSMITTER_ADJUST, RV6xxTMDSBMacro[i].TX);
1015
        RHDRegWrite(Output, LVTMA_PREEMPHASIS_CONTROL, RV6xxTMDSBMacro[i].PreEmphasis);
1016
        return;
1017
	    }
1018
 
1019
	xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
1020
		   __func__, rhdPtr->PciDeviceID);
1021
	xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_MACRO_CONTROL: 0x%08X\n",
1022
            (unsigned int) RHDRegRead(Output, LVTMA_MACRO_CONTROL));
1023
	xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_TRANSMITTER_ADJUST: 0x%08X\n",
1024
            (unsigned int) RHDRegRead(Output, LVTMA_TRANSMITTER_ADJUST));
1025
	xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_PREEMPHASIS_CONTROL: 0x%08X\n",
1026
            (unsigned int) RHDRegRead(Output, LVTMA_PREEMPHASIS_CONTROL));
1027
    }
1028
}
1029
 
1030
/*
1031
 *
1032
 */
1033
static Bool
1034
TMDSBPropertyControl(struct rhdOutput *Output,
1035
	     enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val)
1036
{
1037
    struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
1038
 
1039
    RHDFUNC(Output);
1040
    switch (Action) {
1041
	case rhdPropertyCheck:
1042
	    switch (Property) {
1043
		case RHD_OUTPUT_COHERENT:
1044
		    return TRUE;
1045
		default:
1046
		    return FALSE;
1047
	    }
1048
	case rhdPropertyGet:
1049
	    switch (Property) {
1050
		case RHD_OUTPUT_COHERENT:
1051
		    val->Bool = Private->Coherent;
1052
		    return TRUE;
1053
		default:
1054
		    return FALSE;
1055
	    }
1056
	    break;
1057
	case rhdPropertySet:
1058
	    switch (Property) {
1059
		case RHD_OUTPUT_COHERENT:
1060
		    Private->Coherent = val->Bool;
1061
		    Output->Mode(Output, Private->Mode);
1062
		    Output->Power(Output, RHD_POWER_ON);
1063
		    break;
1064
		default:
1065
		    return FALSE;
1066
	    }
1067
	    break;
1068
    }
1069
    return TRUE;
1070
}
1071
 
1072
/*
1073
 *
1074
 */
1075
static void
1076
TMDSBSet(struct rhdOutput *Output, DisplayModePtr Mode)
1077
{
1078
    RHDPtr rhdPtr = RHDPTRI(Output);
1079
    struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
1080
 
1081
    RHDFUNC(Output);
1082
 
1083
    RHDRegMask(Output, LVTMA_MODE, 0x00000001, 0x00000001); /* select TMDS */
1084
 
1085
    /* Clear out some HPD events first: this should be under driver control. */
1086
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x0000000C);
1087
    RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00070000);
1088
    RHDRegMask(Output, LVTMA_CNTL, 0, 0x00000010);
1089
 
1090
    /* Disable the transmitter */
1091
	RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E);
1092
 
1093
    /* Disable bit reduction and reset temporal dither */
1094
    RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0x00010101);
1095
    RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, LVTMA_DITHER_RESET_BIT, LVTMA_DITHER_RESET_BIT);
1096
    usleep(2);
1097
    RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, LVTMA_DITHER_RESET_BIT);
1098
    RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0xF0000000); /* not documented */
1099
 
1100
    /* reset phase on vsync and use RGB */
1101
    RHDRegMask(Output, LVTMA_CNTL, 0x00001000, 0x00011000);
1102
 
1103
    /* Select CRTC, select syncA, no stereosync */
1104
    RHDRegMask(Output, LVTMA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101);
1105
 
1106
    RHDRegWrite(Output, LVTMA_COLOR_FORMAT, 0);
1107
 
1108
    Private->Mode = Mode;
1109
    if (Mode->SynthClock > 165000) {
1110
	RHDRegMask(Output, LVTMA_CNTL, 0x01000000, 0x01000000);
1111
	Private->RunsDualLink = TRUE; /* for TRANSMITTER_ENABLE in TMDSBPower */
1112
    } else {
1113
    RHDRegMask(Output, LVTMA_CNTL, 0, 0x01000000);
1114
	Private->RunsDualLink = FALSE;
1115
    }
1116
 
1117
    if (rhdPtr->ChipSet > RHD_R600) /* Rv6xx: disable split mode */
1118
	RHDRegMask(Output, LVTMA_CNTL, 0, 0x20000000);
1119
 
1120
    /* Disable force data */
1121
    RHDRegMask(Output, LVTMA_FORCE_OUTPUT_CNTL, 0, 0x00000001);
1122
 
1123
    /* DC balancer enable */
1124
    RHDRegMask(Output, LVTMA_DCBALANCER_CONTROL, 0x00000001, 0x00000001);
1125
 
1126
    TMDSBVoltageControl(Output, Mode);
1127
 
1128
    /* use IDCLK */
1129
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010);
1130
    /* LVTMA only: use clock selected by next write */
1131
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x20000000, 0x20000000);
1132
    /* coherent mode */
1133
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL,
1134
	       Private->Coherent ? 0 : 0x10000000, 0x10000000);
1135
    /* clear LVDS clock pattern */
1136
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x03FF0000);
1137
 
1138
    /* reset transmitter pll */
1139
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
1140
    usleep(2);
1141
    RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002);
1142
    usleep(20);
1143
 
1144
    /* restart data synchronisation */
1145
    RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000001, 0x00000001);
1146
    RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000100, 0x00000100);
1147
    usleep(2);
1148
    RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0, 0x00000001);
1149
 
1150
    RHDHdmiSetMode(Private->Hdmi, Mode);
1151
}
1152
 
1153
/*
1154
 *
1155
 */
1156
static void
1157
TMDSBPower(struct rhdOutput *Output, int Power)
1158
{
1159
    RHDPtr rhdPtr = RHDPTRI(Output);
1160
    struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
1161
 
1162
    RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
1163
	     rhdPowerString[Power]);
1164
 
1165
    RHDRegMask(Output, LVTMA_MODE, 0x00000001, 0x00000001); /* select TMDS */
1166
 
1167
    switch (Power) {
1168
    case RHD_POWER_ON:
1169
	RHDRegMask(Output, LVTMA_CNTL, 0x1, 0x00000001);
1170
 
1171
	if (Private->RunsDualLink)
1172
	    RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00003E3E,0x00003E3E);
1173
	else
1174
	    RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x0000003E, 0x00003E3E);
1175
 
1176
	RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001);
1177
	usleep(2);
1178
	RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002);
1179
	if(Output->Connector != NULL && RHDConnectorEnableHDMI(Output->Connector))
1180
	    RHDHdmiEnable(Private->Hdmi, TRUE);
1181
	else
1182
	    RHDHdmiEnable(Private->Hdmi, FALSE);
1183
	return;
1184
    case RHD_POWER_RESET:
1185
	RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E);
1186
	return;
1187
    case RHD_POWER_SHUTDOWN:
1188
    default:
1189
	RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
1190
	usleep(2);
1191
	RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000001);
1192
	RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E);
1193
	RHDRegMask(Output, LVTMA_CNTL, 0, 0x00000001);
1194
	RHDHdmiEnable(Private->Hdmi, FALSE);
1195
	return;
1196
    }
1197
}
1198
 
1199
/*
1200
 *
1201
 */
1202
static void
1203
TMDSBSave(struct rhdOutput *Output)
1204
{
1205
    struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
1206
    RHDPtr rhdPtr = RHDPTRI(Output);
1207
 
1208
    RHDFUNC(Output);
1209
 
1210
    Private->StoreControl = RHDRegRead(Output, LVTMA_CNTL);
1211
    Private->StoreSource = RHDRegRead(Output, LVTMA_SOURCE_SELECT);
1212
    Private->StoreFormat = RHDRegRead(Output, LVTMA_COLOR_FORMAT);
1213
    Private->StoreForce = RHDRegRead(Output, LVTMA_FORCE_OUTPUT_CNTL);
1214
    Private->StoreReduction = RHDRegRead(Output, LVTMA_BIT_DEPTH_CONTROL);
1215
    Private->StoreDCBalancer = RHDRegRead(Output, LVTMA_DCBALANCER_CONTROL);
1216
 
1217
    Private->StoreDataSynchro = RHDRegRead(Output, LVTMA_DATA_SYNCHRONIZATION);
1218
    Private->StoreMode = RHDRegRead(Output, LVTMA_MODE);
1219
    Private->StoreTXEnable = RHDRegRead(Output, LVTMA_TRANSMITTER_ENABLE);
1220
    Private->StoreMacro = RHDRegRead(Output, LVTMA_MACRO_CONTROL);
1221
    Private->StoreTXControl = RHDRegRead(Output, LVTMA_TRANSMITTER_CONTROL);
1222
    Private->StoreTestOutput = RHDRegRead(Output, LVTMA_REG_TEST_OUTPUT);
1223
 
1224
    if (rhdPtr->ChipSet > RHD_R600) { /* Rv6x0 */
1225
       Private->StoreRv600TXAdjust = RHDRegRead(Output, LVTMA_TRANSMITTER_ADJUST);
1226
       Private->StoreRv600PreEmphasis = RHDRegRead(Output, LVTMA_PREEMPHASIS_CONTROL);
1227
    }
1228
 
1229
    RHDHdmiSave(Private->Hdmi);
1230
 
1231
    Private->Stored = TRUE;
1232
}
1233
 
1234
/*
1235
 *
1236
 */
1237
static void
1238
TMDSBRestore(struct rhdOutput *Output)
1239
{
1240
    struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
1241
    RHDPtr rhdPtr = RHDPTRI(Output);
1242
 
1243
    RHDFUNC(Output);
1244
 
1245
    if (!Private->Stored) {
1246
	xf86DrvMsg(Output->scrnIndex, X_ERROR,
1247
		   "%s: No registers stored.\n", __func__);
1248
	return;
1249
    }
1250
 
1251
    RHDRegWrite(Output, LVTMA_CNTL, Private->StoreControl);
1252
    RHDRegWrite(Output, LVTMA_SOURCE_SELECT, Private->StoreSource);
1253
    RHDRegWrite(Output, LVTMA_COLOR_FORMAT, Private->StoreFormat);
1254
    RHDRegWrite(Output, LVTMA_FORCE_OUTPUT_CNTL, Private->StoreForce);
1255
    RHDRegWrite(Output, LVTMA_BIT_DEPTH_CONTROL, Private->StoreReduction);
1256
    RHDRegWrite(Output, LVTMA_DCBALANCER_CONTROL, Private->StoreDCBalancer);
1257
 
1258
    RHDRegWrite(Output, LVTMA_DATA_SYNCHRONIZATION, Private->StoreDataSynchro);
1259
    RHDRegWrite(Output, LVTMA_MODE, Private->StoreMode);
1260
    RHDRegWrite(Output, LVTMA_TRANSMITTER_ENABLE, Private->StoreTXEnable);
1261
    RHDRegWrite(Output, LVTMA_MACRO_CONTROL, Private->StoreMacro);
1262
    RHDRegWrite(Output, LVTMA_TRANSMITTER_CONTROL, Private->StoreTXControl);
1263
    RHDRegWrite(Output, LVTMA_REG_TEST_OUTPUT, Private->StoreTestOutput);
1264
 
1265
    if (rhdPtr->ChipSet > RHD_R600) { /* Rv6x0 */
1266
	RHDRegWrite(Output, LVTMA_TRANSMITTER_ADJUST, Private->StoreRv600TXAdjust);
1267
	RHDRegWrite(Output, LVTMA_PREEMPHASIS_CONTROL, Private->StoreRv600PreEmphasis);
1268
    }
1269
 
1270
    RHDHdmiRestore(Private->Hdmi);
1271
}
1272
 
1273
 
1274
/*
1275
 *
1276
 */
1277
static void
1278
TMDSBDestroy(struct rhdOutput *Output)
1279
{
1280
    struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
1281
    RHDFUNC(Output);
1282
 
1283
    if (!Private)
1284
	return;
1285
 
1286
    RHDHdmiDestroy(Private->Hdmi);
1287
 
1288
    xfree(Private);
1289
    Output->Private = NULL;
1290
}
1291
 
1292
#ifdef NOT_YET
1293
static Bool
1294
LVDSPropertyWrapper(struct rhdOutput *Output,
1295
		    enum rhdPropertyAction Action,
1296
		    enum rhdOutputProperty Property,
1297
		    union rhdPropertyData *val)
1298
{
1299
    struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
1300
    void *storePrivate = Output->Private;
1301
    Bool (*func)(struct rhdOutput *,enum rhdPropertyAction, enum rhdOutputProperty,
1302
		  union rhdPropertyData *) = Private->WrappedPropertyCallback;
1303
    Bool ret;
1304
 
1305
    Output->Private = Private->PropertyPrivate;
1306
    ret = func(Output, Action, Property, val);
1307
    Output->Private = storePrivate;
1308
 
1309
    return ret;
1310
}
1311
#endif
1312
 
1313
/*
1314
 *
1315
 */
1316
struct rhdOutput *
1317
RHDLVTMAInit(RHDPtr rhdPtr, CARD8 Type)
1318
{
1319
    struct rhdOutput *Output;
1320
 
1321
    RHDFUNC(rhdPtr);
1322
 
1323
    /* Stop weird connector types */
1324
    if ((Type != RHD_CONNECTOR_PANEL)
1325
	&& (Type != RHD_CONNECTOR_DVI)
1326
	&& (Type != RHD_CONNECTOR_DVI_SINGLE)) {
1327
	xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: unhandled connector type:"
1328
		   " %d\n", __func__, Type);
1329
	return NULL;
1330
    }
1331
 
1332
    Output = xnfcalloc(sizeof(struct rhdOutput), 1);
1333
 
1334
    Output->scrnIndex = rhdPtr->scrnIndex;
1335
    Output->Id = RHD_OUTPUT_LVTMA;
1336
 
1337
    Output->Sense = NULL; /* not implemented in hw */
1338
 
1339
    if (Type == RHD_CONNECTOR_PANEL) {
1340
	struct LVDSPrivate *Private;
1341
 
1342
	Output->Name = "LVDS";
1343
 
1344
	Output->ModeValid = LVDSModeValid;
1345
	Output->Mode = LVDSSet;
1346
	Output->Power = LVDSPower;
1347
	Output->Save = LVDSSave;
1348
	Output->Restore = LVDSRestore;
1349
	Output->Property = LVDSPropertyControl;
1350
	Output->Destroy = LVDSDestroy;
1351
	Output->Private = Private =  LVDSInfoRetrieve(rhdPtr);
1352
#ifdef NOT_YET
1353
	if (Private->BlLevel < 0) {
1354
	    Private->BlLevel = RhdAtomSetupBacklightControlProperty(Output, &Private->WrappedPropertyCallback,
1355
								    &Private->PropertyPrivate);
1356
	    if (Private->PropertyPrivate)
1357
		Output->Property = LVDSPropertyWrapper;
1358
	} else
1359
#else
1360
	if (Private->BlLevel >= 0)
1361
#endif
1362
	    LVDSDebugBacklight(Output);
1363
 
1364
    } else {
1365
	struct rhdTMDSBPrivate *Private = xnfcalloc(sizeof(struct rhdTMDSBPrivate), 1);
1366
 
1367
	Output->Name = "TMDS B";
1368
 
1369
	Output->ModeValid = TMDSBModeValid;
1370
	Output->Mode = TMDSBSet;
1371
	Output->Power = TMDSBPower;
1372
	Output->Save = TMDSBSave;
1373
	Output->Restore = TMDSBRestore;
1374
	Output->Property = TMDSBPropertyControl;
1375
	Output->Destroy = TMDSBDestroy;
1376
 
1377
	Private->Hdmi = RHDHdmiInit(rhdPtr, Output);
1378
	Output->Private = Private;
1379
 
1380
	Private->RunsDualLink = FALSE;
1381
	Private->Coherent = FALSE;
1382
    }
1383
 
1384
    return Output;
1385
}