Subversion Repositories Kolibri OS

Rev

Rev 1029 | Details | Compare with Previous | 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
#endif
38
 
39
#include "rhd.h"
40
#include "rhd_crtc.h"
41
#include "rhd_connector.h"
42
#include "rhd_output.h"
43
#include "rhd_regs.h"
44
#ifdef ATOM_BIOS
45
#include "rhd_atombios.h"
46
#endif
47
 
48
struct DDIAPrivate
49
{
50
    Bool RunDualLink;
51
    CARD32 PcieCfgReg7;
52
    CARD32 CapabilityFlag;
53
 
54
    Bool Stored;
55
 
56
    CARD32 DdiaPathControl;
57
    CARD32 DdiaCntl;
58
    CARD32 DdiaDcbalancerControl;
59
    CARD32 DdiaPcieLinkControl2;
60
    CARD32 DdiaBitDepthControl;
61
};
62
 
63
/*
64
 *
65
 */
66
static ModeStatus
67
DDIAModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
68
{
69
    RHDFUNC(Output);
70
 
71
    if (Mode->Flags & V_INTERLACE)
72
        return MODE_NO_INTERLACE;
73
 
74
    if (Mode->Clock < 25000)
75
	return MODE_CLOCK_LOW;
76
 
77
    if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) {
78
	if (Mode->Clock > 165000)
79
	    return MODE_CLOCK_HIGH;
80
    } else if (Output->Connector->Type == RHD_CONNECTOR_DVI) {
81
	if (Mode->Clock > 330000) /* could go higher still */
82
	    return MODE_CLOCK_HIGH;
83
    }
84
 
85
    return MODE_OK;
86
}
87
 
88
/*
89
 *
90
 */
91
static void
92
DDIAMode(struct rhdOutput *Output, DisplayModePtr Mode)
93
{
94
    struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private;
95
    CARD32 mux0, mux1, mux2, mux3;
96
    Bool LaneReversal;
97
    RHDPtr rhdPtr = RHDPTRI(Output);
98
 
99
    RHDFUNC(Output);
100
 
101
    if (Mode->SynthClock >= 165000)
102
	Private->RunDualLink = TRUE;
103
    else
104
	Private->RunDualLink = FALSE;
105
 
106
    /* reset on - will be enabled at POWER_ON */
107
    RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, RS69_DDIA_PIXVLD_RESET, RS69_DDIA_PIXVLD_RESET);
108
    /* RGB 4:4:4 */
109
    RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_PIXEL_ENCODING);
110
    /* TMDS_AC */
111
    RHDRegMask(Output, RS69_DDIA_PATH_CONTROL,
112
	       2 << RS69_DDIA_PATH_SELECT_SHIFT,
113
	       0x3 << RS69_DDIA_PATH_SELECT_SHIFT);
114
    /* dual link */
115
    RHDRegMask(Output, RS69_DDIA_CNTL, Private->RunDualLink ?
116
	       RS69_DDIA_DUAL_LINK_ENABLE : 0, RS69_DDIA_DUAL_LINK_ENABLE);
117
    RHDRegMask(Output, RS69_DDIA_DCBALANCER_CONTROL,
118
	       RS69_DDIA_DCBALANCER_EN,
119
	       RS69_DDIA_SYNC_DCBAL_EN_MASK | RS69_DDIA_DCBALANCER_EN);
120
 
121
    RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x80);
122
    RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x100);
123
 
124
    mux0 = Private->PcieCfgReg7 & 0x3;
125
    mux1 = (Private->PcieCfgReg7 >> 2) & 0x3;
126
    mux2 = (Private->PcieCfgReg7 >> 4) & 0x3;
127
    mux3 = (Private->PcieCfgReg7 >> 6) & 0x3;
128
 
129
    RHDRegMask(Output, RS69_DDIA_PCIE_LINK_CONTROL2,
130
	       (mux0 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL0)
131
	       | (mux1 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL1)
132
	       | (mux2 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL2)
133
	       | (mux3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL3),
134
	       (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL0)
135
	       | (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL1)
136
	       | (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL2)
137
	       | (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL3)
138
	);
139
    LaneReversal = Private->PcieCfgReg7 & (0x1 << 10);
140
    RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x3);
141
    RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x2, 0x2);
142
 
143
    RHDRegMask(Output, RS69_DDIA_PCIE_LINK_CONTROL3,
144
	       LaneReversal ? RS69_DDIA_PCIE_MIRROR_EN : 0,
145
	       RS69_DDIA_PCIE_MIRROR_EN);
146
 
147
    RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x70, 0x70);
148
 
149
    RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0, 0x10);
150
    RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0, 0x60);
