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 | }>>>>=>>>=>>><>><>><>><>><>=>=>><>><>><>><>><>><>><>><>>>>><>><>><>> |