Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1029 | serge | 1 | /* |
2 | * Copyright 2007, 2008 Luc Verhaegen |
||
3 | * Copyright 2007, 2008 Matthias Hopf |
||
4 | * Copyright 2007, 2008 Egbert Eich |
||
5 | * Copyright 2007, 2008 Advanced Micro Devices, Inc. |
||
6 | * |
||
7 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
8 | * copy of this software and associated documentation files (the "Software"), |
||
9 | * to deal in the Software without restriction, including without limitation |
||
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
11 | * and/or sell copies of the Software, and to permit persons to whom the |
||
12 | * Software is furnished to do so, subject to the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice shall be included in |
||
15 | * all copies or substantial portions of the Software. |
||
16 | * |
||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
20 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
23 | * OTHER DEALINGS IN THE SOFTWARE. |
||
24 | */ |
||
25 | |||
26 | #ifdef HAVE_CONFIG_H |
||
27 | #include "config.h" |
||
28 | #endif |
||
29 | |||
30 | #include "xf86.h" |
||
31 | |||
32 | /* for usleep */ |
||
33 | #if HAVE_XF86_ANSIC_H |
||
34 | # include "xf86_ansic.h" |
||
35 | #else |
||
36 | # include |
||
37 | #endif |
||
38 | |||
39 | #include "rhd.h" |
||
40 | #include "rhd_crtc.h" |
||
41 | #include "rhd_pll.h" |
||
42 | #include "rhd_connector.h" |
||
43 | #include "rhd_output.h" |
||
44 | #include "rhd_crtc.h" |
||
45 | #include "rhd_regs.h" |
||
46 | #if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) |
||
47 | # include "rhd_atombios.h" |
||
48 | # include "rhd_biosscratch.h" |
||
49 | |||
50 | struct atomPLLPrivate { |
||
51 | enum atomPxclk Pxclk; |
||
52 | struct atomPixelClockConfig Config; |
||
53 | struct atomCodeTableVersion Version; |
||
54 | |||
55 | CARD32 StoreFBDivFrac; |
||
56 | enum atomDevice StoreDevice; |
||
57 | enum rhdConnectorType StoreConnectorType; |
||
58 | enum rhdOutputType StoreOutputType; |
||
59 | int StoreCrtc; |
||
60 | }; |
||
61 | |||
62 | /* |
||
63 | * |
||
64 | */ |
||
65 | static void |
||
66 | getSetPixelClockParameters(struct rhdPLL *PLL, struct atomPixelClockConfig *Config, |
||
67 | enum rhdConnectorType ct, enum rhdOutputType ot, enum atomDevice device) |
||
68 | { |
||
69 | RHDPtr rhdPtr = RHDPTRI(PLL); |
||
70 | struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; |
||
71 | |||
72 | switch (Private->Version.cref) { |
||
73 | case 1: |
||
74 | break; |
||
75 | case 2: |
||
76 | Config->u.v2.Device = device; |
||
77 | Config->u.v2.Force = TRUE; |
||
78 | break; |
||
79 | case 3: |
||
80 | switch (ct) { |
||
81 | case RHD_CONNECTOR_VGA: |
||
82 | Config->u.v3.EncoderMode = atomNoEncoder; |
||
83 | break; |
||
84 | case RHD_CONNECTOR_DVI: |
||
85 | case RHD_CONNECTOR_DVI_SINGLE: |
||
86 | Config->u.v3.EncoderMode = atomDVI; |
||
87 | break; |
||
88 | case RHD_CONNECTOR_PANEL: |
||
89 | Config->u.v3.EncoderMode = atomLVDS; |
||
90 | break; |
||
91 | #if 0 |
||
92 | case RHD_CONNECTOR_DP: |
||
93 | case RHD_CONNECTOR_DP_DUAL: |
||
94 | Config->u.v3.EncoderMode = atomDP; |
||
95 | break; |
||
96 | case RHD_CONNECTOR_HDMI_A: |
||
97 | case RHD_CONNECTOR_HDMI_B: |
||
98 | Config->u.v3.EncoderMode = atomHDMI; |
||
99 | break; |
||
100 | #endif |
||
101 | default: |
||
102 | xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Unknown connector type: 0x%x\n",__func__,ct); |
||
103 | } |
||
104 | switch (ot) { |
||
105 | case RHD_OUTPUT_DACA: |
||
106 | Config->u.v3.OutputType = atomOutputDacA; |
||
107 | break; |
||
108 | case RHD_OUTPUT_DACB: |
||
109 | Config->u.v3.OutputType = atomOutputDacB; |
||
110 | break; |
||
111 | case RHD_OUTPUT_KLDSKP_LVTMA: |
||
112 | Config->u.v3.OutputType = atomOutputKldskpLvtma; |
||
113 | break; |
||
114 | case RHD_OUTPUT_UNIPHYA: |
||
115 | Config->u.v3.OutputType = atomOutputUniphyA; |
||
116 | break; |
||
117 | case RHD_OUTPUT_UNIPHYB: |
||
118 | Config->u.v3.OutputType = atomOutputUniphyB; |
||
119 | break; |
||
120 | case RHD_OUTPUT_UNIPHYC: |
||
121 | Config->u.v3.OutputType = atomOutputUniphyC; |
||
122 | break; |
||
123 | case RHD_OUTPUT_UNIPHYD: |
||
124 | Config->u.v3.OutputType = atomOutputUniphyD; |
||
125 | break; |
||
126 | case RHD_OUTPUT_UNIPHYE: |
||
127 | Config->u.v3.OutputType = atomOutputUniphyE; |
||
128 | break; |
||
129 | case RHD_OUTPUT_UNIPHYF: |
||
130 | Config->u.v3.OutputType = atomOutputUniphyF; |
||
131 | break; |
||
132 | case RHD_OUTPUT_DVO: |
||
133 | Config->u.v3.OutputType = atomOutputDvo; |
||
134 | break; |
||
135 | default: |
||
136 | xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Unhandled ouptut type\n",__func__); |
||
137 | break; |
||
138 | } |
||
139 | Config->u.v3.Force = TRUE; |
||
140 | Config->u.v3.UsePpll = FALSE; |
||
141 | break; |
||
142 | default: |
||
143 | xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Unsupported SelectPixelClock version: %i\n",Private->Version.cref); |
||
144 | break; |
||
145 | } |
||
146 | } |
||
147 | |||
148 | /* |
||
149 | * |
||
150 | */ |
||
151 | static void |
||
152 | rhdAtomPLLSave(struct rhdPLL *PLL, CARD32 PllCntl, CARD32 OwnerVal) |
||
153 | { |
||
154 | RHDPtr rhdPtr = RHDPTRI(PLL); |
||
155 | struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; |
||
156 | CARD32 Crtc1Cntl, Crtc2Cntl; |
||
157 | enum atomCrtc owner; |
||
158 | |||
159 | RHDFUNC(PLL); |
||
160 | |||
161 | Crtc1Cntl = RHDRegRead(PLL, PCLK_CRTC1_CNTL); |
||
162 | Crtc2Cntl = RHDRegRead(PLL, PCLK_CRTC2_CNTL); |
||
163 | |||
164 | if (PllCntl & 0x2) |
||
165 | PLL->StoreActive = FALSE; |
||
166 | else |
||
167 | PLL->StoreActive = TRUE; |
||
168 | |||
169 | if ((Crtc1Cntl & 0x00010000) == OwnerVal) |
||
170 | owner = atomCrtc1; |
||
171 | else if ((Crtc2Cntl & 0x00010000) == OwnerVal) |
||
172 | owner = atomCrtc2; |
||
173 | else { |
||
174 | owner = atomCrtc1; /* whatever... */ |
||
175 | PLL->StoreActive = FALSE; |
||
176 | } |
||
177 | |||
178 | Private->StoreCrtc = owner; |
||
179 | Private->StoreDevice = RHDGetDeviceOnCrtc(rhdPtr, owner); |
||
180 | |||
181 | if (Private->StoreDevice != atomNone) |
||
182 | RHDFindConnectorAndOutputTypesForDevice(rhdPtr, Private->StoreDevice, |
||
183 | &Private->StoreOutputType, &Private->StoreConnectorType); |
||
184 | else |
||
185 | PLL->StoreActive = FALSE; |
||
186 | |||
187 | RHDDebug(PLL->scrnIndex, "Saving PLL %i on CRTC: %i %s active - device: 0x%x\n", |
||
188 | (PLL->Id == PLL_ID_PLL1) ? 1 : 2, |
||
189 | (owner == atomCrtc1) ? 1 : 2, |
||
190 | (PLL->StoreActive) ? "" : "not", |
||
191 | Private->StoreDevice); |
||
192 | |||
193 | PLL->Stored = TRUE; |
||
194 | |||
195 | /* Set parameters found at startup for shutdownInactive(). This is somewhat ugly... */ |
||
196 | Private->Config.Crtc = Private->StoreCrtc; |
||
197 | Private->Config.Enable = PLL->StoreActive; |
||
198 | if (Private->StoreDevice != atomNone) |
||
199 | getSetPixelClockParameters(PLL, &Private->Config, Private->StoreConnectorType, |
||
200 | Private->StoreOutputType, Private->StoreDevice); |
||
201 | } |
||
202 | |||
203 | /* |
||
204 | * |
||
205 | */ |
||
206 | static void |
||
207 | rhdAtomPLL1Save(struct rhdPLL *PLL) |
||
208 | { |
||
209 | struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; |
||
210 | CARD32 PllCntl; |
||
211 | |||
212 | RHDFUNC(PLL); |
||
213 | |||
214 | PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P1PLL_INT_SS_CNTL); |
||
215 | PLL->StoreRefDiv = RHDRegRead(PLL, EXT1_PPLL_REF_DIV) & 0x1FF; |
||
216 | PLL->StoreFBDiv = (RHDRegRead(PLL, EXT1_PPLL_FB_DIV) >> 16) & 0x7FF; |
||
217 | Private->StoreFBDivFrac = RHDRegRead(PLL, EXT1_PPLL_FB_DIV) & 0x7; |
||
218 | PLL->StorePostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV) & 0x3F; |
||
219 | PllCntl = RHDRegRead(PLL, P1PLL_CNTL); |
||
220 | RHDDebug(PLL->scrnIndex, "Saving %i kHz clock on PLL1\n", |
||
221 | ((PLL->StoreFBDiv * PLL->RefClock * 10) |
||
222 | / (PLL->StorePostDiv * PLL->StoreRefDiv))); |
||
223 | |||
224 | rhdAtomPLLSave(PLL, PllCntl, 0x00000000); |
||
225 | } |
||
226 | |||
227 | |||
228 | /* |
||
229 | * |
||
230 | */ |
||
231 | static void |
||
232 | rhdAtomPLL2Save(struct rhdPLL *PLL) |
||
233 | { |
||
234 | struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; |
||
235 | CARD32 PllCntl; |
||
236 | |||
237 | RHDFUNC(PLL); |
||
238 | |||
239 | PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P2PLL_INT_SS_CNTL); |
||
240 | PLL->StoreRefDiv = RHDRegRead(PLL, EXT2_PPLL_REF_DIV) & 0x1FF; |
||
241 | PLL->StoreFBDiv = (RHDRegRead(PLL, EXT2_PPLL_FB_DIV) >> 16) & 0x7FF; |
||
242 | Private->StoreFBDivFrac = RHDRegRead(PLL, EXT2_PPLL_FB_DIV) & 0x7; |
||
243 | PLL->StorePostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV) & 0x3F; |
||
244 | PllCntl = RHDRegRead(PLL, P2PLL_CNTL); |
||
245 | RHDDebug(PLL->scrnIndex, "Saving %i kHz clock on PLL2\n", |
||
246 | ((PLL->StoreFBDiv * PLL->RefClock * 10) |
||
247 | / (PLL->StorePostDiv * PLL->StoreRefDiv))); |
||
248 | |||
249 | rhdAtomPLLSave(PLL, PllCntl, 0x00010000); |
||
250 | } |
||
251 | |||
252 | /* |
||
253 | * |
||
254 | */ |
||
255 | static void |
||
256 | rhdAtomPLLRestore(struct rhdPLL *PLL) |
||
257 | { |
||
258 | RHDPtr rhdPtr = RHDPTRI(PLL); |
||
259 | struct atomPixelClockConfig Config; |
||
260 | struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; |
||
261 | |||
262 | RHDFUNC(PLL); |
||
263 | |||
264 | if (!PLL->Stored) { |
||
265 | xf86DrvMsg(PLL->scrnIndex, X_ERROR, "%s: %s: trying to restore " |
||
266 | "uninitialized values.\n", __func__, PLL->Name); |
||
267 | return; |
||
268 | } |
||
269 | Config.PixelClock = PLL->StoreActive |
||
270 | ? ((PLL->StoreFBDiv * PLL->RefClock * 10) / (PLL->StorePostDiv * PLL->StoreRefDiv)) |
||
271 | : 0; |
||
272 | |||
273 | Config.Enable = PLL->StoreActive; |
||
274 | Config.RefDiv = PLL->StoreRefDiv; |
||
275 | Config.FbDiv = PLL->StoreFBDiv; |
||
276 | Config.PostDiv = PLL->StorePostDiv; |
||
277 | Config.FracFbDiv = Private->StoreFBDivFrac; |
||
278 | Config.Crtc = Private->StoreCrtc; |
||
279 | |||
280 | if (Private->StoreDevice != atomNone) |
||
281 | getSetPixelClockParameters(PLL, &Config, Private->StoreConnectorType, |
||
282 | Private->StoreOutputType, Private->StoreDevice); |
||
283 | RHDDebug(PLL->scrnIndex, "Restoring PixelClock %i with %i kHz, (%i * %i) / ( %i * %i )" |
||
284 | " on CRTC %i device: %x\n", |
||
285 | Private->Pxclk, Config.PixelClock, PLL->RefClock, PLL->StoreFBDiv, PLL->StorePostDiv, |
||
286 | PLL->StoreRefDiv, (Config.Crtc == atomCrtc1) ? 1 : 2, Config.u.v2.Device); |
||
287 | |||
288 | /* Restore spread spectrum: AtomBIOS doesn't handle this for us */ |
||
289 | RHDRegWrite(PLL, (PLL->Id == PLL_ID_PLL1) ? P1PLL_INT_SS_CNTL : P2PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum); |
||
290 | |||
291 | rhdAtomSetPixelClock(rhdPtr->atomBIOS, Private->Pxclk, &Config); |
||
292 | } |
||
293 | |||
294 | /* |
||
295 | * |
||
296 | */ |
||
297 | static void |
||
298 | rhdAtomPLLPower(struct rhdPLL *PLL, int Power) |
||
299 | { |
||
300 | RHDPtr rhdPtr = RHDPTRI(PLL); |
||
301 | struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; |
||
302 | struct atomPixelClockConfig *config = &Private->Config; |
||
303 | |||
304 | RHDFUNC(PLL); |
||
305 | |||
306 | switch (Power) { |
||
307 | case RHD_POWER_ON: |
||
308 | if (config->PixelClock > 0) |
||
309 | config->Enable = TRUE; |
||
310 | else { |
||
311 | xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, |
||
312 | "%s: cannot enable pixel clock without frequency set\n",__func__); |
||
313 | config->Enable = FALSE; |
||
314 | } |
||
315 | break; |
||
316 | case RHD_POWER_RESET: |
||
317 | case RHD_POWER_SHUTDOWN: |
||
318 | return; |
||
319 | config->Enable = FALSE; |
||
320 | default: |
||
321 | break; |
||
322 | } |
||
323 | rhdAtomSetPixelClock(rhdPtr->atomBIOS, Private->Pxclk, config); |
||
324 | } |
||
325 | |||
326 | /* |
||
327 | * |
||
328 | */ |
||
329 | static void |
||
330 | rhdAtomPLLSet(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider, |
||
331 | CARD16 FeedbackDivider, CARD8 PostDivider) |
||
332 | { |
||
333 | RHDPtr rhdPtr = RHDPTRI(PLL); |
||
334 | struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; |
||
335 | struct rhdCrtc *Crtc = NULL; |
||
336 | |||
337 | RHDFUNC(PLL); |
||
338 | RHDDebug(rhdPtr->scrnIndex, "%s: %i kHz RefDiv: %x FeedbackDiv: %x PostDiv: %x\n", |
||
339 | __func__, PixelClock, ReferenceDivider, FeedbackDivider, PostDivider); |
||
340 | |||
341 | Private->Config.PixelClock = PixelClock; |
||
342 | Private->Config.RefDiv = ReferenceDivider; |
||
343 | Private->Config.FbDiv = FeedbackDivider; |
||
344 | Private->Config.PostDiv = PostDivider; |
||
345 | Private->Config.FracFbDiv = 0; |
||
346 | if (rhdPtr->Crtc[0]->PLL == PLL) { |
||
347 | Private->Config.Crtc = atomCrtc1; |
||
348 | Crtc = rhdPtr->Crtc[0]; |
||
349 | } else if (rhdPtr->Crtc[1]->PLL == PLL) { |
||
350 | Private->Config.Crtc = atomCrtc2; |
||
351 | Crtc = rhdPtr->Crtc[1]; |
||
352 | } else |
||
353 | xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Trying to set an unassigned PLL\n"); |
||
354 | |||
355 | if (Crtc && Private->Version.cref > 1) { |
||
356 | struct rhdOutput *Output; |
||
357 | for (Output = rhdPtr->Outputs; Output; Output = Output->Next) { |
||
358 | if (Output->Crtc == Crtc) |
||
359 | break; |
||
360 | } |
||
361 | if (Output) |
||
362 | getSetPixelClockParameters(PLL, &Private->Config, |
||
363 | Output->Connector->Type, Output->Id, |
||
364 | Output->OutputDriverPrivate->Device); |
||
365 | } |
||
366 | |||
367 | /* Disable spread spectrum. AtomBIOS doesn't do this for us */ |
||
368 | RHDRegMask(PLL, (PLL->Id == PLL_ID_PLL1) ? P1PLL_INT_SS_CNTL : P2PLL_INT_SS_CNTL, 0, 0x00000001); |
||
369 | |||
370 | Private->Config.Enable = TRUE; |
||
371 | rhdAtomSetPixelClock(rhdPtr->atomBIOS, Private->Pxclk, &Private->Config); |
||
372 | } |
||
373 | |||
374 | /* |
||
375 | * |
||
376 | */ |
||
377 | Bool |
||
378 | RHDAtomPLLsInit(RHDPtr rhdPtr) |
||
379 | { |
||
380 | struct rhdPLL *PLL; |
||
381 | struct atomPLLPrivate *Private; |
||
382 | CARD32 RefClock, IntMin, IntMax, PixMin, PixMax; |
||
383 | int i; |
||
384 | |||
385 | RHDFUNC(rhdPtr); |
||
386 | |||
387 | RHDSetupLimits(rhdPtr, &RefClock, &IntMin, &IntMax, &PixMin, &PixMax); |
||
388 | |||
389 | for (i = 0; i < 2; i++) { |
||
390 | |||
391 | PLL = (struct rhdPLL *) xnfcalloc(sizeof(struct rhdPLL), 1); |
||
392 | Private = (struct atomPLLPrivate *) xnfcalloc(sizeof(struct atomPLLPrivate),1); |
||
393 | PLL->Private = Private; |
||
394 | |||
395 | Private->Version = rhdAtomSetPixelClockVersion(rhdPtr->atomBIOS); |
||
396 | if (Private->Version.cref > 3) { |
||
397 | xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Unsupported SelectPixelClock version; %i\n", |
||
398 | Private->Version.cref); |
||
399 | xfree(PLL->Private); |
||
400 | xfree(PLL); |
||
401 | return FALSE; |
||
402 | } |
||
403 | |||
404 | PLL->scrnIndex = rhdPtr->scrnIndex; |
||
405 | if (i == 0) { |
||
406 | PLL->Name = PLL_NAME_PLL1; |
||
407 | PLL->Id = PLL_ID_PLL1; |
||
408 | PLL->Save = rhdAtomPLL1Save; |
||
409 | Private->Pxclk = atomPclk1; |
||
410 | } else { |
||
411 | PLL->Name = PLL_NAME_PLL2; |
||
412 | PLL->Id = PLL_ID_PLL2; |
||
413 | PLL->Save = rhdAtomPLL2Save; |
||
414 | Private->Pxclk = atomPclk2; |
||
415 | } |
||
416 | |||
417 | PLL->RefClock = RefClock; |
||
418 | PLL->IntMin = IntMin; |
||
419 | PLL->IntMax = IntMax; |
||
420 | PLL->PixMin = PixMin; |
||
421 | PLL->PixMax = PixMax; |
||
422 | |||
423 | PLL->Valid = NULL; |
||
424 | |||
425 | PLL->Set = rhdAtomPLLSet; |
||
426 | PLL->Power = rhdAtomPLLPower; |
||
427 | PLL->Restore = rhdAtomPLLRestore; |
||
428 | |||
429 | rhdPtr->PLLs[i] = PLL; |
||
430 | } |
||
431 | |||
432 | |||
433 | return TRUE; |
||
434 | } |
||
435 | |||
436 | #endif /* ATOM_BIOS && ATOM_BIOS_PARSER */> |