151
    RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0, 0x4000000);
152
 
153
    switch (rhdPtr->PciDeviceID) {
154
	case 0x791E:
155
	    if (Mode->SynthClock <= 25000) {
156
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x2780, 0x3f80);
157
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000);
158
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x039f0000, 0x03000000 | 0x039f0000);
159
	    } else if (Mode->SynthClock <= 60000) {
160
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x2780, 0x3f80);
161
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000);
162
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x024f0000, 0x03000000 | 0x024f0000);
163
	    } else {
164
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0980, 0x3f80);
165
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000);
166
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x01270000, 0x03000000 | 0x01270000);
167
	    }
168
	    break;
169
	case 0x791F:
170
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0980, 0x3f80);
171
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x4000, 0xc000);
172
		RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x00ac0000, 0x03000000 | 0x00ac0000);
173
		if (Private->CapabilityFlag & 0x10) {
174
		    RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000);
175
		    if (Mode->SynthClock <= 6500)
176
			RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x01ac0000, 0x03ff0000);
177
		    else
178
			RHDRegMaskD(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x01110000, 0x03ff0000);
179
		}
180
	    break;
181
    }
182
    usleep (1);
183
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x04000000, 0x04000000);
184
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x60, 0x60);
185
    usleep(30);
186
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x01, 0x01);
187
    usleep(1);
188
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x02, 0x02);
189
    usleep(1);
190
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x04, 0x04);
191
    usleep(1);
192
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x08, 0x08);
193
    usleep(1);
194
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x10, 0x10);
195
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xf);
196
 
197
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x0180, 0x0180);
198
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x600, 0x600);
199
    usleep(5);
200
    RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x600);
201
 
202
    /* hw reset will be turned off at POWER_ON */
203
 
204
    /* select crtc source, sync_a, no stereosync */
205
    RHDRegMask(Output, RS69_DDIA_SOURCE_SELECT, Output->Crtc->Id,
206
	       RS69_DDIA_SOURCE_SELECT_BIT
207
	       | RS69_DDIA_SYNC_SELECT
208
	       | RS69_DDIA_STEREOSYNC_SELECT);
209
}
210
 
211
/*
212
 *
213
 */
214
static void
215
DDIAPower(struct rhdOutput *Output, int Power)
216
{
217
    RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
218
	     rhdPowerString[Power]);
219
 
220
    switch (Power) {
221
	case RHD_POWER_ON:
222
	    RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, RS69_DDIA_PIXVLD_RESET,
223
		       RS69_DDIA_PIXVLD_RESET);
224
	    RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, 0);
225
	    RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
226
		       RS69_DDIA_TEMPORAL_DITHER_RESET, RS69_DDIA_TEMPORAL_DITHER_RESET);
227
	    RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
228
		       0, RS69_DDIA_TEMPORAL_DITHER_RESET);
229
	    RHDRegMask(Output, RS69_DDIA_CNTL, RS69_DDIA_ENABLE, RS69_DDIA_ENABLE);
230
	    RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, 0, RS69_DDIA_PIXVLD_RESET);
231
	    return;
232
	case RHD_POWER_RESET:
233
	    RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_ENABLE);
234
	    return;
235
	case RHD_POWER_SHUTDOWN:
236
	    RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
237
		       RS69_DDIA_TEMPORAL_DITHER_RESET, RS69_DDIA_TEMPORAL_DITHER_RESET);
238
	    RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
239
		       0, RS69_DDIA_TEMPORAL_DITHER_RESET);
240
	    RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
241
		       0,
242
		       RS69_DDIA_TRUNCATE_EN
243
		       | RS69_DDIA_TRUNCATE_DEPTH
244
		       | RS69_DDIA_SPATIAL_DITHER_EN
245
		       | RS69_DDIA_SPATIAL_DITHER_DEPTH);
246
	    RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
247
		       0,
248
		       RS69_DDIA_TEMPORAL_DITHER_EN
249
		       | RS69_DDIA_TEMPORAL_DITHER_EN
250
		       | RS69_DDIA_TEMPORAL_DITHER_DEPTH
251
		       | RS69_DDIA_TEMPORAL_LEVEL);
252
	    RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_ENABLE);
253
	    return;
254
	default:
255
	    return;
256
    }
257
}
258
 
259
/*
260
 *
261
 */
262
static void
263
DDIASave(struct rhdOutput *Output)
264
{
265
    struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private;
266
 
267
    RHDFUNC(Output);
268
 
269
    Private->DdiaPathControl = RHDRegRead(Output, RS69_DDIA_PATH_CONTROL);
270
    Private->DdiaCntl = RHDRegRead(Output, RS69_DDIA_CNTL);
271
    Private->DdiaDcbalancerControl = RHDRegRead(Output, RS69_DDIA_DCBALANCER_CONTROL);
272
    Private->DdiaPcieLinkControl2 = RHDRegRead(Output, RS69_DDIA_PCIE_LINK_CONTROL2);
273
    Private->DdiaBitDepthControl = RHDRegRead(Output, RS69_DDIA_BIT_DEPTH_CONTROL);
274
 
275
    Private->Stored = TRUE;
276
}
277
 
278
/*
279
 *
280
 */
281
static void
282
DDIARestore(struct rhdOutput *Output)
283
{
284
    struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private;
285
    RHDFUNC(Output);
286
 
287
    if (!Private->Stored)
288
	return;
289
 
290
    /* disalbe */
291
    RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_ENABLE);
292
    /* reset on */
293
    RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, RS69_DDIA_PIXVLD_RESET, RS69_DDIA_PIXVLD_RESET);
294
    RHDRegWrite(Output, RS69_DDIA_PATH_CONTROL, Private->DdiaPathControl | RS69_DDIA_PIXVLD_RESET);
295
 
296
    RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, Private->DdiaBitDepthControl);
297
    /* temporal dither reset on */
298
    RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, Private->DdiaBitDepthControl
299
	       | RS69_DDIA_TEMPORAL_DITHER_RESET);
300
    /* temporal dither reset off */
301
    RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, Private->DdiaBitDepthControl);
302
 
303
    RHDRegWrite(Output, RS69_DDIA_DCBALANCER_CONTROL, Private->DdiaDcbalancerControl);
304
    RHDRegWrite(Output, RS69_DDIA_PCIE_LINK_CONTROL2, Private->DdiaPcieLinkControl2);
305
    /* enable if enabled at startup */
306
    RHDRegWrite(Output, RS69_DDIA_CNTL, Private->DdiaCntl);
307
    /* reset off */
308
    RHDRegWrite(Output, RS69_DDIA_PATH_CONTROL, Private->DdiaPathControl);
309
}
310
 
311
/*
312
 *
313
 */
314
static void
315
DDIADestroy(struct rhdOutput *Output)
316
{
317
    struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private;
318
 
319
    RHDFUNC(Output);
320
 
321
    xfree(Private);
322
    Output->Private = NULL;
323
}
324
 
325
/*
326
 *
327
 */
328
struct rhdOutput *
329
RHDDDIAInit(RHDPtr rhdPtr)
330
{
331
#ifdef ATOM_BIOS
332
    struct rhdOutput *Output;
333
    struct DDIAPrivate *Private;
334
    AtomBiosArgRec data;
335
 
336
    RHDFUNC(rhdPtr);
337
 
338
    /*
339
     * This needs to be handled separately
340
     * for now we only deal with it here.
341
     */
342
    if (rhdPtr->ChipSet < RHD_RS600 || rhdPtr->ChipSet >= RHD_RS740)
343
	return FALSE;
344
 
345
    Output = xnfcalloc(sizeof(struct rhdOutput), 1);
346
 
347
    Output->Name = "DDIA";
348
 
349
    Output->scrnIndex = rhdPtr->scrnIndex;
350
    Output->Id = RHD_OUTPUT_DVO;
351
 
352
    Output->Sense = NULL;
353
    Output->ModeValid = DDIAModeValid;
354
    Output->Mode = DDIAMode;
355
    Output->Power = DDIAPower;
356
    Output->Save = DDIASave;
357
    Output->Restore = DDIARestore;
358
    Output->Destroy = DDIADestroy;
359
 
360
    Private = xnfcalloc(1, sizeof(struct DDIAPrivate));
361
    Output->Private = Private;
362
    Private->Stored = FALSE;
363
 
364
    if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
365
			ATOM_GET_PCIENB_CFG_REG7, &data) == ATOM_SUCCESS) {
366
	Private->PcieCfgReg7 = data.val;
367
    } else {
368
	xf86DrvMsg(Output->scrnIndex, X_ERROR, "Retrieval of PCIE MUX values failed. "
369
		   "no DDIA block support available\n");
370
	goto error;
371
    }
372
    if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
373
			 ATOM_GET_CAPABILITY_FLAG, &data) == ATOM_SUCCESS) {
374
	Private->CapabilityFlag = data.val;
375
    } else {
376
	xf86DrvMsg(Output->scrnIndex, X_ERROR, "Retrieval of Capability flag failed. "
377
		   "no DDIA block support available\n");
378
	goto error;
379
    }
380
 
381
    return Output;
382
error:
383
    xfree(Private);
384
    return NULL;
385
 
386
#else
387
    return NULL;
388
#endif
389
}